做网站一般使用什么算法,开发安卓软件用什么工具,芍药居网站建设公司,网站建设用几级域名合适叠甲#xff1a;本人比较菜#xff0c;如果哪里不对或者有认知不到的地方#xff0c;欢迎锐评#xff08;不玻璃心#xff09;#xff01;
导师留了个任务#xff0c;渲染大量的、移动的物体。
寻找解决方案#xff1a;
当时找了几个解决方案#xff1a;
静态批处…叠甲本人比较菜如果哪里不对或者有认知不到的地方欢迎锐评不玻璃心
导师留了个任务渲染大量的、移动的物体。
寻找解决方案
当时找了几个解决方案
静态批处理
要求字如其意必须是静态的不能移动旋转缩放等等。
原理Unity 会自动将相同材质球的物体合并到一个大的mesh里提取顶点和索引数据放到共享的顶点缓冲和索引缓冲 并不减少drawcall减少了渲染状态的设置。
缺点;在处理的时候会把相同模型的顶点信息都保存并变换到世界空间。会导致包体和运行时体积变大。
哪怕勾上上万个物体就寄了虽然灵活度很高只需要勾上就可以了。
动态批处理
要求不超过300个顶点不超过总计900个属性不包含镜像的缩放材质一样物体lightmap指向的位置一样
原理运行时将所有共享同一材质的模型顶点信息变换到世界空间一次drawcall 绘制多个模型。
内置渲染管线 URPHDRP没有 真正意义上的减少drawcall。
缺点会有额外的cpu性能消耗而且新一代的图形api在批次间消耗降低反而使用动态批处理可能更差。
对于打断动态批处理的情况:
若优先级低会自动禁用SRPBatch静态批处理GPUinstance动态批处理多passShader自动禁用动态批处理shadow casters可以使用不用材质但shadow casters pass使用的参数是相同的就不会禁用动态批处理。向前渲染路径如果一个物体接受了多个光照会为每个per pixel light 产生提交和绘制从而附加多个Pass导致无法合批。
SRPBatch
原理简化了批处理的渲染循环可以加速相同着色器变体的多种材质在场景中的CPU渲染速度。
要求Shader中的变体一致对象不可以是粒子或蒙皮网格好像最新版已经支持蒙皮了位置不相邻且中间夹杂着不同shader或不同变体的其他物体不会进行同批处理。
这个详细阅读一下官方文档这个本文不做深入研究但注意srpBatch与GPUinstance不兼容参考上方的优先级
Unity - 手册可编写脚本的渲染管线批处理程序
URPHDRP默认开启 缺点
降低setpass call的消耗
GPUInstance
要求同材质、同mesh默认材质仅支持transform的改变。支持meshRenderer和Graphics.RenderMesh不支持SkinMeshRenderer。缩放为负的情况下会失效代码动态改变材质变量就不算同一材质就会失效但是可以通过将颜色变化等变量加入常量缓冲区实现。仅支持一个实时光需要多个光源只能切换到延迟渲染路径。
原理仅绘制一个剩下的“复制”。
只需要勾上材质里的GPUInstancing、当使用该材质时就会合批。但经实测仅支持完全相同的物体方块和球使用相同材质并不会合批。而且不要对顶点少于 256 个的网格使用 GPU 实例化官方文档提醒。 减少了draw call
灵活度也挺高的但是对于超过上限貌似是1023的物体数量依旧拉胯batch数虽然不是猛增但是帧率感人后续可能会做性能分析
RenderMeshIndirect
原理手动GPUInstance多个对象。
跑了一下示例woc吊的一批就是每个块可控性比较差也可能是我比较菜目前已知的就是使用动画贴图、时间来控制每个单体的行为而且没有碰撞、单独操作难度高需要在shader里写改变顶点位置但是一次性绘制10w600帧没有一点儿压力。1000w个能跑十几帧视觉效果拉满。而且支持光照和阴影。 所以接下来我从 RenderMesh到RenderMeshInstanced再到RenderMeshIndirect的API给说一下并且跑一下示例 小总结
抄过来的侵删 RenderMesh
使用给定的渲染参数渲染网格就单纯绘制网格没有任何合批。 public static void RenderMeshref RenderParams rparams Mesh mesh int submeshIndex Matrix4x4 objectToWorld NullableMatrix4x4 prevObjectToWorld null; rparams
camera用于渲染的相机。如果设置为 null默认则为所有摄像机渲染。layer用于渲染的图层。要使用的图层。lightProbeProxyVolume用于渲染的光探针代理体积 LPPV。lightProbeUsage光探头使用的类型。material用于渲染的材质。matProps用于渲染的材质属性。motionVectorMode用于渲染的运动矢量模式。receiveShadows描述渲染的几何体是否应接收阴影。reflectionProbeUsage用于渲染的反射探针的类型。rendererPriority渲染器优先级。renderingLayerMask用于渲染的渲染器图层蒙版。shadowCastingMode描述几何体是否应投射阴影。worldBounds定义几何体的世界空间边界。用于对渲染的几何体进行剔除和排序。
MaterialPropertyBlock-CSDN博客
submeshIndex
当网格体包含多个材质子网格时子网格体 Unity 的索引会呈现。对于具有单个材质的网格请使用值 0这个是啥子冲浪了好久但是找不到
objectToWorld
Unity 用于将网格从对象转换为世界空间的转换矩阵。
prevObjectToWorld
Unity 使用前面的帧变换矩阵来计算网格的运动矢量。
using UnityEngine;public class ExampleClass : MonoBehaviour
{public Material material;public Mesh mesh;void Update(){RenderParams rp new RenderParams(material);rp.camera Camera.main;rp.layer 6;rp.matProps new MaterialPropertyBlock();rp.worldBounds new Bounds(new Vector3(0,0,0),new Vector3(1,1,1));for (int i 0; i 10; i)Graphics.RenderMesh(rp, mesh, 0, Matrix4x4.Translate(new Vector3(-6.5f i, 0.0f, 5.0f)));}
}
RenderMeshInstanced
使用 GPU 实例渲染网格的多个实例但是不会传入命令。 public static void RenderMeshInstanced(RenderParams rparams, Mesh mesh, int submeshIndex, NativeArrayT instanceData, int instanceCount -1, int startInstance 0); instanceData
用于呈现实例的实例数据数组。
instanceCount
要呈现的实例数。当此参数为 -1默认值时Unity 会呈现从数组到末尾的所有实例。
startInstance
要呈现的第一个实例。
using UnityEngine;public class ExampleClass : MonoBehaviour
{public Material material;public Mesh mesh;const int numInstances 1000;struct MyInstanceData{public Matrix4x4 objectToWorld;public float myOtherData;public uint renderingLayerMask;};void Update(){RenderParams rp new RenderParams(material);MyInstanceData[] instData new MyInstanceData[numInstances];for (int i 0; i numInstances; i){instData[i].objectToWorld Matrix4x4.Translate(new Vector3(-4.5f i*3, 0.0f, 5.0f));instData[i].renderingLayerMask (i 1) 0 ? 1u : 2u;}Graphics.RenderMeshInstanced(rp, mesh, 0, instData);}
} RenderMeshIndirect
与RenderMeshInstanced类似但是可以从command buffer中获取命令参数并且只需要调用一次即可执行。 public static void RenderMeshIndirect(ref RenderParams rparams, Mesh mesh, GraphicsBuffer commandBuffer, int commandCount 1, int startCommand 0); commandBuffer 把命令打包的buffer
using UnityEngine;public class ExampleClass : MonoBehaviour
{public Material material;public Mesh mesh;GraphicsBuffer commandBuf;GraphicsBuffer.IndirectDrawIndexedArgs[] commandData;const int commandCount 1;public uint num100;void Start(){commandBuf new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, commandCount, GraphicsBuffer.IndirectDrawIndexedArgs.size);commandData new GraphicsBuffer.IndirectDrawIndexedArgs[commandCount];}void OnDestroy(){commandBuf?.Release();commandBuf null;}void Update(){RenderParams rp new RenderParams(material);rp.worldBounds new Bounds(Vector3.zero, 10000 * Vector3.one); // use tighter bounds for better FOV cullingrp.matProps new MaterialPropertyBlock();rp.matProps.SetMatrix(_ObjectToWorld, Matrix4x4.Translate(new Vector3(0f, 0, 0)));commandData[0].indexCountPerInstance mesh.GetIndexCount(0);commandData[0].instanceCount num;commandBuf.SetData(commandData);Graphics.RenderMeshIndirect(rp, mesh, commandBuf, commandCount);}
}
示例shader
Shader ExampleShader
{SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include UnityCG.cginc#define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs#include UnityIndirect.cgincstruct v2f{float4 pos : SV_POSITION;float4 color : COLOR0;};uniform float4x4 _ObjectToWorld;v2f vert(appdata_base v, uint svInstanceID : SV_InstanceID){InitIndirectDrawArgs(0);v2f o;uint cmdID GetCommandID(0);uint instanceID GetIndirectInstanceID(svInstanceID);float timeOffset _Time.y * 0.5; // 调整运动速度float xOffset sin(timeOffset instanceID *5) * 10; // x方向偏移float yOffset cos(timeOffset instanceID * 7) * 10; // y方向偏移float zOffset sin(timeOffset instanceID * 9) *10; // z方向偏移float4 wpos mul(_ObjectToWorld, v.vertex float4(instanceID%1000 xOffset, cmdID yOffset, instanceID / 1000 *3zOffset, 0));o.pos mul(UNITY_MATRIX_VP, wpos);o.color float4(cmdID 1 ? 0.0f : 1.0f, cmdID 1 ? 1.0f : 0.0f, instanceID / float(GetIndirectInstanceCount()), 0.0f);return o;}float4 frag(v2f i) : SV_Target{return i.color;}ENDCG}}
}
100w个方块能跑150帧cool