【问题标题】:Send vertice shader changes to surface shader将顶点着色器更改发送到表面着色器
【发布时间】:2018-06-06 08:16:05
【问题描述】:

我正在尝试做一个着色器来像Subway Surfer 那样弯曲世界。

我找到了一个GitHub repo,有人在其中推了一个很酷的近似值。

这是代码:

 Shader "Custom/Curved" {
 Properties {
     _MainTex ("Base (RGB)", 2D) = "white" {}
     _QOffset ("Offset", Vector) = (0,0,0,0)
     _Dist ("Distance", Float) = 100.0
 }
 SubShader {
     Tags { "RenderType"="Opaque" }
     Pass
     {
         CGPROGRAM
         #pragma vertex vert
         #pragma fragment frag
         #include "UnityCG.cginc"

                     sampler2D _MainTex;
         float4 _QOffset;
         float _Dist;

         struct v2f {
             float4 pos : SV_POSITION;
             float4 uv : TEXCOORD0;
         };

         v2f vert (appdata_base v)
         {
             v2f o;
             float4 vPos = mul (UNITY_MATRIX_MV, v.vertex);
             float zOff = vPos.z/_Dist;
             vPos += _QOffset*zOff*zOff;
             o.pos = mul (UNITY_MATRIX_P, vPos);
             o.uv = v.texcoord;
             return o;
         }

         half4 frag (v2f i) : COLOR
         {
             half4 col = tex2D(_MainTex, i.uv.xy);
             return col;
         }
         ENDCG
     }
 }
 FallBack "Diffuse"
}

关键是现在我想将新的顶点位置发送到表面着色器,以便能够为其他顶点提供照明。

我读到我必须删除片段着色器,但我仍然遇到无法将新信息发送到表面着色器的问题。

这是我的代码:

Shader "Custom/Curve" {
 Properties{
     _Color("Color", Color) = (1,1,1,1)
     _MainTex("Albedo (RGB)", 2D) = "white" {}
     _Glossiness("Smoothness", Range(0,1)) = 0.5
     _Metallic("Metallic", Range(0,1)) = 0.0


     _QOffset("Offset", Vector) = (0,0,0,0)
     _Dist("Distance", Float) = 100.0
 }
     SubShader{
     Tags{ "RenderType" = "Opaque" }
     LOD 200

     CGPROGRAM

 #pragma surface surf Standard fullforwardshadows vertex:vert addshadow

 #pragma target 3.0

 sampler2D _MainTex;

 struct Input {
     float2 uv_MainTex;
 };

 half _Glossiness;
 half _Metallic;
 fixed4 _Color;

 float4 _QOffset;
 float _Dist;

 void vert(inout appdata_full v)
 {
     v.position.x += 10;
 }

 void surf(Input IN, inout SurfaceOutputStandard o) {
     // Albedo comes from a texture tinted by color
     fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
     o.Albedo = c.rgb;
     // Metallic and smoothness come from slider variables
     o.Metallic = _Metallic;
     o.Smoothness = _Glossiness;
     o.Alpha = c.a;
 }
 ENDCG
 }
     FallBack "Diffuse"
 }

正如您现在在顶点着色器中看到的那样,我只是想在顶点的 X 位置添加一些单位,因为我认为如果我实现了这一点,那么“曲线变化”将是微不足道的,但如果你认为它如果您警告我,我将不胜感激。

