Unity学习之Shader(Phong与Blinn-Phong)

三、Lesson3

1、关键名称

csharp 复制代码
向量
• nDir:法线方向,点乘操作时简称n; 
• lDir:光照方向,点乘操作时简称l;
• vDir:观察方向,点乘操作时简称v;
• rDir:光反射方向,点乘操作时简称r;
• hDir:半角方向(Halfway),lDir和vDir的中间角方向,点乘操作时简称h
空间
• OS:ObjectSpace 物体空间,本地空间;
• WS:WorldSpace世界空间;
• VS:ViewSpace 观察空间;
• CS:HomogenousClipSpace 齐次剪裁空间;
• TS:TangentSpace 切线空间;
• TXS:TextureSpace 纹理空间;

2、漫反射与镜面反射

(1)漫反射

特点:向四面八方均匀反射,反射亮度与观察者看的方向无关

主要模型:兰伯特、半兰伯特

涉及向量:nDir、lDir

(2)镜面反射

特点:反射具有明显方向性,观察者的视角决定了反射光线的有无、明暗

主要模型:Phong、Blinn-Phong

涉及向量:nDir、lDir、vDir、rDir、hDir

3、Phong

(1)效果展示

(2)计算方式

Phong=rDir(光反射方向) dot vDir(观察方向)

rDir=Reflect(-lDir,nDir)

(3)实现代码

