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

Unity Mesh生成Cube

1. 配置一个Cube的每个面的数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一共是6个面,每个面包含的数据包括4个顶点的相对顶点坐标(Cube的中心为原点),法线方向,UV坐标,顶点渲染顺序,以及这个面用到的材质,因为这里是Top,即顶部,所以法线方向是(0,1,0),其他面以此类推。
顶点的渲染顺序依照左手定则和法线方向判断
在这里插入图片描述
即这里的渲染顺序为[0,2,1,0,3,2],按照左手定则,这两个三角形的法线方向才是朝上的,否则会看不见渲染出的东西,其他面以此类推

再配置一个Cube的数据
在这里插入图片描述
显然包含了每个面

2. 生成

public class MeshBuild : MonoBehaviour
{
    private MeshRenderer meshRenderer;
    private MeshFilter meshFilter;
    public BlockAsset blockAsset;
    
    /// <summary>
    /// 顶点坐标
    /// </summary>
    private List<Vector3> vertices = new List<Vector3>();  
    private List<Vector3> normals = new List<Vector3>();
    private List<Vector2> uvs = new List<Vector2>();
    
    /// <summary>
    /// 顶点的渲染顺序索引,相同材质的为一组
    /// </summary>
    private List<List<int>> subs = new List<List<int>>();
    
    /// <summary>
    /// 用来存储材质的渲染顺序
    /// </summary>
    private Dictionary<Material, int> materials = new Dictionary<Material,int>();
    
    private List<Vector3> offsets = new List<Vector3>()
    {
        new Vector3(0.5f, 0.5f, 0.5f),
        new Vector3(1.5f, 0.5f, 0.5f)
    };
    private void Start()
    {
        meshRenderer = GetComponent<MeshRenderer>();
        meshFilter = GetComponent<MeshFilter>();
        Build();
    }

    public void Build()
    {
        Mesh mesh = new Mesh();
        if (blockAsset != null)
        {
            foreach (var o in offsets)
            {
                var offset = o;
                if (blockAsset.top != null)
                {
                    Append(blockAsset.top, offset);
                }
                if (blockAsset.bottom != null)
                {
                    Append(blockAsset.bottom,offset);
                }
                if (blockAsset.left != null)
                {
                    Append(blockAsset.left,offset);
                }
                if (blockAsset.right != null)
                {
                    Append(blockAsset.right,offset);
                }
                if (blockAsset.forward != null)
                {
                    Append(blockAsset.forward,offset);
                }
                if(blockAsset.backward != null)
                {
                    Append(blockAsset.backward,offset);
                }   
            }
        }

        BuildMesh(mesh);
        BuildMaterial();
    }

    private void Append(BlockFaceAsset face, Vector3 offset)
    {
        List<int> indices;
        if (!materials.TryGetValue(face.material, out var sub_index))   //如果这个材质不曾出现过
        {
            sub_index = subs.Count;     
            indices = new List<int>();
            subs.Add(indices);
            materials.Add(face.material, sub_index);
        }
        else      //如果这个材质已经出现过,则直接拿出这个材质的顶点渲染顺序索引,相同的材质的顶点需要放到一起渲染
        {
            indices = subs[sub_index];
        }

        var base_index = vertices.Count;   //所有的顶点索引必须连一块儿
        foreach (var v in face.vertices)
        {
            vertices.Add(v.position + offset);
            normals.Add(v.normal);
            uvs.Add(v.uv);
        }

        foreach (var i in face.indices)
        {
            indices.Add(base_index + i);    //添加到这一组顶点渲染顺序索引中
        }
    }

    private void BuildMesh(Mesh mesh)
    {
        mesh.Clear();
        mesh.SetVertices(vertices);
        mesh.SetNormals(normals);
        mesh.SetUVs(0, uvs);
        mesh.subMeshCount = subs.Count;
        for (int i = 0; i < subs.Count; i++)
        {
            mesh.SetTriangles(subs[i], i,false);
        }
        meshFilter.mesh = mesh;
    }

