当前位置: 首页 > news >正文

C for Graphic:DNF手游残影效果

      dnf手游在作死的道路上越行越远,困难罗特斯完全打不动,提前在抖音上细看攻略,基本能躲过机制不死,但是伤害不够,全时打满也还剩3000+管血,组团半天+炸团半天=完全浪费一天。
     个人觉得策划完全没必要这么逼氪,毕竟才开服四个月,就马不停蹄的想逼玩家氪金,可见游戏后续发展基本玩不下去,最后记录一下用得上的功能就退游。
      dnf手游操作里,按两下后跳,就会朝着操作方向快速闪现,同时出现滞留残影,有时候会发生一个残影一直滞留的bug,满屏幕到处跑会产生满屏幕残影,可见dnf开发人员加班挺凶的,很多bug估计来不及修。
      制作角色残影的核心就是连续记录角色上一段时间的状态,至于具体怎么记录角色状态,依据不同项目的情况而定。
      比如在3d项目中,角色状态就是通过bakemesh出不同时间的instancedmesh,再对instancedmesh进行渲染操作。
      而2d项目中,用spriterender制作一个2d角色,如下:
在这里插入图片描述
      记录2d角色状态,就是记录不同时间spriterender的sprite。
      但是这次我想用后处理完成这个功能。
      核心:按时间间隔采样mesh并使用commandbuffer渲染,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using System.Linq;
using System;public class ESAfterEffect : MonoSingleton<ESAfterEffect>
{public class SpriteParam{public Sprite Spr;public Vector3 WorldPos;public Quaternion WorldQua;public Vector3 WorldScale;public Material Mat;public float Countdown;public float Elapse;}private CommandBuffer cmdBuffer;private const int SPRITE_COUNT = 10;private List<SpriteParam> sprList = new List<SpriteParam>();void Start(){}void Update(){DestroyBuffer();if (sprList.Count > 0){for (int i = 0; i < sprList.Count; i++){SpriteParam spr = sprList[i];if (cmdBuffer == null){cmdBuffer = new CommandBuffer();Camera.main.AddCommandBuffer(CameraEvent.AfterEverything, cmdBuffer);}cmdBuffer.DrawMesh(GetSpriteMesh(spr.Spr), Matrix4x4.TRS(spr.WorldPos, spr.WorldQua, spr.WorldScale), spr.Mat);spr.Elapse -= Time.deltaTime;float alpha = spr.Elapse / spr.Countdown;spr.Mat.SetFloat("_Alpha", alpha);if (spr.Elapse < 0f){sprList.Remove(spr);}}}}private void OnRenderImage(RenderTexture source, RenderTexture destination){if (cmdBuffer != null){Graphics.ExecuteCommandBuffer(cmdBuffer);}Graphics.Blit(source, destination);}public void DrawSprite(Sprite spr, Vector3 wpos, Quaternion wqua, Vector3 wsca, Material mat, float cd = 0.3f){SpriteParam pam = new SpriteParam{Spr = spr,WorldPos = wpos,WorldQua = wqua,WorldScale = wsca,Mat = mat,Countdown = cd,Elapse = cd,};DrawSprite(pam);}public void DrawSprite(SpriteParam spr){if (sprList.Count > SPRITE_COUNT){sprList.RemoveTail();}sprList.Add(spr);}public void DestroyBuffer(){if (cmdBuffer != null){cmdBuffer.Clear();cmdBuffer = null;}}private Mesh GetSpriteMesh(Sprite spr){Mesh mesh = new Mesh();mesh.SetVertices(Array.ConvertAll(spr.vertices, x => (Vector3)x).ToList());mesh.SetUVs(0, spr.uv.ToList());mesh.SetTriangles(spr.triangles, 0);return mesh;}
}

      调用绘制

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;public class ESCharacterGhost : MonoBehaviour
{public SpriteRenderer spriteRd;public RectTransform rectRd;public Material ghostMat;public float sampleInterval = 0.1f;private float sampleElapse = 0f;private Vector2 lastAnchorPos;void Start(){}void Update(){sampleElapse += Time.deltaTime;if (sampleElapse > sampleInterval){if (IsPositionChanged()){lastAnchorPos = rectRd.anchoredPosition;Sprite spr = spriteRd.sprite;Material mat = new Material(ghostMat);mat.SetTexture("_MainTex", spr.texture);mat.SetInt("_Inverse", spriteRd.flipX ? 1 : 0);ESAfterEffect.Instance.DrawSprite(spr, transform.position, transform.rotation, transform.lossyScale, mat);sampleElapse = 0f;}}}private bool IsPositionChanged(){if (MathModule.Instance.CheckVector2Approximate(lastAnchorPos, rectRd.anchoredPosition)){return false;}return true;}
}

      渐变着色

Shader "EchoShadow/EchoShadowAlphaShader"
{Properties{_MainTex ("Texture", 2D) = "white" {}_Inverse("Inverse X",int) = 0_Alpha("Alpha",Range(0, 1)) = 1}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100Pass{Blend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;int _Inverse;float _Alpha;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{if(_Inverse == 1){i.uv.x = (1-i.uv.x);}fixed4 col = tex2D(_MainTex, i.uv);col.a *= _Alpha;return col;}ENDCG}}
}

      最终效果如下:
在这里插入图片描述
      重回dnf端游pk更惬意一点,休闲为主,不搞太累。


http://www.mrgr.cn/news/40696.html

相关文章:

  • 宝塔的软件商店打不开怎么办?
  • 进程控制
  • Prompt 模版解析:诗人角色的创意引导与实践
  • 【科研日常】2024年计算图形学与多媒体CCF A、B类会议投稿截止日期汇总
  • springboot系列--web相关知识探索二
  • C++之String类(上)
  • 图解MySQL 1-22 章节相关总结
  • 大数据毕业设计选题推荐-个性化图书推荐系统-Python数据可视化-Hive-Hadoop-Spark
  • SHA-1 是一种不可逆的、固定长度的哈希函数,在 Git 等场景用于生成唯一的标识符来管理对象和数据完整性
  • CSP-J模拟赛(1)补题报告
  • OpenSCAP部署、使用与原理分析
  • 浏览器预解析机制
  • 螺狮壳里做道场:老破机搭建的私人数据中心---Centos下docker学习02(yum源切换及docker安装配置)
  • 叶绿素透射反射率与波长
  • 【AGC005D】~K Perm Counting(计数抽象成图)
  • 爵士编曲:爵士钢琴编写的规律和步骤 关于教程的个人想法 举一反三
  • Java面试必杀技为什么面试官都爱问源码?
  • MacOS配置python环境
  • 数据工程师岗位常见面试问题-3(附回答)
  • Electron应用创建和打包