1. 概述

在文章Unity3D学习笔记4——创建Mesh高级接口通过高级API的方式创建了一个Mesh,里面还提到了一个SubMesh的概念。Mesh是对于三维物体对象的封装概念,一个很容易的需求是,有的地方我希望用到材质A,有的地方我希望用到材质B,我不想把这个Mesh进行拆分,那么很简单,就在这个Mesh中划分两个子Mesh就可以了。

2. 详论

2.1. 实现

我们创建如下脚本,并且随便挂接两个不同的材质在属性material1和属性material2上:

using UnityEngine;
using UnityEngine.Rendering; [ExecuteInEditMode]
public class Note5Main : MonoBehaviour
{
public Material material1;
public Material material2; // Start is called before the first frame update
void Start()
{
Mesh mesh = CreateMesh(); MeshFilter mf = gameObject.GetComponent<MeshFilter>();
if (mf == null)
{
mf = gameObject.AddComponent<MeshFilter>();
}
mf.sharedMesh = mesh; MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
if (meshRenderer == null)
{
meshRenderer = gameObject.AddComponent<MeshRenderer>();
} Material[] materials = new Material[2];
materials[0] = material1;
materials[1] = material2;
meshRenderer.materials = materials;
} Mesh CreateMesh()
{
Mesh mesh = new Mesh(); const int vertexCount = 8; Vector3[] vertices = new Vector3[vertexCount]
{
new Vector3(-5, 0, 0),
new Vector3(-5, 5, 0),
new Vector3(5, 0, 0),
new Vector3(5, 5, 0), new Vector3(-5, -5, 0),
new Vector3(-5, 0, 0),
new Vector3(5, -5, 0),
new Vector3(5, 0, 0),
}; Vector3[] normals = new Vector3[vertexCount]
{
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1), new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
new Vector3(0, 0, -1),
}; Vector2[] uv = new Vector2[vertexCount]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1), new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1),
}; mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uv; int[] triangles = new int[12] { 0, 1, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6 }; MeshUpdateFlags flags = MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontResetBoneBounds
| MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds;
//MeshUpdateFlags flags = MeshUpdateFlags.Default; int indexCount = triangles.Length;
mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
mesh.SetIndexBufferData(triangles, 0, 0, indexCount, flags); mesh.subMeshCount = 2;
SubMeshDescriptor subMeshDescriptor1 = new SubMeshDescriptor(0, 6);
mesh.SetSubMesh(0, subMeshDescriptor1, flags); SubMeshDescriptor subMeshDescriptor2 = new SubMeshDescriptor(6, 6);
mesh.SetSubMesh(1, subMeshDescriptor2, flags); return mesh;
} // Update is called once per frame
void Update()
{ }
}

我这里得到的效果如下:

2.2. 解析

很明显,我这里创建了两个四边形,并且将其放到一个Mesh下。创建顶点属性我使用的是简单接口,创建顶点索引属性信息使用的是高级接口。关键点在于对SubMesh的描述:

mesh.subMeshCount = 2;
SubMeshDescriptor subMeshDescriptor1 = new SubMeshDescriptor(0, 6);
mesh.SetSubMesh(0, subMeshDescriptor1, flags); SubMeshDescriptor subMeshDescriptor2 = new SubMeshDescriptor(6, 6);
mesh.SetSubMesh(1, subMeshDescriptor2, flags);

SubMeshDescriptor类定义了从那个顶点索引开始,之后多长的空间是一个SubMesh,也就是对Mesh做了一个划分。另外,GameObject上挂接的材质个数也要对应:

MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
if (meshRenderer == null)
{
meshRenderer = gameObject.AddComponent<MeshRenderer>();
} Material[] materials = new Material[2];
materials[0] = material1;
materials[1] = material2;
meshRenderer.materials = materials;

MeshRenderer上能挂接多个材质,有多少个SubMesh就应该有多少个材质,它们是一一对应的。数量没对应上Unity编辑器会报错。

通过划分SubMesh的方式来描述一个Mesh通常是用于存在多个材质的情况,如果使用的都是同一个材质,就最好不要作SubMesh划分。我们打开Frame Debug,可以看到:

