Unity技术学习:RenderMesh、RenderMeshInstanced

叠甲:本人比较菜,如果哪里不对或者有认知不到的地方,欢迎锐评(不玻璃心)!

导师留了个任务,渲染大量的、移动的物体。

当时找了几个解决方案:

静态批处理:

这东西只对静态物体管用,哪怕勾上,上万个物体就寄了(虽然灵活度很高),只需要勾上就可以了。

Shader上的GPUInstance:

灵活度也挺高的,但是对于超过上限(貌似是1023?)的物体数量,依旧拉胯,batch数虽然不是猛增但是帧率很拉(后续可能会做性能分析)

RenderMeshIndirect(手动GPUInstance?):

跑了一下示例,woc,吊的一批,就是每个块可控性比较差(也可能是我比较菜,目前已知的就是使用,动画贴图,作为参数传入,才能单独控制某个块的动画,而且没有碰撞、无法单独操控等等),但是,一次性绘制10w,600帧没有一点儿压力。1000w个能跑十几帧(视觉效果拉满)。

所以接下来我从 RenderMesh到RenderMeshInstanced再到RenderMeshIndirect的API给说一下,并且跑一下示例:

 RenderMesh:

使用给定的渲染参数渲染网格。

public static void RenderMesh(ref RenderParams rparams, Mesh mesh, int submeshIndex, Matrix4x4 objectToWorld, Nullable<Matrix4x4> 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, NativeArray<T> 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:

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   num=100;
    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 culling
        rp.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 "ExampleShader"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs
            #include "UnityIndirect.cginc"

            struct 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 *3+zOffset, 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!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/593149.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot+Vue项目-基于Java+MySQL的校园二手书交易平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

Netty 网络编程深入学习【一】:ByteBuffer 源码解析

ByteBuffer源码阅读 ByteBuffer是一个用于处理字节数据的缓冲区类。它是Java NIO 包的一部分&#xff0c;提供了一种高效的方式来处理原始字节数据。 ByteBuffer 可以用来读取、写入、修改和操作字节数据&#xff0c;它是一种直接操作字节的方式&#xff0c;比起传统的 InputSt…

如何高速下载,百度 阿里 天翼 等网盘内的内容

如何高速下载&#xff0c;百度 阿里 天翼 等网盘内的内容&#x1f3c5; 前言教程下期更新预报&#x1f3c5; 前言 近段时间经常给大家分享各种视频教程&#xff0c;由于分享的资料是用迅雷网盘存的&#xff0c;但是绝大部分用户都是使用的某度&#xff0c;阿某的这些网盘&…

AI工具大揭秘:如何改变我们的工作和生活

文章目录 &#x1f4d1;前言一、常用AI工具&#xff1a;便利与高效的结合1.1 语音助手1.2 智能推荐系统1.3 自然语言处理工具 二、创新AI应用&#xff1a;不断突破与发展2.1 医疗诊断AI2.2 智能家居2.3 无人驾驶技术 三、AI工具在人们生活中的应用和影响3.1 生活方式的变化3.2 …

旅游系列之:庐山美景

旅游系列之&#xff1a;庐山美景 一、路线二、住宿二、庐山美景 一、路线 庐山北门乘坐大巴上山&#xff0c;住在上山的酒店东线大巴游览三叠泉&#xff0c;不需要乘坐缆车&#xff0c;步行上下三叠泉即可&#xff0c;线路很短 二、住宿 长江宾馆庐山分部 二、庐山美景

Ubuntu 20.04安装桌面XFCE

1.安装Xfce软件包 $ sudo apt update $ sudo apt install xfce42.选择gdm3和lightdm 我这里选择的是lightdm LightDM&#xff0c;即&#xff1a;Light Display Manager&#xff0c;是一个全新的、轻量的Linux桌面的桌面显示管理器&#xff0c;而传统的Ubuntu用的是GNOME桌面…

HR面试测评,招聘行政部门主管的人才测评方案

把合适的人放入到合适的岗位中&#xff0c;可以实现双赢&#xff08;企业效益和个人成就&#xff09;&#xff0c;人力资源管理者HR又该如何去发掘行政主管岗位的人才&#xff1f; 行政部门主管属于管理层岗位&#xff0c;在企业发展中有重要的作用&#xff0c;可以协助企业…

Docker私有镜像仓库搭建 带图形化界面的

搭建镜像仓库可以基于Docker官方提供的DockerRegistry来实现。 官网地址&#xff1a;https://hub.docker.com/_/registry 先配置私服的信任地址: # 打开要修改的文件 vi /etc/docker/daemon.json # 添加内容&#xff1a; "insecure-registries":["http://192.…

FastAPI - Pydantic相关应用

参考链接&#xff1a;Pydantic官方文档 文章目录 定义数据模型创建模型实例数据验证数据转换模型转换模型更新模型配置辅助类Fieldvalidator Pydantic 是一个 Python 库&#xff0c;主要用于数据验证和管理。数据验证是指检查数据是否符合预定的规则和格式&#xff0c;比如检查…

xss注入漏洞解析(下)

DOM型XSS 概念 DOM全称Document Object Model&#xff0c;使用DOM可以使程序和脚本能够动态访问和更新文档的内容、结 构及样式。DOM型XSS其实是一种特殊类型的反射型XSS&#xff0c;它是基于DOM文档对象模型的一种漏洞。 HTML的标签都是节点&#xff0c;而这些节点组成了DOM的…

TeXCount failed. Please refer to LaTeX Utilities Output for details.

写LaTeX的时候总是报这个错、看了下网上也没有什么好的解决方法、就是单词计数器无法使用 我的解决方法: 看下驱动器是否还在&#xff0c;不在的话重新安装一下、不要把驱动器给删除了

开关门机关

根物体创建动画 子物体录制动画 ctrl6&#xff1a;调用动画窗口 添加关键帧&#xff1a;输入添加关键帧到第几帧&#xff0c;然后点击录制&#xff0c;最后在该物体的面板上修改其位置等&#xff0c;记得添加完要结束录制 搞个父物体是为了让动画的可移植性变高 设置触发器方…

基于OpenCv的图像金字塔

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

人工智能大模型应用指南

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

【Flask 系统教程 2】路由的使用

Flask 是一个轻量级的 Python Web 框架&#xff0c;其简洁的设计使得构建 Web 应用变得轻而易举。其中&#xff0c;路由是 Flask 中至关重要的一部分&#xff0c;它定义了 URL 与视图函数之间的映射关系&#xff0c;决定了用户请求的处理方式。在本文中&#xff0c;我们将深入探…

设计模式——行为型模式——策略模式

策略模式 定义 策略模式定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以相互替换&#xff0c;且算法的变化不会影响使用算法的客户。 策略模式属于对象行为模式&#xff0c;它通过对算法进行封装&#xff0c;把使用算法的责任和算法的实现分割开来&a…

【ARM Cortex-M3指南】3:Cortex-M3基础

文章目录 三、Cortex-M3基础3.1 寄存器3.1.1 通用目的寄存器 R0~R73.1.2 通用目的寄存器 R8~R123.1.3 栈指针 R133.1.4 链接寄存器 R143.1.5 程序计数器 R15 3.2 特殊寄存器3.2.1 程序状态寄存器3.2.2 PRIMASK、FAULTMASK和BASEPRI寄存器3.2.3 控制寄存器 3.3 操作模式3.4 异常…

# 在 Windows 命令提示符(cmd)中,可以通过以下方法设置长命令自动换行

在 Windows 命令提示符&#xff08;cmd&#xff09;中&#xff0c;可以通过以下方法设置长命令自动换行 1、点击 cmd 窗口左上角标题栏&#xff0c;选择【属性】。 2、在【属性】菜单中&#xff0c;依次点击【选项】&#xff0c;找到【编辑选项】下面的【自动换行】&#xff…

经纬度聚类:聚类算法比较

需求&#xff1a; 将经纬度数据&#xff0c;根据经纬度进行聚类 初始数据 data.csv K均值聚类 简介 K均值&#xff08;K-means&#xff09;聚类是一种常用的无监督学习算法&#xff0c;用于将数据集中的样本分成K个不同的簇&#xff08;cluster&#xff09;。其基本思想是…