尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
GPU Instancing 实战:一句话画一万个,怎么开怎么用全讲透
开场一个一万棵草让 CPU 崩溃的难题小王要做一片草地一万棵草。他先试了动态批处理——直接卡爆“一万棵草DrawCall 爆炸CPU 直接跪了老鸟说这种’大量相同物体’要用GPU Instancing……可这玩意儿到底怎么开启、怎么用是勾个选项就行还是要写代码有几种用法”老鸟说“GPU Instancing 就是为’大量相同物体’而生的神器一次 DrawCall 画上万个相同网格CPU 几乎不累开启方式有好几种从’勾选项’到’写代码’都有今天把每种用法手把手教你” 第一幕GPU Instancing 是什么核心定义GPU Instancing(GPU实例化) 用一次DrawCall画大量相同网格的物体 ↓ 关键: 网格相同、材质相同,但 每个实例可以有不同的 位置/旋转/缩放(和少量其他属性) ↓ CPU只传每个实例的差异数据 GPU自己复制网格,画出所有实例!为什么它高效普通渲染1000棵树: CPU发1000个DrawCall 每个都传网格数据 → CPU累死 GPU Instancing: CPU发1个DrawCall 一个1000个实例的变换数组 GPU拿着同一个网格,画1000次 ↓ CPU超轻松,GPU高效批量!生动理解GPU Instancing像盖章印刷 普通渲染: 一张张手画1000棵树(累) Instancing: 刻一个树的印章(网格) 给GPU一张1000个盖章位置的清单 GPU咔咔咔盖1000个章! ↓ 一个模子,批量复制,飞快!和其他批处理的定位动态批处理: 小的、不同的动态物体(CPU拼顶点) 静态批处理: 静止物体(预处理合并) GPU Instancing: 大量相同网格⭐ ↓ Instancing专治: 树、草、石头、子弹、 敌人群、粒子...大量重复的东西! 第二幕方式一——材质勾选(最简单)⭐开启步骤✅ 最简单的开启方式 1. 选中材质 2. Inspector里找到 Enable GPU Instancing 3. 勾选它! ↓ 搞定!用这个材质的相同物体 会自动尝试Instancing前提条件✅ 要生效需满足 1. Shader支持Instancing (URP的Lit、Unlit等内置Shader都支持) 2. 物体用相同网格 相同材质 3. 物体是普通的MeshRenderer (场景里摆放的GameObject) ↓ 勾选满足条件 → 自动Instancing适用场景✅ 这种方式适合 场景里手动摆放/Instantiate的 大量相同物体 (如摆了一堆相同的石头、树) ↓ 最省事,勾一下就行!生动理解勾选方式材质勾选像告诉系统:这批可以盖章印 勾上Enable GPU Instancing 跟Unity说这材质的相同物体, 请用盖章方式批量画 ↓ Unity自动识别相同的,批量处理! 第三幕方式二——代码 DrawMeshInstanced适用场景✅ 当物体不是场景GameObject, 而是纯数据驱动渲染时 (如程序生成的大量草、子弹、特效) ↓ 用代码直接调用Instancing绘制! 不需要创建GameObject!基础代码usingUnityEngine;publicclassGrassInstancing:MonoBehaviour{publicMeshgrassMesh;// 草的网格publicMaterialgrassMat;// 开启Instancing的材质Matrix4x4[]matrices;// 每个实例的变换voidStart(){intcount1000;// ⚠️单次上限1023!matricesnewMatrix4x4[count];for(inti0;icount;i){Vector3posnewVector3(Random.Range(-50f,50f),0,Random.Range(-50f,50f));QuaternionrotQuaternion.Euler(0,Random.Range(0,360f),0);Vector3scaleVector3.one;matrices[i]Matrix4x4.TRS(pos,rot,scale);}}voidUpdate(){// ⭐一次画1000棵草!Graphics.DrawMeshInstanced(grassMesh,0,grassMat,matrices);}}关键限制单次1023个⚠️ DrawMeshInstanced单次最多画1023个! ↓ 超过要分批: 10000棵草 → 分成10次调用 每次≤1023个分批处理代码voidDrawManyInstances(Matrix4x4[]allMatrices){inttotalallMatrices.Length;// 假设10000intbatchSize1023;for(inti0;itotal;ibatchSize){intcountMathf.Min(batchSize,total-i);// 取这一批的子数组Matrix4x4[]batchnewMatrix4x4[count];System.Array.Copy(allMatrices,i,batch,0,count);Graphics.DrawMeshInstanced(grassMesh,0,grassMat,batch);}}⚠️ 注意: 上面每帧new数组会GC! 实际应预先分好批,缓存数组复用!生动理解代码方式DrawMeshInstanced像直接下达印刷指令 不用摆GameObject 直接跟GPU说: 拿这个网格(草),照这1000个位置(矩阵), 给我批量印出来! ↓ 纯数据驱动,超高效,适合海量物体! 第四幕方式三——DrawMeshInstancedIndirect(超大量)适用场景✅ 当数量巨大(几万、几十万) 甚至实例数据在GPU上生成时 ↓ 用Indirect版本: 实例参数放在GPU缓冲(ComputeBuffer) 连画多少个都由GPU决定! ↓ 适合: 超大规模草地、粒子、 GPU剔除后的渲染简化示例usingUnityEngine;publicclassMassiveGrass:MonoBehaviour{publicMeshmesh;publicMaterialmat;publicintinstanceCount100000;// 十万!ComputeBufferargsBuffer;// 绘制参数ComputeBufferpositionBuffer;// 实例位置数据uint[]argsnewuint[5]{0,0,0,0,0};voidStart(){// 设置绘制参数args[0]mesh.GetIndexCount(0);// 索引数args[1](uint)instanceCount;// 实例数argsBuffernewComputeBuffer(1,args.Length*sizeof(uint),ComputeBufferType.IndirectArguments);argsBuffer.SetData(args);// 准备实例位置数据(传到GPU)Vector4[]positionsnewVector4[instanceCount];for(inti0;iinstanceCount;i){positions[i]newVector4(Random.Range(-100f,100f),0,Random.Range(-100f,100f),1);}positionBuffernewComputeBuffer(instanceCount,sizeof(float)*4);positionBuffer.SetData(positions);mat.SetBuffer(_Positions,positionBuffer);}voidUpdate(){// ⭐一次调用画十万个!Graphics.DrawMeshInstancedIndirect(mesh,0,mat,newBounds(Vector3.zero,Vector3.one*1000),argsBuffer);}voidOnDestroy(){argsBuffer?.Release();positionBuffer?.Release();}}关键点✅ Indirect版本特点 - 数量几乎无上限 - 实例数据在GPU缓冲 - 参数(画多少)也可GPU动态定 - 配合Compute Shader做GPU剔除 ↓ ⚠️ 复杂度高,ComputeBuffer要记得Release!生动理解 IndirectIndirect像全自动印刷厂 普通DrawMeshInstanced: 你告诉印刷机印1000个(CPU定数量) Indirect: 印刷机自己的系统(GPU)决定印多少! 连数量都在GPU算(如剔除后剩多少) ↓ 超大规模、GPU驱动的终极方案! 第五幕让实例各不相同(每实例属性)需求不同实例不同颜色Instancing默认所有实例材质属性一样 → 但想让每个实例不同颜色怎么办? ↓ 用MaterialPropertyBlock传每实例数据!代码实现usingUnityEngine;publicclassColoredInstances:MonoBehaviour{publicMeshmesh;publicMaterialmat;Matrix4x4[]matrices;MaterialPropertyBlockprops;voidStart(){intcount500;matricesnewMatrix4x4[count];Vector4[]colorsnewVector4[count];for(inti0;icount;i){matrices[i]Matrix4x4.TRS(newVector3(Random.Range(-20f,20f),0,Random.Range(-20f,20f)),Quaternion.identity,Vector3.one);// 每个实例随机颜色colors[i]newColor(Random.value,Random.value,Random.value,1);}// ⭐用PropertyBlock设置每实例颜色数组propsnewMaterialPropertyBlock();props.SetVectorArray(_Colors,colors);}voidUpdate(){Graphics.DrawMeshInstanced(mesh,0,mat,matrices,matrices.Length,props);}}Shader 要支持每实例属性// Shader里声明每实例属性 UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float4, _Color) UNITY_INSTANCING_BUFFER_END(Props) half4 frag(v2f i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); // 关键 // 取当前实例的颜色 float4 col UNITY_ACCESS_INSTANCED_PROP( Props, _Color); return col; }生动理解每实例属性每实例属性像同款盖章不同颜色墨水 网格相同(同一个印章) 但每个盖章用不同颜色墨水(每实例颜色) ↓ 还是批量盖章(Instancing不断) 但每个又能不一样! ↓ 既高效又有变化! 第六幕三种方式对比与选择对比表方式 数量 用法 场景 ────────────────────────────────────────────────────── 材质勾选 中等 最简单 场景摆放的相同物体 DrawMeshInstanced ≤1023/次 写代码 程序生成的大量物体 DrawMeshInstanced- 几乎无限 复杂 超大规模、GPU驱动 Indirect (草海、GPU剔除) ──────────────────────────────────────────────────────选择建议✅ 怎么选 场景里摆的相同物体(石头堆) → 材质勾选,最省事 程序生成、几百到几千个(子弹、敌人) → DrawMeshInstanced 超大规模、几万几十万(草海、森林) → DrawMeshInstancedIndirect 配合GPU剔除 ↓ 按数量和场景选!⚠️ 第七幕使用注意点注意1Shader 必须支持⚠️ 不是所有Shader都支持Instancing! ↓ ✅ 检查 - URP内置Shader(Lit/Unlit)默认支持 - 自定义Shader要加Instancing支持代码 #pragma multi_compile_instancing注意2性能不一定总赢⚠️ Instancing也有开销(准备实例数据) 物体数量少时,可能不如普通渲染 ↓ ✅ 适合大量相同物体 少量(几个)没必要用注意3数组不要每帧 new// ❌ 每帧new,GC暴增!voidUpdate(){Matrix4x4[]mnewMatrix4x4[1000];// 坏!}// ✅ 缓存数组,复用Matrix4x4[]cached;voidStart(){cachednewMatrix4x4[1000];}voidUpdate(){/* 用cached */}注意4ComputeBuffer 要 Release// ⚠️ Indirect用的ComputeBuffer// 必须手动释放,否则内存泄漏!voidOnDestroy(){argsBuffer?.Release();positionBuffer?.Release();}注意5验证是否真的Instancing了✅ 用Frame Debugger确认 看到 Draw Mesh (instanced) → 成功!一次画了多个 ↓ 没生效就查Shader支持、材质设置️ 第八幕实战——完整草地方案需求做一片5000棵草的草地 要求: 高性能、每棵草朝向随机完整代码usingUnityEngine;publicclassGrassField:MonoBehaviour{publicMeshgrassMesh;publicMaterialgrassMat;// 勾了InstancingpublicintgrassCount5000;publicfloatfieldSize50f;// 分批(每批1023)Matrix4x4[][]batches;voidStart(){intbatchSize1023;intbatchCountMathf.CeilToInt((float)grassCount/batchSize);batchesnewMatrix4x4[batchCount][];intcreated0;for(intb0;bbatchCount;b){intsizeMathf.Min(batchSize,grassCount-created);batches[b]newMatrix4x4[size];for(inti0;isize;i){Vector3posnewVector3(Random.Range(-fieldSize,fieldSize),0,Random.Range(-fieldSize,fieldSize));QuaternionrotQuaternion.Euler(0,Random.Range(0,360f),0);batches[b][i]Matrix4x4.TRS(pos,rot,Vector3.one);}createdsize;}}voidUpdate(){// 每帧画所有批次(数组已缓存,无GC)foreach(varbatchinbatches){Graphics.DrawMeshInstanced(grassMesh,0,grassMat,batch);}}}✅ 要点 - 预先分好批,缓存数组(无GC) - 每帧只调用绘制(不重新生成数据) - 材质勾了Instancing、Shader支持 ↓ 5000棵草,极少DrawCall,CPU轻松!✅ GPU Instancing 使用检查清单开启方式 □ 会材质勾选Enable GPU Instancing⭐ □ 会用DrawMeshInstanced代码 □ 知道有DrawMeshInstancedIndirect 前提条件 □ Shader支持Instancing □ 相同网格相同材质 □ 自定义Shader加了multi_compile_instancing 每实例属性 □ 会用MaterialPropertyBlock传每实例数据 □ Shader里用UNITY_ACCESS_INSTANCED_PROP 注意事项 □ 知道DrawMeshInstanced单次≤1023 □ 数组缓存不每帧new(避免GC) □ ComputeBuffer记得Release □ 用Frame Debugger验证真Instancing了 选型 □ 场景摆放→材质勾选 □ 程序生成→DrawMeshInstanced □ 超大规模→Indirect 一句话总结GPU Instancing 怎么用它用一次 DrawCall 画大量相同网格专治树、草、子弹、敌人群这类大量重复物体。三种开启方式① 材质勾选 “Enable GPU Instancing”最简单适合场景摆放的相同物体② 代码Graphics.DrawMeshInstanced适合程序生成单次上限 1023 个超过要分批③DrawMeshInstancedIndirect超大规模几万几十万实例数据放 GPU 缓冲配合 GPU 剔除。想让每个实例不同如颜色用 MaterialPropertyBlock 传每实例数据Shader 里用 UNITY_ACCESS_INSTANCED_PROP 读取。关键注意Shader 必须支持自定义 Shader 加#pragma multi_compile_instancing、数组别每帧 newGC、ComputeBuffer 要 Release、用 Frame Debugger 验证真的 Instancing 了核心口诀Instancing一次画一堆相同物体材质勾选最简单代码DrawMeshInstanced上限1023要分批超大量用Indirect每实例差异用PropertyBlockShader要支持数组缓存别GC GPU Instancing 使用速查表方式数量难度适用材质勾选中⭐最易场景摆放物体DrawMeshInstanced≤1023/次中程序生成物体DrawMeshInstancedIndirect几乎无限高超大规模/GPU驱动PropertyBlock-中每实例差异化 一句话记住核心场景摆放勾材质、程序生成用 DrawMeshInstanced记得分批 1023、超大规模用 Indirect。Shader 必须支持、数组要缓存、Buffer 要释放——写完一定用 Frame Debugger 看到 “instanced” 才算成功 延伸Instancing 的进阶方向【GPU Instancing的进阶玩法】 基础Instancing → 更强的组合 ① GPU剔除(Compute Shader): GPU算哪些实例可见 → 只画可见的 → DrawMeshInstancedIndirect动态数量 ② LOD: 远处实例用低模,近处高模 → 分组Instancing ③ 动画: 顶点动画烘焙到纹理(VAT) → 大量动画角色也能Instancing! ④ 结合SRP Batcher: URP下两者配合优化 ↓ 从静态草地到十万动画大军 Instancing是大规模渲染的核心!
RELATED

相关推荐

从检索到生成:统一外部与参数知识,小白也能掌握的大模型医疗问答秘籍!收藏学习,轻松提升!

从检索到生成:统一外部与参数知识,小白也能掌握的大模型医疗问答秘籍!收藏学习,轻松提升!

本文探讨了医疗问答中模型应如何结合外部检索文档与自身生成背景知识。传统方法如RAG和GAG各有优劣,前者证据可追溯但信息可能不完整,后者解释贴合问题但易生成错误。为解决此问题,本文提出了MedRGAG框架,通过均衡检索、知识引导补…

📅 2026/9/21 19:45:30
Switch手柄连接电脑,5分钟上手BetterJoy:让Pro手柄和Joy-Con在PC上满血复活

Switch手柄连接电脑,5分钟上手BetterJoy:让Pro手柄和Joy-Con在PC上满血复活

Switch手柄连接电脑,5分钟上手BetterJoy:让Pro手柄和Joy-Con在PC上满血复活 【免费下载链接】BetterJoy Allows the Nintendo Switch Pro Controller, Joycons and SNES controller to be used with CEMU, Citra, Dolphin, Yuzu and as generic XInput …

📅 2026/10/7 5:10:02
小白程序员必学:三大经典Agent设计范式,彻底搞懂大模型执行逻辑

小白程序员必学:三大经典Agent设计范式,彻底搞懂大模型执行逻辑

本文深入剖析了ReAct、Plan-and-Execute、Reflection三大经典Agent设计范式,阐述了它们的核心原理、优劣势及适用场景。文章强调这三大范式是构建智能体的基础,并澄清了常见的认知误区,如将Reflection误认为调试工具或将多智能体模式视为独立…

📅 2026/9/21 13:20:25
MORE NEWS

更多资讯

📰

我的电视(my-tv):免注册、开箱即用的电视直播软件,把老电视变成直播入口

我的电视(my-tv):免注册、开箱即用的电视直播软件,把老电视变成直播入口 【免费下载链接】my-tv 我的电视 电视直播软件,安装即可使用 项目地址: https://gitcode.com/GitHub_Trending/my/my-tv 家里只想看央视…

📰

为什么你的断点续传总是从 0 开始:Hutool 大文件下载避坑实战

为什么你的断点续传总是从 0 开始:Hutool 大文件下载避坑实战 【免费下载链接】hutool 🍬A set of tools that keep Java sweet. 项目地址: https://gitcode.com/gh_mirrors/hu/hutool 用 Hutool 做文件下载,几 MB 的包一行 HttpUtil.…

📰

Codex 免配置一键安装包|本地部署不用敲一行命令

前言 做开发的朋友应该都有体会,想要本地部署 Codex,最麻烦的不是软件本身,而是前期环境准备。手动安装 Node.js、处理依赖版本冲突,还要打开终端输入多条命令,稍有不慎就会报错,很多新手卡在这一步直接放…

📰

HarmonyOS 通知点开只进首页?让通知直接跳到指定业务页面【鸿蒙心迹】

👋 你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 Harmo…

📰

my-tv:免费电视直播软件,电视盒子装上就能看

my-tv:免费电视直播软件,电视盒子装上就能看 【免费下载链接】my-tv 我的电视 电视直播软件,安装即可使用 项目地址: https://gitcode.com/GitHub_Trending/my/my-tv my-tv 是一款开源的电视直播软件,免注册、不收费&#…

📰

【HarmonyOS 7新能力|008】互动卡片入门实战:从能力边界到最小可运行链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