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)实现方式
相关推荐
淡海水15 分钟前
【节点】[RandomRange节点]原理解析与实际应用
unity·游戏引擎·shadergraph·图形·randomrange
我的xiaodoujiao17 分钟前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 39--生成 Allure测试报告
python·学习·测试工具·pytest
QiZhang | UESTC17 分钟前
学习日记day53
学习
qq_5710993519 分钟前
学习周报三十
学习
风行男孩24 分钟前
stm32基础学习——串口(USART)的基本使用
stm32·嵌入式硬件·学习
诺狞猫24 分钟前
SF32LB52-i2c驱动TM1650
学习·sifli
却道天凉_好个秋28 分钟前
音视频学习(八十二):mp4v
学习·音视频·mp4v
好奇龙猫31 分钟前
【大学院-筆記試験練習:数据库(データベース問題訓練) と 软件工程(ソフトウェア)(6)】
学习
咚咚王者35 分钟前
人工智能之核心基础 机器学习 第十一章 无监督学习总结
人工智能·学习·机器学习
0和1的舞者36 分钟前
Python 中四种核心数据结构的用途和嵌套逻辑
数据结构·python·学习·知识