首页 > 解决方案 > ShaderLab Unity:使用 Surface Shader 将顶点渲染到 UV 空间

问题描述

我正在按照本教程将着色器烘焙到纹理贴图中效果很好。我只是在标准着色器上应用它时遇到了一些问题。

所以这是他们使用顶点/片段制作的展开着色器(我认为这些负责将顶点渲染到 uv 空间):

v2f vert (appdata v)
        {
            v2f o;
            v.vertex = float4(v.uv.xy, 0.0, 1.0);
            o.vertex = mul(UNITY_MATRIX_P, v.vertex);
            //o.vertex = UnityObjectToClipPos(v.vertex);

            o.uv = v.uv;
            return o;
        }

        fixed4 frag (v2f IN) : SV_Target
        {
          //here is where you would put the shader code you want to bake
          //for now I will just do a noise
          float f = fbm(IN.uv + fbm(5*IN.uv, 4), 4);
          fixed4 color = fixed4(f,f,1,1);
          return color;
        }

我想这样做,但在表面着色器上。你们能帮帮我吗?

标签: unity3dvertex-shader

解决方案


你有两个选择。如果还不算太晚...

选项 1:更改从表面着色器生成的代码

选项2:使用顶点修改器并抵消UnityObjectToClipPos(v.vertex);

Unity 表面着色器也只是 Vertex 和 Fragmentshader,就像上面的代码片段一样。它是不同通道和预定义函数的长集合,用于添加各种效果,如阴影、雾等。如果您将着色器创建为表面着色器,您会告诉统一哪些预定义函数与“surface surf Standard fullforwardshadows”之类的编译指示一起使用。如果单击已编译的着色器有一个按钮,则可以随时查看生成的代码。在那里,您会看到一个带有顶点和片段部分的长着色器。它与#ifelse 有点混乱,并且在您的机器上运行的代码最终只是一小部分。可以手动整理它,只更改您想要更改的特定部分,即添加自定义顶点着色器。

选项 2: 其中之一是顶点修改器编译指示,vertex:vert您可以指定要在顶点着色器中调用的自定义顶点函数来修改顶点位置。(请参阅法线挤出:此处)不幸的是,统一 UnityObjectToClipPos(v.vertex);在您的顶点修改器函数之后直接包装了 a 。因此,如果您进行从对象空间到 uv 空间单位的转换,那么会自动将 uv 坐标转换为剪辑空间,就好像它是对象空间坐标一样,从而导致废话。你可以做的是用它来抵消这个mul(transpose(UNITY_MATRIX_IT_MV), v.vertex); 结果乘法是:P VM*t(t(inv(MV))) = P 这样你就可以欺骗顶点修改器作为覆盖。请记住,位置也用于其他操作阴影等。如果您想拥有更多控制权并跳过这个不必要的双重乘法,您可以这样做

选项 2: 您始终可以从表面着色器进入生成的代码并更改顶点函数。您可以即UnityObjectToClipPos(v.vertex);手动删除调用。

注意:我在使用 UV 空间操作时遇到的一个问题是剪辑空间取决于您使用的图形 api。无论是 OpenGL 还是 Directx,您可能需要将 z 坐标设置为 -1.0 或 0.0 in float4(v.uv.xy, 0.0, 1.0);. 这也可能会根据您的构建目标而改变。

编辑:这是表面着色器的示例顶点修改器:

#pragma surface surf Standard fullforwardshadows vertex:vert        

void vert (inout appdata_full v) {
    v.vertex = float4(v.texcoord.xy, 0.0, 1.0);
    //or float4(v.texcoord.xy, -1.0, 1.0); 
    v.vertex = mul(transpose(UNITY_MATRIX_IT_MV), v.vertex);
}

推荐阅读