    private void BuildMaterial()
    {
        var mats = new Material[this.materials.Count];
        foreach (var kv in materials)
        {
            mats[kv.Value] = kv.Key;
        }
        
        meshRenderer.materials = mats;
    }
}

在这里插入图片描述

最终生成效果
在这里插入图片描述
一共用到三个材质
在这里插入图片描述
顶部为白色,侧边为绿色,底部为红色

3. 代码解释

在这里插入图片描述
首先定义三个列表,用来存储顶点坐标,法线,UV坐标
在这里插入图片描述
此列表存储材质相同的一组顶点渲染顺序索引,比如上面的两个Cube,顶部是一组白色的材质,侧面是一组绿色的材质,底面是一组红色的材质
在这里插入图片描述
此字典用来存储材质的渲染顺序
在这里插入图片描述
两个偏移值,用来遍历生成两个Cube
在这里插入图片描述
对于这段代码,先尝试从材质字典中判断当前的材质是否已经渲染过,如果没有,则初始化sub_index,即此材质和顶点所在的渲染组别,并且同时初始化渲染顺序列表和添加材质字典。
如果已经渲染过此材质了,那么直接拿出之前存储过的顶点渲染顺序组别。
对于base_index的理解,就是看之前已经渲染过多少顶点,然后接着这些顶点的顺序渲染
就比如拿顶部举例
在这里插入图片描述
第一个Cube的顶部,此时vertices列表中是空的,所以base_index是0,然后遍历这个面的顶点的渲染顺序,将其添加到这个组别的列表中,即[0,2,1,0,3,2],也就是说subs[0]目前是这个列表
然后继续迭代,当再一次渲染到第二个Cube的顶部时
在这里插入图片描述
这里因为是使用的相同的材质,所以直接从材质字典中取出了sub_index,为0,再从subs中索引,里面的数据就是第一个Cube填入的顶点渲染顺序,然后发现此时base_index为24,因为渲染第一个Cube总共4*6=24个顶点
然后继续
在这里插入图片描述
当遍历完第二个Cube的顶部时,可以发现按照之前的顺序将现有的顶点顺序填入了当前组别的列表,即0+24,2+24,1+24,以此类推

在这里插入图片描述
然后依次调用Mesh的方法绘制Mesh,其中设置三角形就是按照组别一个个设置

在这里插入图片描述
最后设置材质,将材质从字典中拿出,组成材质数组,给到meshRenderer


http://www.kler.cn/a/463209.html

相关文章:

  • 详细的一条SQL语句的执行流程
  • 【数据仓库金典面试题】—— 包含详细解答
  • 重装操作系统后 Oracle 11g 数据库数据还原
  • android studio android sdk下载地址
  • 【Vim Masterclass 笔记01】Section 1:Course Overview + Section 2:Vim Quickstart
  • 二十三种设计模式-单例模式
  • Unable to locate package pcre-devel
  • 虚拟化服务器在云计算中起着什么作用?
  • 第十讲 比特币的社会与文化影响
  • Spring Boot应用启动慢的原因分析及优化方法
  • 站在风口上的AI电子宠物玩具——开启智能陪伴的新纪元
  • 初学stm32 --- 高级定时器输出比较模式
  • PyQt实战——将pcm文本数据转换成.pcm的二进制文件
  • 关于自回归模型的一份介绍
  • 概率论期末考题类型
  • vue3+TS+vite中Echarts的安装与使用
  • Python视频解码库DeFFcode使用指南
  • 数势科技:解锁数据分析 Agent 的智能密码(14/30)
  • hadoop-common的下载位置分享
  • 【2024年-12月-11日-开源社区openEuler实践记录】深度探秘 libkperf:解锁系统性能剖析的开源宝藏
  • PyTorch快速入门教程【小土堆】之非线性激活
  • LoxodonFramework实现Lua侧绑定UI元素的原理
  • BOSS直聘招聘数据分析的第一步:用Python进行深度清洗
  • 中科汉玉-舆情感知,品牌声誉管理,政企舆情大数据服务平台
  • Django Settings 优化与常用配置指南
  • 安卓入门一 Java基础