如何在着色器之间实时切换?
Posted
技术标签:
【中文标题】如何在着色器之间实时切换?【英文标题】:How can I switch between shaders in real time? 【发布时间】:2018-07-11 14:06:15 【问题描述】:问题是我有两个着色器。如果我在游戏运行时在着色器之间进行更改,它将不会生效。只有当我使用当前着色器开始游戏时,它才会使用该着色器,而不是我切换到的那个。
我看到了这段代码,但它正在切换材质,我想切换着色器。 我的意思是在同一个游戏对象上的着色器之间切换。我不确定这段代码中应该包含哪些材料?
var materials : Material[];
var count = 0;
function OnMouseDown()
if (count == materials.Length - 1)
count = 0;
else
count++;
renderer.material = materials[count];
【问题讨论】:
【参考方案1】:简答
不要这样做。通过游戏对象的渲染器分配更改material
的shader
属性会导致创建材质的多个实例,这不仅计算成本高,而且在GPU 上的内存方面也很昂贵。
Thomas of Unity 教程说得最好:
最有可能跳入您脑海的第一件事是:
GetComponent<Renderer>().material.color = ...
很简单,对吧?只需抓住该颜色并设置动画即可。这样做的问题是,为了改变着色器中的颜色,Unity 需要告诉 GPU 这个对象将以不同的方式渲染,而唯一的方法就是改变材质实例。因此,当您第一次访问 renderer.material 时,Unity 会创建一个材质的副本。
这意味着可能有大量素材副本,所有吃掉记忆1
2500 个球体共享相同材质的场景。其他 39 种材质用于场景中的其他项目。 1
1
在 2500 个对象上摆弄 GameObject.renderer.material.shader
之后。请注意材料是如何从 40 到 2540 个材料跃升的!
1
长答案
首先复习一下。在 Unity 中,您创建(或从 Asset Store 购买)着色器,然后创建材质。然后,材质指的是着色器,它提供着色器可能需要的任何参数,例如纹理;凹凸贴图;和标量,可以将此材质与可能使用相同着色器的任何其他材质区分开来。完成后,您可以将材质应用于对象。
我的意思是在同一个游戏对象上的着色器之间切换
所以想要切换着色器并没有什么意义。对象直接与着色器对话不仅不正确,而且它没有足够的细节供着色器这样做。
您想要做的是切换材质在一个对象上而不是。
如果我在游戏运行时在着色器之间切换,它不会生效
没有看到你的代码,很难说。无论如何,您最好提前定义所有资产,而不是动态创建。通过这种方式,您可以为已知的保真度或平台烘焙它,而无需代码决定应该使用哪个着色器级别。
解决方法
如果您必须在运行时更改材质,您可能需要考虑 Unity 的 MaterialPropertyBlock
。
MaterialPropertyBlock 由 Graphics.DrawMesh 和 Renderer.SetPropertyBlock 使用。在您想用相同的材料绘制多个对象但属性略有不同的情况下使用它。例如,如果您想稍微改变绘制的每个网格的颜色。不支持更改渲染状态More...
不幸的是,您现在需要将 PerRendererData
添加到您的着色器中,Thomas 在下面的文章中对此进行了解释。
这么简单的事情有很多复杂性。提前准备好预先设计好的材料要好得多。这可以说是一种更好的做法。
告诉我更多
优秀文章THE MAGIC OF MATERIAL PROPERTY BLOCKS
"Change the color of a material for only one object",Answers, Unity
【讨论】:
【参考方案2】:您可以使用GameObject.renderer.material.shader
设置着色器。
API 有这件事的例子。查看documentation。
【讨论】:
不幸的是,这会影响使用该材质的场景中的所有内容。 answers.unity.com/questions/411601/… 和 thomasmountainborn.com/2016/05/25/materialpropertyblocks。那个时候或者现在你有同一个着色器的多个实例都在吞噬 gpu 内存以上是关于如何在着色器之间实时切换?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我必须切换纹理单元才能让我的片段着色器识别要使用的纹理?