Unity ProjectTiny在纯ECS运行时动态创建Mesh

ProjectTiny包是一个纯DOTS环境,可以在Unity里体验下完全用ECS来写代码的感觉。

学习了解了下如何在DOTS环境下动态创建一个Quad网格。在MonoBehavior里创建一个Quad只需要两三行代码,在ECS里创建一个最简单的Quad Mesh,代码都要多好几倍。开发环境用的是Ubuntu20.04,Unity2020.1.17,ProjectTiny0.32。

官方有个列子RuntimeGeometry3D可以根据鼠标路径来创建网格路线,不过里边代码比较多,看起来有点麻烦。通过创建一个最简单的Quad,更方便了解其中的原理。直接上代码:

using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Tiny.Rendering;

namespace Tiny3D {
    public class CreateQuadMeshSystem : SystemBase
    {
        protected override void OnUpdate()
        {
            var quadEntity = EntityManager.CreateEntity();
            // 添加储存顶点数据的Buffer
            EntityManager.AddBuffer<DynamicLitVertex>(quadEntity);
            // 添加储存顶点下标的Buffer
            EntityManager.AddBuffer<DynamicIndex>(quadEntity);
            var vertex = EntityManager.GetBuffer<DynamicLitVertex>(quadEntity); // 不能直接用AddBuffer接口返回的,要再GetBuffer一下,不然运行会报错
            var index = EntityManager.GetBuffer<DynamicIndex>(quadEntity);
            vertex.Capacity = 4;
            vertex.ResizeUninitialized(4);
            index.Capacity = 6;
            index.ResizeUninitialized(6);
            DynamicMeshData dmd = new DynamicMeshData{
                Dirty = true,
                IndexCapacity = index.Capacity,
                VertexCapacity = vertex.Capacity,
                NumIndices = index.Length,
                NumVertices = vertex.Length,
                UseDynamicGPUBuffer = true
            };

            MeshBounds mb;
            MeshHelper.FillPlaneMeshLit(vertex.AsNativeArray().Reinterpret<DynamicLitVertex, LitVertex>(),
                index.AsNativeArray().Reinterpret<DynamicIndex, ushort>(), new float3(-0.5f, -0.5f, 0), new float3(1, 0, 0), new float3(0, 1, 0),
                out mb.Bounds);
            // color-定为红色
            MeshHelper.SetAlbedoColor(vertex.AsNativeArray().Reinterpret<DynamicLitVertex, LitVertex>(), new float4(1, 0, 0, 1));
            // normal-由于创建的是LitMesh,不计算好法线的话,light-color就计算不正确,Quad就渲染成黑漆漆的
            MeshHelper.ComputeNormals(vertex.AsNativeArray().Reinterpret<DynamicLitVertex, LitVertex>(), index.AsNativeArray().Reinterpret<DynamicIndex, ushort>());
            // tangent-计算光照还要用到切线
            MeshHelper.ComputeTangentAndBinormal(vertex.AsNativeArray().Reinterpret<DynamicLitVertex, LitVertex>(), index.AsNativeArray().Reinterpret<DynamicIndex, ushort>());

            // 添加各种渲染LitMesh必须用到的组件
            EntityManager.AddComponentData<DynamicMeshData>(quadEntity, dmd); // 动态网格数据,这种可以在运行时改顶点数据的。还有一种是固定了顶点数据的,无法在运行时改数据!
            EntityManager.AddComponentData<MeshRenderer>(quadEntity, new MeshRenderer{ // 网格渲染组件
                mesh = quadEntity,
                material = CreateLitMaterial(),
                startIndex = 0,
                indexCount = dmd.NumIndices
            });
            EntityManager.AddComponentData(quadEntity, new LitMeshRenderer()); // 这个组件用来表明该Mesh是支持光照的网格。还有一种是Mesh是Unlit的,没有光照
            EntityManager.AddComponentData(quadEntity, mb); // Mesh的包围盒
            EntityManager.AddComponentData<Translation>(quadEntity, new Translation { Value = float3.zero });
            EntityManager.AddComponentData<Rotation>(quadEntity, new Rotation { Value = quaternion.identity });
            EntityManager.AddComponentData<LocalToWorld>(quadEntity, new LocalToWorld { Value = float4x4.Translate(float3.zero) });
            // 添加下面这个组件可以使Quad绕x轴旋转,按空格键可以停止/恢复旋转
            EntityManager.AddComponentData(quadEntity, new DemoSpinner { spin =  math.normalize(new quaternion(new float4(1, 0, 0, 1))) });

            // 销毁该System,避免重复创建。可以用EntityCommadBuffer在OnCreate中创建Entity,但是那样有其他限制
            World.GetExistingSystem<SimulationSystemGroup>().RemoveSystemFromUpdateList(this);
            World.DestroySystem(this);
        }

        Entity CreateLitMaterial() {
            var materialEntity = EntityManager.CreateEntity();
            EntityManager.AddComponentData(materialEntity, new LitMaterial
            {
                texAlbedoOpacity = Entity.Null,
                texMetal = Entity.Null,
                texNormal = Entity.Null,
                texEmissive = Entity.Null,
                constEmissive = new float3(0),
                constOpacity = 1.0f,
                constAlbedo = new float3(1),
                constMetal = 0.0f,
                constSmoothness = .18f,
                normalMapZScale = 1.0f,
                twoSided = false,
                transparent = false,
                scale = new float2(1, 1),
                offset = new float2(0, 0)
            });
            return materialEntity;
        }
    }
}

拷贝上面的代码,丢到官方那个Tiny3D工程目录里,删掉多余的代码和场景里的模型,设置好相机的位置,打包Web并运行就可以看到一个红色方块在旋转了。当然也可以打包Android。运行Web时注意要设置浏览器的跨域支持,不然无法加载本地文件。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值