【问题讨论】:

    标签: unity3d shader


    【解决方案1】:

    编辑:

    这是一个统一 2018.1 的示例 https://gist.github.com/bricevdm/caaace3cce9a87e081602ffd08dee1ad

    float4 worldPosition = mul(unity_ObjectToWorld, v.vertex); 
    // get world space position of vertex
    half2 wpToCam = _WorldSpaceCameraPos.xz - worldPosition.xz; 
    // get vector to camera and dismiss vertical component
    half distance = dot(wpToCam, wpToCam); 
    // distance squared from vertex to the camera, this power gives the curvature
    worldPosition.y -= distance * _Curvature; 
    // offset vertical position by factor and square of distance.
    // the default 0.01 would lower the position by 1cm at 1m distance, 1m at 10m and 100m at 100m
    v.vertex = mul(unity_WorldToObject, worldPosition); 
    // reproject position into object space
    

    您正在混淆常规 CG 着色器和表面着色器。您来自 github 的样本是前者。表面着色器中的v.vertex 预计位于对象空间,而 CG 着色器中的float4 pos : SV_POSITION 预计将位于其最终 - 剪辑/屏幕空间 - 位置。

    解决方案是将变换反转回对象空间。在您的情况下,您需要从相机中公开逆投影矩阵。

    替换v.vertex = mul (UNITY_MATRIX_P, vPos); 使用此矩阵:https://docs.unity3d.com/ScriptReference/Camera-cameraToWorldMatrix.html。由于您使用 UNITY_MATRIX_MV 将顶点从对象空间转换到相机空间,因此您需要先反转到世界,然后使用 unity_WorldToObject 反转到对象空间(或者更好地在 cpu 上将两者结合起来)。

    但是使用已经提供的矩阵计算世界空间中的曲率实际上要容易得多:

    https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

    unity_ObjectToWorld 当前模型矩阵。

    unity_WorldToObject 当前世界矩阵的逆矩阵。

    【讨论】:

    • 抱歉,当您评论 v.vertex = mul (UNITY_MATRIX_P, vPos); 部分时,您是在谈论在其他评论中给我的方法吗?我想我明白了,但我不确定实施。我应该对顶点着色器中的“对象空间”进行更改,我的曲率是否会更改并将它们移回屏幕空间?
    • 我在这里做了一个评论版本:gist.github.com/bricevdm/caaace3cce9a87e081602ffd08dee1ad
    【解决方案2】:

    这是因为appdata_full struct 中没有值作为位置:

    struct appdata_full {
        float4 vertex : POSITION;
        float4 tangent : TANGENT;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
        float4 texcoord1 : TEXCOORD1;
        fixed4 color : COLOR;
    #if defined(SHADER_API_XBOX360)
        half4 texcoord2 : TEXCOORD2;
        half4 texcoord3 : TEXCOORD3;
        half4 texcoord4 : TEXCOORD4;
        half4 texcoord5 : TEXCOORD5;
    #endif
    };
    

    像这样使用v.vertex 而不是v.position

    void vert (inout appdata_full v, out Input o){
                UNITY_INITIALIZE_OUTPUT(Input,o);
                v.vertex += 10;
    }
    

    这是你的曲线着色器的表面版本:

    Shader "Custom/Curve" {
     Properties{
         _Color("Color", Color) = (1,1,1,1)
         _MainTex("Albedo (RGB)", 2D) = "white" {}
         _Glossiness("Smoothness", Range(0,1)) = 0.5
         _Metallic("Metallic", Range(0,1)) = 0.0
    
    
         _QOffset("Offset", Vector) = (0,0,0,0)
         _Dist("Distance", Float) = 100.0
     }
         SubShader{
         Tags{ "RenderType" = "Opaque" }
         LOD 200
    
         CGPROGRAM
    
     #pragma surface surf Standard fullforwardshadows vertex:vert addshadow
    
     #pragma target 3.0
    
     sampler2D _MainTex;
    
     struct Input {
         float2 uv_MainTex;
     };
    
     half _Glossiness;
     half _Metallic;
     fixed4 _Color;
    
     float4 _QOffset;
     float _Dist;
    
    void vert (inout appdata_full v, out Input o){
                UNITY_INITIALIZE_OUTPUT(Input,o);
                float4 vPos = mul (UNITY_MATRIX_MV, v.vertex);
                float zOff = vPos.z/_Dist;
                vPos += _QOffset*zOff*zOff;
                v.vertex = mul (UNITY_MATRIX_P, vPos);
                v.texcoord = v.texcoord;
    }
    
     void surf(Input IN, inout SurfaceOutputStandard o) {
         // Albedo comes from a texture tinted by color
         fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
         o.Albedo = c.rgb;
         // Metallic and smoothness come from slider variables
         o.Metallic = _Metallic;
         o.Smoothness = _Glossiness;
         o.Alpha = c.a;
     }
     ENDCG
     }
         FallBack "Diffuse"
     }
    

    【讨论】:

    • 嗨,很抱歉回复晚了:我已经按照您的建议做了,但结果不是预期的:imgur.com/RixvcCI 我不知道到底发生了什么,因为当我只编码时顶点着色器“Position.x +=10”位移不正确:imgur.com/gGuthTN
    • @CarlosHdezBarbera 你能发送结果问题吗?
    • @CarlosHdezBarbera 我提到使用 v.vertex.x += 10; 。你能用两张图片描述发生了什么吗?你到底期待什么?
    • 当然,我已经上传了两个视频示例来展示正在发生的事情。我可以理解曲线着色器可能是错误的(我不知道如何,因为在 git repo 中它按预期工作)但 x 位移没有按我预期的那样工作,我无法理解。示例 1:youtu.be/kFpyySpfVik 示例 2:youtu.be/nhLdvQEQKIw
    • @CarlosHdezBarbera 我有经验,有时顶点着色器无法正常工作,您需要添加Tags{ "DisableBatching" = "true"},如this question
    猜你喜欢
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    相关资源
    最近更新 更多