[UnityShader学习日志]2.第六章实验代码记录

第六章-Unity中的基础光照

提要

  • 本章节进行了最基本的光照实验

实验1-1:漫反射光照模型·逐顶点

  • 首先给出漫反射光照的计算公式(基本光照模型中
    $C_{diffuse} = (C_{light}·m_{diffuse})max(0,\hat{n}·\hat{l})$
    也就是说:我们需要入射光线的强度和颜色,材质的漫反射系数,以及根据兰伯特定律所得的表面法线与光源方向的点积(并且截取在[0,1]内,防止其为负值)
  • 有关颜色的我们往往可以通过.rgb属性来获取

获取入射光线的强度和颜色

  • 在Pass语义块中,我们利用Tag{}来指明光照模式
    Tags{ "LightMode" = "ForwardBase" }
  • 其次,为了获取这样光照的入射光线信息,我们需要引入Unity的内置文件
    #include "Lighting.cginc"
  • 使用内置变量_LightColor0()来访问相关信息
    _LightColor0.rgb

获取材质的漫反射系数

  • 在Properties语义块中,声明一个Color类型的属性,将初始值设为白色
    Properties
    {
        _Diffuse ("Diffuse",Color) = (1,1,1,1)
    }
  • 在pass中声明对应变量后,用同样的方式获取颜色
    _Diffuse.rgb

编写相关相关代码

  • 完成了需要信息的获取后,就可以开始编写代码了。还要注意的一点是,我们需要把法线方向和光线方向都转到世界空间中计算。

Shader "Unlit/diffuseVertex"
{
    Properties
    {
        _Diffuse ("Diffuser",Color) = (1,1,1,1)
    }
    SubShader
    {

        Pass
        {
            Tags{ "LightMode" = "ForwardBase" }
            CGPROGRAM
            #include "Lighting.cginc"
            #pragma vertex vert
            #pragma fragment frag

            fixed4 _Diffuse;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                fixed3 color : COLOR;
            };
			
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光

                fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));//把法线转换到世界空间(顶点变换矩阵的逆转置矩阵)

                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

                o.color = ambient + diffuse;
                return o;


            }

            fixed4 frag(v2f i) : SV_TARGET0{
                return fixed4(i.color,1.0);
            }


            ENDCG
        }
    }
}

实验1-2:漫反射光照模型·逐像素

  • 此时,顶点着色器不再需要计算光照模型,只需要传递给片元着色器即可
Shader "Unlit/diffuseFrag"
{
    Properties
    {
        _Diffuse("DIFFUSE",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "LightMode" = "ForwardBase" }

        Pass
        {
            CGPROGRAM
            #include "Lighting.cginc"
            #pragma vertex vert
            #pragma fragment frag

            fixed4 _Diffuse;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);

                return o;
            }

            fixed4 frag(v2f i) : SV_TARGET0
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));

                float3 color = ambient + diffuse;

                return fixed4(color,1.0);
                
            }        
            ENDCG
        }
    }
}

半兰伯特光照模型

  • 引入:不管是使用逐顶点还是逐像素来实现,我们都会发现模型背面(光照无法到达的区域)都是全黑的,为了改善这个问题,V社的《半条命2》提出了一种技术:半兰伯特光照模型
  • 半兰伯特光照模型对之前的公式进行了一些更改:
    $C_{diffuse} = (C_{light}·m_{diffuse})(α·(\hat{n}·\hat{l})$ +β)
    多数情况下,α和β的值都是0.5,这样就将原先向量点积的结果[-1,1]映射到哦了[0,1]范围内,对于背光面,原来的结果都是映射到0,而在这个模型公式下,背光面也可以有明暗变化
  • 使用半兰伯特光照模型,我们只需要修改一些计算的代码:
fixed halfLambert =  dot(worldNormal,worldLightDir) * 0.5 + 0.5;

fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
  • 背面效果

实验2-1,2-2:高光反射光照模型·逐顶点 与 逐像素

  • 高光反射的计算公式:
    $C_{specular} = (C_{light}·m_{specular})max(0,\hat{v}·\hat{r})^{m_{gloss}}$
  • 高光反射需要的参数较多,比如反射方向和视角方向,Cg提供了计算反射方向的函数reflect,需要法线方向和入射方向
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

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

Shader "Unlit/SpeecularFrag"
{
   Properties
    {
        _Diffuse("DIFFUSE",COLOR) = (1,1,1,1)
        _Specular("SPECULAR",COLOR) = (1,1,1,1)
        _Gloss("GLOSS",Range(8.0,256)) = 20
    }
    SubShader
    {
        Tags { "LightMode" = "ForwardBase"}

        Pass
        {
            CGPROGRAM
            #include "Lighting.cginc"
            #pragma vertex vert
            #pragma fragment frag

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                return o;

            }

            fixed4 frag(v2f i) : SV_TARGET0
            {
                
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal,worldLightDir));

                fixed3 reflectDir = normalize(reflect(-worldLightDir,i.worldNormal));
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);

                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);

                fixed3 color = ambient + diffuse + specular;

                return fixed4(color , 1.0);

            }


            ENDCG
        }
    }
}

posted @ 2023-04-19 17:55  月牙同学  阅读(23)  评论(0)    收藏  举报