如何在Unity中将表面着色器转换为Vertex / Fragment代码?

时间:2018-05-08 01:45:23

标签: unity3d shader fragment-shader vertex-shader

我想知道如何将此表面着色器代码转换为Vertex / Fragment pragma:

Shader "Custom/Diamond Opaque Test" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,1)
        _SpecColor ("Specular Color", Color) = (0.5,0.5,0.5,1)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
        _RimPower ("Rim Power", Range(0,8.0)) = 3.0
        _ReflectColor ("Reflection Color", Color) = (1,1,1,0.5)
        [NoScaleOffset] _Cube ("Cubemap", CUBE) = "" {}
    }

    SubShader {

        CGPROGRAM
        #pragma surface surf BlinnPhong

        struct Input {
            float3 worldRefl;
            float3 viewDir;
        };

        samplerCUBE _Cube;
        fixed4 _Color;
        fixed4 _ReflectColor;
        half _Shininess;
        half _RimPower;

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = _Color.rgb;
            o.Gloss = _Color.a;
            o.Specular = _Shininess;
            half rim = saturate(dot (normalize(IN.viewDir), o.Normal));
            o.Emission = texCUBE (_Cube, IN.worldRefl).rgb * _ReflectColor.rgb * pow(rim,_RimPower);;
        }
        ENDCG
    } 
    FallBack "Mobile/Diffuse"
}

上面的着色器代码是下图左侧的红色宝石:

no shadow

我的目标是看起来与右边的宝石相似。我一路上遇到了一些挑战。左边的宝石是不透明的,可以接受阴影。右边的宝石有正面透明但不是背面。然而,这不接受阴影。我不得不在BlinnPhong上制作宝石,这样它就可以投射和接收阴影。

shadow

是否可以为正面和背面透明度创建不同的控件?还有一种方法可以让透明物体接受阴影吗?我想为宝石添加轮廓,以便可以看到更远的地方。有没有办法在同一通行证中添加轮廓,还是必须有自己独立的通行证?另外,你怎么能让收到的阴影变暗?是否所有这些要求都要归功于GPU?该游戏适用于移动平台。

我是CG编程的初学者。我的第一步是弄清楚转换表面编程到顶点/片段。任何例子都会非常感激。

我确实在资产商店购买了几个宝石资产,但其中一些可以投下阴影,但根本无法接收或无法投射或接收。是什么赋予了?右侧的宝石着色器来自资产商店购买的资产之一。我不想在未经他们许可的情况下在本网站上分享他们的着色器脚本。

1 个答案:

答案 0 :(得分:0)

这实际上是一个相当复杂的过程,尽管我建议您首先从其网站下载unity shader源代码。大多数实际阴影是在UnityStandardBRDF.cginc,UnityPBSLighting.cginc和UnityStandardCore.cginc中完成的。如果您对它们进行搜索,也可以在github上找到这些文件。

基本上,前向着色器的基本结构如下:

Shader "MyForwardAddShader"
{
    Properties
    {
        _MainTex("Some texture", 2D) = "white"{}
    }

    SubShader
    {
        Tags {"RenderType"="Geometry" "Queue" = "Geometry"}

        Pass 
        {
            // Forward Base pass - this applies main directional light and ambient
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM
            #pragma target 3.5

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
            #pragma multi_compile_instancing

            #pragma vertex vert
            #pragma fragment frag

            // I Like to keep these in separate include files
            #include "MyForwardBase.cginc"

            ENDCG
        }

        Pass
        {
            // Forward Add pass - this is added once per extra light source

            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend SrcAlpha One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual

            CGPROGRAM
            #pragma target 3.5

            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog

            #pragma vertex vert
            #pragma fragment frag

            #include "MyForwardAdd.cginc"

            ENDCG
        }
    }
}

请注意,您还需要一个阴影投射器通行证来投射阴影(您可以只复制标准着色器源代码中使用的通行证),如果要使用烘焙的照明,还需要一个元通行证。

类似“ MyForwardBase.cginc”的文件应包括顶点输入和输出结构的定义,以及传递过程的顶点和片段功能。使用此设置,您还需要在此处定义制服(属性变量)。光照计算可能需要一些变量:

// Calculate this in the vertex shader and normalize per fragment
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 viewDir = _WorldSpaceCameraPos.xyz - o.worldPos;

// In the ForwardBase pass, _WorldSPaceLightPos0.xyz stores the direction of the main directional light, instead of position. 
// Use this in the vertex function:
half3 mainLightColor = _LightColor0.rgb;
half3 mainLightDir = _WorldSpaceLightPos0.xyz;

对于Forw​​ardBase传递,您需要包括“ AutoLight.cginc”,并在顶点函数中使用此宏:

COMPUTE_LIGHT_COORDS(o);

这又需要您在VertexOutput结构中包含此宏:

UNITY_LIGHTING_COORDS(6,7) // 6, 7 can be any texture interpolator IDs, they will translate to TEXCOORD6 and TEXCOORD7 in this case

ForwardAdd光衰减的工作原理如下:

UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos.xyz); // Here, worldPos is stored in the vertex output struct and calculated per vertex
half3 lightColor = _LightColor0.rgb * atten;

还有一些宏可以找出像素是否在阴影中,您可以在AutoLight.cginc中找到它们。在ForwardAdd通道中,按每个顶点的方向计算光照方向,如下所示:

o.lightDir      = _WorldSpaceLightPos0.xyz - o.worldPos.xyz * _WorldSpaceLightPos0.w;

我个人而言,我喜欢为每个功能(例如反射,折射,三边形贴图等)创建小的CGIncludes,并在需要时将它们包括在内。我还倾向于在其自己的包含文件中保留一个单独的名为“ Lighting”的函数,因为光照计算在各遍之间共享。此函数将所有变量(如lightDir,viewDir,反照率,粗糙度等)用作参数,并返回片段的阴影颜色。

就像我说的那样,这是一个非常复杂的过程,这只是入门。实施照明功能本身就是一个故事,尽管查看UnityStandardBRDF.cginc可以帮助实现这一点。我建议您从基本的blinn-phong模型开始进行调试,然后从那里进行改进。