内容简介:在Unity中 同网格同材质的模型是可以合批的动态批处理和静态批处理都可以合批 但是都有其限制动态批处理有顶点数不能超过900的限制 只适合比较简单的模型
前言
在Unity中 同网格同材质的模型是可以合批的
动态批处理和静态批处理都可以合批 但是都有其限制
动态批处理有顶点数不能超过900的限制 只适合比较简单的模型
静态批处理的物体不能移动、旋转、缩放
如果动态静态批处理都无法使用 能否用其他方式合批呢?
可以尝试一下GPU Instance 虽然也有所限制 但是提供了更多可能
使用GPU Instancing的条件
1.Shader支持GPU Instancing
2.硬件支持GPI Instancing
3.代码动态绘制物体
硬件需求:
GPU Instancing is available on the following platforms and APIs: ·DirectX 11 and DirectX 12 on Windows ·OpenGL Core 4.1+/ES3.0+ on Windows, macOS, Linux, iOS and Android ·Metal on macOS and iOS ·Vulkan on Windows and Android ·PlayStation 4 and Xbox One ·WebGL (requires WebGL 2.0 API)
限制情况:
下列情况不能使用Instancing: ·使用Lightmap的物体 ·受不同Light Probe / Reflection Probe影响的物体 ·使用包含多个Pass的Shader的物体,只有第一个Pass可以Instancing前向渲染时, 受多个光源影响的物体只有Base Pass可以instancing,Add Passes不行
GPU Instancing确实可以动态合批 但是需要Shader的支持
虽然官方的Standard Shader提供了GPU Instance的选项 但是给材质设置不同颜色后合批失败了 这里有坑 使用了其他Shader后解决
GPU Instance测试
测试代码:
using UnityEngine; using System.Collections.Generic; /// <summary> /// PropertyBlockTest /// ZhangYu 2019-06-17 /// </summary> public class PropertyBlockTest : MonoBehaviour { public GameObject prefab; public int count = 100; private Mesh insMesh; private Material insMaterial; private List<Matrix4x4> insMatrices; private MaterialPropertyBlock insBlock; private List<Color> insColors; private int colorID; private void Start () { GPUInstanceByBlock(); //GPUInstanceByDrawMesh(); } private void Update() { if (insMesh != null) DrawMeshes(); } // 方法1:通过Shader + PropertyBlock 实现GPU Instance private void GPUInstanceByBlock() { MaterialPropertyBlock block = new MaterialPropertyBlock(); int colorID = Shader.PropertyToID("_Color"); GameObject[] objs = new GameObject[count]; for (int i = 0; i < count; i++) { Vector3 position = new Vector3(Random.Range(-8, 8f), Random.Range(-4, 4f), 3); Color color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f)); block.SetColor(colorID, color); GameObject obj = Instantiate(prefab); // 用Block代替Material设置值 这样就能合批了 obj.GetComponent<MeshRenderer>().SetPropertyBlock(block); obj.transform.position = position; obj.SetActive(true); } } // 方法2:通过DrawMesh + Shader + PropertyBlock实现GPU Instance private void GPUInstanceByDrawMesh() { insMesh = prefab.GetComponent<MeshFilter>().mesh; insMaterial = prefab.GetComponent<Renderer>().material; insMatrices = new List<Matrix4x4>(); insColors = new List<Color>(); insBlock = new MaterialPropertyBlock(); colorID = Shader.PropertyToID("_Color"); for (int i = 0; i < count; i++) { Vector3 position = new Vector3(Random.Range(-8, 8f), Random.Range(-4, 4f), 3); Quaternion rotation = prefab.transform.rotation; Color color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f)); // Position + Rotation + Scale > Matrix4x4 Matrix4x4 matrix = TransformToMatrix(position, rotation); insMatrices.Add(matrix); insColors.Add(color); } } private void DrawMeshes() { // 测试结果: // 同网格 同材质 可以合批 需要Shader支持GPU Instance + 用PropertyBlock设置参数 // DrawMeshInstanced() 一次绘制多个物体 调用一次 一个DrawCall //Graphics.DrawMeshInstanced(insMesh, 0, insMaterial, insMatrices, insBlock); // DrawMesh() 一次绘制一个物体 多次调用 可以合成一批 for (int i = 0; i < count; i++) { insBlock.SetColor(colorID, insColors[i]); Graphics.DrawMesh(insMesh, insMatrices[i], insMaterial, 1, Camera.main, 0, insBlock); } } private Matrix4x4 TransformToMatrix(Vector3 position) { return Matrix4x4.TRS(position, Quaternion.identity, Vector3.one); } private Matrix4x4 TransformToMatrix(Vector3 position, Quaternion rotation) { return Matrix4x4.TRS(position, rotation, Vector3.one); } private Matrix4x4 TransformToMatrix(Vector3 position, Quaternion rotation, Vector3 scale) { return Matrix4x4.TRS(position, rotation, scale); } }
测试Shader:
Shader "SimplestInstancedShader" { Properties { _Color("Color", Color) = (1, 1, 1, 1) } SubShader { Tags{ "RenderType" = "Opaque" } LOD 100 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 }; struct v2f { float4 vertex : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID // necessary only if you want to access instanced properties in fragment Shader. }; UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float4, _Color) UNITY_INSTANCING_BUFFER_END(Props) v2f vert(appdata v) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); // necessary only if you want to access instanced properties in the fragment Shader. o.vertex = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag(v2f i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader. return UNITY_ACCESS_INSTANCED_PROP(Props, _Color); } ENDCG } } }
SkinMeshRender的GPU Instancing
Unity官方开源的Animation Instacing: https://blogs.unity3d.com/cn/...
CSDN博主
《Unity中使用GPU Instancing优化SkinnedMesh渲染》 https://blog.csdn.net/xoyojan...
参考资料:
《[unity]GPU Instance学习》: https://www.jianshu.com/p/ecf...
《使用MaterialPropertyBlock来替换Material属性操作》 https://blog.uwa4d.com/archiv...
《Unity3D研究院GPU Instancing实战(九十七)》 https://www.xuanyusong.com/ar...
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入浅出Web设计(中文版)
(美)瓦特罗尔、(美)西罗托 / O'Reilly Taiwan公司 / 东南大学出版社 / 2010-11 / 99.00元
你将从《深入浅出Web设计(中文版)》学到什么?你曾经希望看看书就能学到真正的网站设计吗?曾经想过该如何同时达成让网站看起来美观,又能有效率地沟通信息,还要通过可访问性与可用性的策略吗?《深入浅出Web设计》正是精通上述主题的秘笈。我们将学到如何设计一个绝佳、用户友好的网站,上谈客户需求,下说手绘分镜表,乃至完成在线所需的HTML与css主文件……而且会有一个真正可以运作的网站!一起来看看 《深入浅出Web设计(中文版)》 这本书的介绍吧!