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更惬意一点,休闲为主,不搞太累。