csharp 复制代码
Shader "AP01/Phong" {
    Properties {
        _MainCol ("颜色", color) = (1.0, 1.0, 1.0, 1.0)
        _SpecularPow ("高光次幂", range(1, 90)) = 30
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }


            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入参数
            // 修饰字(满足小朋友太多的问好, 想保发量的大家看热闹)
                // uniform  共享于vert,frag
                // attibute 仅用于vert
                // varying  用于vert,frag传数据
            uniform float3 _MainCol;     // RGB够了 float3
            uniform float _SpecularPow;  // 标量 float
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;   // 顶点信息 Get✔
                float4 normal : NORMAL;     // 法线信息 Get✔
            };
            // 输出结构
            struct VertexOutput {
                float4 posCS : SV_POSITION;     // 裁剪空间(暂理解为屏幕空间吧)顶点位置
                float4 posWS : TEXCOORD0;       // 世界空间顶点位置
                float3 nDirWS : TEXCOORD1;      // 世界空间法线方向
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;                   // 新建输出结构
                    o.posCS = UnityObjectToClipPos( v.vertex );     // 变换顶点位置 OS>CS
                    o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 变换顶点位置 OS>WS
                    o.nDirWS = UnityObjectToWorldNormal(v.normal);  // 变换法线方向 OS>WS
                return o;                                           // 返回输出结构
            }
            // 输出结构>>>像素
            float4 frag(VertexOutput i) : COLOR {
                // 准备向量
                float3 nDir = normalize(i.nDirWS);
                float3 lDir = _WorldSpaceLightPos0.xyz;
                float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
                float3 hDir = normalize(vDir + lDir);
                // 准备点积结果
                float ndotl = dot(nDir, lDir);
                float ndoth = dot(nDir, hDir);
                // 光照模型
                float lambert = max(0.0, ndotl);
                float phong = dot(reflect(-lDir,nDir),vDir);
                // 返回结果
                return phong ;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

4、Blinn-Phong

(1)效果展示

(2)计算方式

Blinn-Phong=nDir dot hDir

hDir:lDir和vDir的中间角方向

(3)实现代码

csharp 复制代码
Shader "AP01/BlinnPhong" {
    Properties {
        _MainCol ("颜色", color) = (1.0, 1.0, 1.0, 1.0)
        _SpecularPow ("高光次幂", range(1, 90)) = 30
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入参数
            // 修饰字(满足小朋友太多的问好, 想保发量的大家看热闹)
                // uniform  共享于vert,frag
                // attibute 仅用于vert
                // varying  用于vert,frag传数据
            uniform float3 _MainCol;     // RGB够了 float3
            uniform float _SpecularPow;  // 标量 float
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;   // 顶点信息 Get✔
                float4 normal : NORMAL;     // 法线信息 Get✔
            };
            // 输出结构
            struct VertexOutput {
                float4 posCS : SV_POSITION;     // 裁剪空间(暂理解为屏幕空间吧)顶点位置
                float4 posWS : TEXCOORD0;       // 世界空间顶点位置
                float3 nDirWS : TEXCOORD1;      // 世界空间法线方向
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;                   // 新建输出结构
                    o.posCS = UnityObjectToClipPos( v.vertex );     // 变换顶点位置 OS>CS
                    o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 变换顶点位置 OS>WS
                    o.nDirWS = UnityObjectToWorldNormal(v.normal);  // 变换法线方向 OS>WS
                return o;                                           // 返回输出结构
            }
            // 输出结构>>>像素
            float4 frag(VertexOutput i) : COLOR {
                // 准备向量
                float3 nDir = normalize(i.nDirWS);
                float3 lDir = _WorldSpaceLightPos0.xyz;
                float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
                float3 hDir = normalize(vDir + lDir);
                // 准备点积结果
                float ndotl = dot(nDir, lDir);
                float ndoth = dot(nDir, hDir);
                // 光照模型
                float lambert = max(0.0, ndotl);
                float phong = dot(reflect(-lDir,nDir),vDir);
                float blinnPhong = pow(max(0.0, ndoth), _SpecularPow);
                // 返回结果
                return blinnPhong;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

5、实践

(1)漫反射+镜面反射+固有色

(i)效果
(ii)实现代码
csharp 复制代码
Shader "AP01/OldSchool" {
    Properties {
        _MainCol ("颜色", color) = (1.0, 1.0, 1.0, 1.0)
        _SpecularPow ("高光次幂", range(1, 90)) = 30
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }


            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入参数
            // 修饰字(满足小朋友太多的问好, 想保发量的大家看热闹)
                // uniform  共享于vert,frag
                // attibute 仅用于vert
                // varying  用于vert,frag传数据
            uniform float3 _MainCol;     // RGB够了 float3
            uniform float _SpecularPow;  // 标量 float
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;   // 顶点信息 Get✔
                float4 normal : NORMAL;     // 法线信息 Get✔
            };
            // 输出结构
            struct VertexOutput {
                float4 posCS : SV_POSITION;     // 裁剪空间(暂理解为屏幕空间吧)顶点位置
                float4 posWS : TEXCOORD0;       // 世界空间顶点位置
                float3 nDirWS : TEXCOORD1;      // 世界空间法线方向
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;                   // 新建输出结构
                    o.posCS = UnityObjectToClipPos( v.vertex );     // 变换顶点位置 OS>CS
                    o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 变换顶点位置 OS>WS
                    o.nDirWS = UnityObjectToWorldNormal(v.normal);  // 变换法线方向 OS>WS
                return o;                                           // 返回输出结构
            }
            // 输出结构>>>像素
            float4 frag(VertexOutput i) : COLOR {
                // 准备向量
                float3 nDir = normalize(i.nDirWS);
                float3 lDir = _WorldSpaceLightPos0.xyz;
                float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
                float3 hDir = normalize(vDir + lDir);
                // 准备点积结果
                float ndotl = dot(nDir, lDir);
                float ndoth = dot(nDir, hDir);
                // 光照模型
                float lambert = max(0.0, ndotl);
                float phong = dot(reflect(-lDir,nDir),vDir);
                float blinnPhong = pow(max(0.0, ndoth), _SpecularPow);
                float3 finalRGB = _MainCol * lambert + blinnPhong;
                // 返回结果
                return float4(finalRGB, 1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

(2)结合噪声图,实现类似不锈钢效果

(i)效果
(ii)实现方式
相关推荐
执笔论英雄4 小时前
【大模型学习cuda】入们第一个例子-向量和
学习
wdfk_prog4 小时前
[Linux]学习笔记系列 -- [drivers][input]input
linux·笔记·学习
在路上看风景5 小时前
4.5 顶点和片元
unity
Gary Studio6 小时前
rk芯片驱动编写
linux·学习
mango_mangojuice6 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习
lingggggaaaa6 小时前
安全工具篇&动态绕过&DumpLsass凭据&Certutil下载&变异替换&打乱源头特征
学习·安全·web安全·免杀对抗
PP东6 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
学电子她就能回来吗7 小时前
深度学习速成:损失函数与反向传播
人工智能·深度学习·学习·计算机视觉·github
AI视觉网奇8 小时前
ue 角色驱动衣服 绑定衣服
笔记·学习·ue5
wdfk_prog10 小时前
[Linux]学习笔记系列 -- [drivers][input]serio
linux·笔记·学习