广东省 网站建站,wordpress的php用什么版本好,WordPress文章浏览,网站页面统计代码是什么一个模型中可以包含很多网格#xff0c;一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格#xff08;Sub-Mesh)组成。
在渲染引擎的时候#xff0c;每个子网格都要匹配一个材质球来做渲染#xff0c;实际上一个子网格本身就是一个个普通的模型#xff0…一个模型中可以包含很多网格一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格Sub-Mesh)组成。
在渲染引擎的时候每个子网格都要匹配一个材质球来做渲染实际上一个子网格本身就是一个个普通的模型它由很多个三角形构成也需要材质球支持达成渲染。
为什么要有子网格
美术人员在制作3D模型时为什么不打网格编成一个而要制作成多个子网格
模型中的一部分网格用一种材质球来表现效果另一部分用另一种。因为一个网格只能对应一个材质球所以要拆开。模型中的莫部分贴图在众多模型中共同时使用的频率比较高为了不重复制作以减少重复劳动原本可以作为一个整体的模型会将公共材质部分单独拆分出来让一部分模型使用同一个材质球。制作动画时由于动画过于复杂如果使用同一个模型去表现则骨骼的数量就会成倍的增加为了更好的表现动画也为了能降低骨骼的使用数量要拆分出来一部分模型让它们单独成为模型动画的一部分。
从以上看多个子网格比单个网格要灵活的多但它也有缺点由于每个子网格都有材质球导致子网格越多drawcall 也越多。
子网格功能虽然强大但也需要注意性能开销。
动态合并3D模型
我们知道每个网格模型都需要有一个材质球支持导致每个模型都会产生一个drawcall,过多的drawcallCPU会忙于发送状态数据给GPU,GPU大多数时间处于等待状态这将导致画面帧率下降及强烈的画面卡顿。
实际项目中通常会遇到这样的问题场景中会有很多物体人物、建筑、路标、景观、树木、石头、碎块、花草等等有的物体可能不只有一个材质球相同物体共用一个当然不同的物体也可能使用相同的材质球这些物体如果不做任何优化处理就会产生很多drawcall。
合并3D模型的主要目的就是减少drawcall,通过减少材质球的提交次数来完成优化简单的说就是大拥有相同材质球的模型合并成一个模型和一个材质球从而减少向GPU提交的drawcall数量让GPU并行处理数据时更快更顺畅。
在Unity中分为动态合批和静态合批两种使用它们的前提条件是模型物体必须具有相同的材质球除了这个必要条件外还有其他条件。
动态批处理
开启动态批处理时Unity会将场景中的某些物体自动批处理成为同一个drawcall需要满足
顶点数目要少于900个顶点网格。如果你的着色器使用顶点坐标、法线和单独的UV,那么顶点个数就要在300以内如果着色器使用顶点坐标、法线、UV0、UV1和切线则顶点要在180个内的网格。两个物体的缩放单位要相同比如A(1,1,1) B(1,1,2)就没法合批了使用相同材质球多管线Pipeline着色器会中断动态合批支持多个灯光的前置渲染它们增加了多个渲染通道因此无法批处理。旧系统中的延迟渲染路径(灯光前置通道)关闭了动态批处理因为它需要绘制物体两次。多有多个Pass的着色器增加了渲染管道不会被动态批处理。
从上面看动态批处理的条件非常苛刻真实的项目里很多模型时不符合动态批处理要求的。另外动态批处理要消耗CPU将所有物体的顶点转换到世界空间合并网格也会带来开销。一味的减小drawcall并不是万能的开销取决于很多因素drawcall的开销主要是由图形API的调用造成的如果节省的开销小于准备工作的开销就得不偿失。例如一个主机设备或流行的API(Apple Metal这样的)drawcall的开销通常很低那么对于它来说动态批处理就没有什么优势了。
静态批处理
静态批处理允许引擎离线的情况下进行模型合并的批处理减少drawcall。无论模型有多大只要使用同一个材质球都会被静态批处理优化。它通常比动态批处理更有用因为不需要实时转换顶点来消耗CPU缺点是消耗了更多的内存。
Unity中需要对物体设置静态标记也就是不能移动缩放旋转的物体。
如果一些物体之前共用一个模型那么unity会复制这些物体的模型用来合并所以使内存增大。个人觉得使用内存换CPU是值得的然而如果用100GB的内存换千分之一的CPU效率那就不值得了。
静态批处理的具体流程是将所有静态标记的物体放入世界空间-通过材质球分类标准将它们分别合并-构建成一个大的顶点集合和索引缓存。从而减少drawcall。
从技术上来说静态批处理并没有节省3D API drawcall的数量但它能减少因3D API之间的状态改变导致的消耗。大多数平台上批处理限制在64000个顶点和64000个索引内OpenGLES上为48000个MacOS上为32000个所以如果批处理过多需要取消一些静态标记。
自己编写合并3D模型程序
Unity3D中
Mesh类有一个CombineMeshes的接口提供了合并入口。MeshFilter类是承载数据类。MeshRenderer类是绘制网格的类
在使用之前我们还需要了解
MeshFilter和MeshRenderer中的mesh与shareMesh、material及shareMaterial的区别
mesh和material都是实例型的变量对mesh和material执行任何操作都是额外复制一份后重新赋值即使只是get操作同样也会执行复制操作。而就是说对mesh和material进行操作后就会变成另一个实例。sharedMesh和shareMaterial与前面的两个变量不同它们是共享型的。多个模型可以共同指定一个sharedMesh和sharedMaterial当年修改了shareMesh或sharedMaterial里面的参数指向同一个sharedMaterial和sharedMesh的多个模型就会同时改变效果。
materials和sharedMaterialsd的区别
materials是实例型sharedMaterials是共享型两个都是数组。material和sharedMaterial只针对主网格。而就是说material等于materials[0],sharedMaterial等于sharedMaterial[0]。
网格、MeshFilter、MeshRenderer的关系
网格时数据资源它可以有自己的资源文件通常时.FBX文件。网格里存储了顶点、UV、顶点颜色、三角形、切线、法线、骨骼、骨骼权重等提供渲染所必要的数据。
MeshFilter是一个承载网格数据的类网格被实例化后存储在MeshFilter类中。MeshFilter包含两种类型即实例型mesh和共享型变量(sharedMesh)。
MeshRenderer具有渲染功能它会提取MeshFilter中的网格数据结合自身的materials或sharedMaterials进行渲染。
Mesh.CombineInstance合并数据实例类
合并时需要为每个将要合并的网格创建一个CombineInstance实例并往里放入mesh、subMesh的索引lightmap的缩放和偏移realtimeLightmap的缩放和偏移以及世界坐标矩阵。它承载了所有需要需要合并的数据。
现在我们掌握了关于合并网格的理论知识我们来实现以下这里我从Unity 商店下载了一个模型我将角色手中的 剑和盾牌进行了合并并生成了一个新的GameObject 效果如下 using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public class CombineTest : MonoBehaviour
{public ListMeshFilter combineMeshFilers new ListMeshFilter();// Start is called before the first frame updatevoid Start(){CreateCombineModel();}private void CreateCombineModel(){// 提取网格所需的资源ListMaterial materials new ListMaterial();CombineInstance[] combines new CombineInstance[combineMeshFilers.Count];for (int i 0; i combineMeshFilers.Count; i){CombineInstance tmpInstance new CombineInstance();MeshFilter tmpFilter combineMeshFilers[i];tmpInstance.mesh tmpFilter.sharedMesh;tmpInstance.transform tmpFilter.transform.localToWorldMatrix;combines[i] tmpInstance;MeshRenderer renderer tmpFilter.transform.GetComponentMeshRenderer();for (int j 0; j renderer.sharedMaterials.Length; j){if (!materials.Contains(renderer.sharedMaterials[j]))materials.Add(renderer.sharedMaterials[j]);}}// 将所有网格合并成一个新的网格Mesh mesh new Mesh();MeshFilter combineFilter transform.AddComponentMeshFilter();MeshRenderer combineRenderer transform.AddComponentMeshRenderer();mesh.CombineMeshes(combines);combineFilter.mesh mesh;combineRenderer.materials materials.ToArray();}
}