UnityECS学习日记二十:ECS+Graphics渲染简单sprite动画

使用的是Entities(0.9.1)版本,渲染sprite动画需要自定义着色器,将动画图集进行分割然后分帧显示在实体位置。

如上图,通过实体控制器创建实体,然后使用Graphics API进行渲染,通过自定义着色器,每帧进行判定切换显示UV范围,实现动画效果。 

自定义Shder:支持GPU实例化

Shader "Custom/InstancedShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            sampler2D _MainTex;
            //float4 _MainTex_UV;

            // #pragma instancing_options assumeuniformscaling
            // 接收实例的颜色和UV数据
            UNITY_INSTANCING_BUFFER_START(Props)
              UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
              UNITY_DEFINE_INSTANCED_PROP(fixed4, _MainTex_UV)
            UNITY_INSTANCING_BUFFER_END(Props)

            v2f vert (appdata v)
            {
                v2f o;

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);

                o.vertex = UnityObjectToClipPos(v.vertex);
                //o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv = (v.uv * UNITY_ACCESS_INSTANCED_PROP(Props, _MainTex_UV).xy) + UNITY_ACCESS_INSTANCED_PROP(Props, _MainTex_UV).zw;

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(i);

                // sample the texture
                fixed4 c = tex2D(_MainTex, i.uv) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);

                return c;
            }
            ENDCG
        }
    }
}

根据自定义shader和动画图集创建个Player命名的材质球。 

脚本:SpriteSheetAnimation_Data 


public struct SpriteSheetAnimation_Data : IComponentData
{
    public int currentFrame;        // 当前帧
    public int frameCount;           // 帧数量
    public float frameTimer;        // 当前帧所花费时间
    public float frameTimerMax; // 超过计时器最大值 增加帧

    public Vector4 uv;                     //当前UV
    public Matrix4x4 matrix4X4;     // 矩阵换算
}

脚本:GameHandle

using UnityEngine;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Rendering;

public class GameHandler : MonoBehaviour
{
    public static GameHandler Instance;
    [SerializeField] public Material unitMaterial;
    [SerializeField] public Mesh quadMesh;

    private static EntityManager entityManager;

    private void Start()
    {
        Instance = this;
        entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;


        for (int i = 0; i < 10000; i++)
        {
            var randomPos = new float3(UnityEngine.Random.Range(0, +100), UnityEngine.Random.Range(0, +100), 0);
            this.SpawnUnitEntity(randomPos);
        }

    }

    private void SpawnUnitEntity(float3 position)
    {
        Entity entity = entityManager.CreateEntity(
            typeof(Translation),
            typeof(SpriteSheetAnimation_Data)
         );
        // entityManager.SetSharedComponentData<RenderMesh>(entity, new RenderMesh { mesh= quadMesh ,material=unitMaterial});
        entityManager.SetComponentData<Translation>(entity, new Translation { Value = position });
        entityManager.SetComponentData<SpriteSheetAnimation_Data>(entity, new SpriteSheetAnimation_Data
        {
            currentFrame = 0,
            frameCount = 4,
            frameTimer = 0f,
            frameTimerMax = 0.1f,
        });
    }
}

脚本:SpriteSheetAnimation_JobSystem

using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Transforms;


public class SpriteSheetAnimation_JobSystem : JobComponentSystem
{
    [BurstCompile]
    public struct AnimationJob : IJobForEach<SpriteSheetAnimation_Data, Translation>
    {
        public float deltaTime;

        public void Execute(ref SpriteSheetAnimation_Data animData,ref Translation translation)
        {
            animData.frameTimer += deltaTime;
            while (animData.frameTimer >= animData.frameTimerMax)
            {
                animData.frameTimer -= animData.frameTimerMax;
                animData.currentFrame = (animData.currentFrame + 1) % animData.frameCount;

                float uvWidth = 1f / animData.frameCount;
                float uvHeight = 1;
                float uvOffsetX = uvWidth * animData.currentFrame;
                float uvOffsetY = 0;
                animData.uv = new Vector4(uvWidth, uvHeight, uvOffsetX, uvOffsetY);

                float3 position = translation.Value;
                position.z = position.y * 0.1f;
                // 处理画面排序顺序
                animData.matrix4X4 = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
            }
        }
    }
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        AnimationJob animationJob = new AnimationJob
        {
            deltaTime = Time.DeltaTime
        };

        var jobHandler = animationJob.Schedule(this, inputDeps);
        return jobHandler;
    }
}

 脚本:SpriteRenderMeshSystem

注意: UpdateAfter(typeof(SpriteSheetAnimation_JobSystem),必须对当前应该显示帧图片计算完再进行渲染

using UnityEngine;
using Unity.Entities;
using Unity.Transforms;

[UpdateAfter(typeof(SpriteSheetAnimation_JobSystem))]
public class SpriteRenderMeshSystem : ComponentSystem
{
    protected override void OnUpdate()
    {
        //通过材质属性块 向 shader 发送数据
        MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
        Vector4[] uv = new Vector4[1];
        Entities.ForEach((ref Translation translation,ref SpriteSheetAnimation_Data animData) =>
        {
            uv[0] = animData.uv;
            // uv从左下角进行绘制
            materialPropertyBlock.SetVectorArray("_MainTex_UV", uv);


            Graphics.DrawMesh(
                GameHandler.Instance.quadMesh,
                animData.matrix4X4,
                GameHandler.Instance.unitMaterial,
                0,
                Camera.main,
                0,
                materialPropertyBlock
            );

        });
    }
}

 如下图,创建了1万个实体进行渲染动画。

 

 

 

 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值