我需要设置一个着色器的变量,但没有包围它的材质。
我将解释这个问题以及为什么它不像问题“如何从脚本访问着色器变量?”。
问题
我的着色器与此类似(删除了 99% 的不相关样板代码):
Shader "Hidden/XShader"
{
Properties
{
_x ("", float) = 0
}
SubShader
{
Pass
{
float _x;
half4 frag(v2f i) : SV_Target
{
// "col" and "wpos" have been correctly defined
if (wpos.x >= _x)
{
col.r = 1;
} else {
col.r = 0;
}
return col;
}
}
}
}
此着色器通过
Edit->Project Settings->Graphics->Deferred
选项设置。它是主相机使用的默认着色器。
现在我需要通过附加到相机的代码设置
_x
值:
public class XCameraController : MonoBehaviour
{
public float x;
void Update()
{
<something>.SetFloat("_x", x);
}
}
<something>
占位符通常是一种材质,因为 SetFloat()
是在那里定义的。但相机和着色器没有材质。 material 的概念甚至不适用于默认着色器。
我在网上和文档中搜索了几个小时。我承认我失败了,我在这里不知所措。我想这一定很简单,但我找不到任何文档。
我不期望有一个已实施的解决方案,一个我可以找到帮助的指针就足够了!
但是相机和着色器没有材质。的概念 材质甚至不适用于默认着色器。
确实如此,但材质只是公开着色器的所有属性,因此它与此处相关,因为您想要更改着色器属性。
您有一个自定义着色器,但它不用于渲染游戏对象,而是用于渲染相机。 仍然需要材质来更改着色器。如果您不想使用材质,那么您可以使用
Shader.SetGlobalXXX
功能,例如Shader.SetGlobalFloat("_x", 3)
,但它会更改所有着色器属性。这是不现实的。
执行此操作的正确方法是创建一个临时材质,用于修改着色器、更改着色器属性,然后更新相机正在使用的着色器。为此,您必须:
查找着色器或使用公共变量获取着色器的引用:
Shader camShader = Shader.Find("Hidden/XShader");
从着色器创建材质
Material camMat = new Material(camShader);
根据需要修改属性
camMat.SetFloat("_x", 3);
将修改后的着色器属性应用到相机
Camera.main.SetReplacementShader(camShader, "RenderType");
如果您手动渲染相机,请使用
Camera.main.RenderWithShader(camShader, "RenderType")
而不是 Camera.main.SetReplacementShader(camShader, "RenderType")
。
我无法从程序员那里得到上述答案来工作。这里使用 Unity 2022.3 URP 是另一种解决方案:
通过脚本 (CameraEffect.cs) 将自定义材质添加到相机,并将着色器设置为该材质,请参阅下面的代码(此步骤的教程在此处:https://www.youtube.com/watch?v= HW8UePVtU5M).
在着色器中,公开需要设置为属性的变量——该属性随后将出现在自定义材质的检查器中。
在CameraEffect.cs中公开一个公共变量并对材质执行SetFloat/Color/等操作(如下代码)。
在单独的游戏对象控制器脚本中创建一个 CameraEffect 类型的公共变量(即“publiccameraEffect camShaderControl;”),它将出现游戏对象的检查器。然后在编辑器中将主摄像机拖到检查器中的 camShaderControl 框中。然后可以通过 camShaderControl.myValue 在外部脚本中访问 myValue
此解决方案可能因新版本 Unity 中的后处理量而过时,但据我所知,整个问题仍然很模糊。
public class CameraEffect : MonoBehaviour
{
public Material material;
public float myValue = 0.0f;
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material == null)
{
Graphics.Blit(source, destination);
return;
}
Graphics.Blit(source, destination, material);
material.SetFloat("_camPos", myValue);
}
}