一个Mesh分成了居然两个渲染指令来实现!原因在于图像引擎通常是一个状态机,一个材质需要对应一个渲染指令,这就是为什么我们往往要尽可能复用材质,减少不同材质的个数。

3. 参考

  1. Unity3D学习笔记4——创建Mesh高级接口

Unity3D学习笔记5——创建子Mesh的更多相关文章

  1. Unity3D学习笔记4——创建Mesh高级接口

    目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...

  2. Unity3D学习笔记——游戏组件之Mesh(网格组件)

    Mesh:网格组件.主要用于设置外形和外表. Mesh Filter:网格过滤器.就是为游戏对象添加一个外形. 例:设置外形为Sphere  如果获取的网格拥有蒙皮信患,Unity将自动创建一个skn ...

  3. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  4. Unity3D学习笔记2——绘制一个带纹理的面

    目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...

  5. Unity3D学习笔记6——GPU实例化(1)

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...

  6. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

  7. springmvc学习笔记---idea创建springmvc项目

    前言: 真的是很久没搞java的web服务开发了, 最近一次搞还是读研的时候, 想来感慨万千. 英雄没落, Eclipse的盟主地位隐隐然有被IntelliJ IDEA超越的趋势. Spring从2. ...

  8. unity3d学习笔记(一) 第一人称视角实现和倒计时实现

    unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...

  9. Unity3D学习笔记7——GPU实例化(2)

    目录 1. 概述 2. 详论 2.1. 实现 2.2. 解析 3. 参考 1. 概述 在上一篇文章<Unity3D学习笔记6--GPU实例化(1)>详细介绍了Unity3d中GPU实例化的 ...

  10. Unity3D学习笔记8——GPU实例化(3)

    目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...

随机推荐

  1. visio 2010 kit tools

    Getting Office License Configuration Information.---------------------------------------Backing Up L ...

  2. 《流畅的Python》 读书笔记 第二章数据结构(2) 231011

    2.5 对序列使用+和* 通常 + 号两侧的序列由相同类型的数据所构成,在拼接的过程中,两个被操作的序列都不会被修改,Python 会新建一个包含同样类型数据的序列来作为拼接的结果 +和*都遵循这个规 ...

  3. Telegram 正式引入国产小程序技术

    Telegram 宣布为其开发者提供了一项"能够在 App 中运行迷你应用"的新功能( 迷你应用即 Mini App,下文中以"小程序"代替). 在一篇博客文章 ...

  4. CSP 2023 游记

    省流:把 #define int long long 写在快读下面,找到答案了不 break. Day -1 手速大赛很有趣,但有人不认识 Aigony 我不说是谁. Day 0 睡大觉,给小朋友讲考 ...

  5. P4022 [CTSC2012]熟悉的文章 题解

    题目链接 简要题意 给定 \(m\) 个模板串和 \(n\) 个匹配串,如果一个字符串是一个模板串的子串且长度不小于 \(L\) 则称其为"熟悉的",对于每个匹配串,求一个最大的 ...

  6. python列表之索引及len()函数

    我们在刚开始使用列表的时候,经常会遇到这种错误 list_1 = ['one', 'two', 'three', 'four', 'five'] print(list_1[5]) 这段代码看上去是没有 ...

  7. Go语言函数详解

    函数 (1)函数的定义 函数使用func进行定义 函数是基本的代码块,用于执行一个任务 Go语言至少有一个main函数 函数声明告诉了编译器函数的名称,返回类型和参数 //1.无参数无返回值函数的定义 ...

  8. charles谷歌浏览器抓包方法

    charles谷歌浏览器抓包方法 在工作中,我们会在PC电脑上测试页面,查看后端接口,我们会选择浏览器F12的功能来查看后端请求的接口,那我们能不能用charles抓包工具去抓呢?下面简答介绍一下ch ...

  9. 解决Spring Boot Mail无法发送HTML格式的邮件

    Spring Boot版本:2.6.2 查阅spring-boot-starter-mail源码的MimeMessageHelper.setText方法,发现有个Boolean类型参数控制是否是HTM ...

  10. [ABC310G] Takahashi And Pass-The-Ball Game

    Problem Statement There are $N$ Takahashi. The $i$-th Takahashi has an integer $A_i$ and $B_i$ balls ...