将代码从ShaderToy转换为Unity后,为什么我的着色器看起来是静态的?

时间:2019-02-06 00:31:48

标签: unity3d shader

我正在尝试将一些代码从ShaderToy转换为Unity。这是我尝试转换的着色器:https://www.shadertoy.com/view/Ws23WD

我已经成功编译了代码,但是,当我在Unity中的球体上查看着色器时,它似乎是一个静态的黄色圆圈。我只是将语法从ShaderToy更改为Unity等效项。可能出什么问题了?

enter image description here

Shader "Unlit/Lava"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        iChannel0 ("iChannel0", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            sampler2D iChannel0;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            #define pi (3.14159265358979323846)
            #define EPSILON (0.0001)

            float2 rotate(float2 v, float a)
            {
                float c = cos(a);
                float s = sin(a);
                return float2(
                v.x*c-v.y*s,
                v.x*s+v.y*c
                );
            }

            float sphere(float3 p, float r)
            {
                return length(p)-r;
            }

            float scene(float3 p)
            {
                float b = sphere(p, 1.6);
                if(b > 0.001) return b; // optimisation

                float3 disp = 0;
                float f = 0.5;
                disp.x = tex2D(iChannel0, p.zy * 0.05 + _Time.y * 0.02).x * f;
                disp.z = tex2D(iChannel0, p.xy * 0.05 + _Time.y * 0.03).z * f;
                disp.y = tex2D(iChannel0, p.xz * 0.05 + _Time.y * 0.04).y * f;

                return sphere(p + disp, 1.0 + sin(_Time.y*2.4) * 0.15);
            }

            fixed4 frag (v2f i) : SV_Target
            {                                
                //float2 uv = float2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
                float2 uv = float2(i.uv);

                uv -= 0.5;
                //uv /= float2(iResolution.y / iResolution.x, 1);

                float3 cam = float3(0, -0.15, -3.5);
                float3 dir = normalize(float3(uv,1));

                float cam_a2 = sin(_Time.y) * pi * 0.1;
                cam.yz = rotate(cam.yz, cam_a2);
                dir.yz = rotate(dir.yz, cam_a2);

                float cam_a = _Time.y * pi * 0.1;
                cam.xz = rotate(cam.xz, cam_a);
                dir.xz = rotate(dir.xz, cam_a);

                float4 color = float4(0.16, 0.12, 0.10, 1.0);
                float t = 0.00001;
                const int maxSteps = 128;
                for(int i = 0; i < maxSteps; ++i) {
                float3 p = cam + dir * t;
                float d = scene(p);

                if(d < 0.0001 * t) {
                    color = float4(1.0, length(p) * (0.6 + (sin(_Time.y*3.0)+1.0) * 0.5 * 0.4), 0, 0);
                    break;
                }

                t += d;
            }

            //fragColor.rgb = color;
            return color;
            //fragColor.a = 1.0;
        }
            ENDCG
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您需要按 PLAY 按钮以查看着色器动画。

着色器有效。

Shader works well

答案 1 :(得分:0)

我对您的着色器进行了一些更改。主要用于UV计算和Alpha混合设置。

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/Lava"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        iChannel0 ("iChannel0", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="TransparentCutout" }
        LOD 100
        Blend  OneMinusSrcAlpha SrcAlpha // Specify blend mode. This is inverted from usual usage.
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag lambert alpha:blend // Enable alpha blend
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                float4 screenPos : TEXCOORD1;
            };

            sampler2D _MainTex;
            sampler2D iChannel0;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.screenPos = ComputeScreenPos(o.vertex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            #define pi (3.14159265358979323846)
            #define EPSILON (0.0001)

            float2 rotate(float2 v, float a)
            {
                float c = cos(a);
                float s = sin(a);
                return float2(
                v.x*c-v.y*s,
                v.x*s+v.y*c
                );
            }

            float sphere(float3 p, float r)
            {
                return length(p)-r;
            }

            float scene(float3 p)
            {
                float b = sphere(p, 1.6);
                if(b > 0.001) return b; // optimisation

                float3 disp = 0;
                float f = 0.5;
                disp.x = tex2D(iChannel0, p.zy * 0.05 + _Time.y * 0.02).x * f;
                disp.z = tex2D(iChannel0, p.xy * 0.05 + _Time.y * 0.03).z * f;
                disp.y = tex2D(iChannel0, p.xz * 0.05 + _Time.y * 0.04).y * f;

                return sphere(p + disp, 1.0 + sin(_Time.y*2.4) * 0.15);
            }

            fixed4 frag (v2f i) : SV_Target
            {                                
                //float2 uv = float2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
                float2 uv = float2(i.screenPos.x , i.screenPos.y); // Unity equivalent of the above

                uv -= 0.5;

                uv /= float2((_ScreenParams.y / _ScreenParams.x)*0.5, (_ScreenParams.y / _ScreenParams.x)*0.5); // Shrink the globule

                float3 cam = float3(0, -0.15, -3.5);
                float3 dir = normalize(float3(uv,1));

                float cam_a2 = sin(_Time.y) * pi * 0.1;
                cam.yz = rotate(cam.yz, cam_a2);
                dir.yz = rotate(dir.yz, cam_a2);

                float cam_a = _Time.y * pi * 0.1;
                cam.xz = rotate(cam.xz, cam_a);
                dir.xz = rotate(dir.xz, cam_a);

                float4 color = float4(0.16, 0.12, 0.10, 1.0);
                float t = 0.00001;
                const int maxSteps = 128;
                for(int i = 0; i < maxSteps; ++i) {
                float3 p = cam + dir * t;
                float d = scene(p);

                if(d < 0.0001 * t) {
                    color = float4(1.0, length(p) * (0.6 + (sin(_Time.y*3.0)+1.0) * 0.5 * 0.4), 0, 0);
                    break;
                }

                t += d;
            }

            return color;
        }
            ENDCG
        }
    }
}

结果并不完美,但更接近:

Lava

我认为ShaderToy着色器的问题在于它是用于屏幕空间的。您会看到,移动相机时,熔岩会吓跑。我认为这是由于屏幕空间的uv计算。您将需要找到其他方法。

祝你好运