zoukankan      html  css  js  c++  java
  • Phong光照模型的Shader实现

    计算反射向量

    Phong用到的是反射向量,计算反射向量的公式是
    R = 2*N(dot(N, L)) - L
    这个公式是根据向量的投影公式以及平行四边形法则推导出来的
    详细步骤请看这篇文章,讲的非常好
     
    Shader "Phong"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
            _Specular("Specular", Range(1, 20)) = 1
            _SpecColor("SpecColor", Color) = (1,1,1,1)
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
    
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    
                #include "UnityCG.cginc"
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    float4 vertex : SV_POSITION;
                    float3 normal : TEXCOORD1;
                    float3 lightDir : TEXCOORD2;
                    float4 objPos : TEXCOORD3;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
    
                float4 _LightColor0;
    
                float _Specular;
                float4 _SpecColor;
    
                v2f vert (appdata_full v)
                {
                    v2f o;
                    o.objPos = v.vertex;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                    o.normal = v.normal;
                    o.lightDir = ObjSpaceLightDir(v.vertex);//把光向量从世界空间转成模型空间
                    return o;
                }
    
                fixed4 frag (v2f i) : SV_Target
                {
                    float3 L = normalize(i.lightDir);
                    float3 N = normalize(i.normal);
                    float3 viewDir = normalize(ObjSpaceViewDir(i.objPos));//计算出视线
    
                    float diff = saturate(dot(L, N));
                    float3 reflection = normalize(2.0 * N * diff - L);//反射向量
                    float spec = pow(max(0, dot(reflection, viewDir)), _Specular);
                    float3 finalSpec = _SpecColor.rgb * spec;
                    //漫反射+镜面高光+环境光
                    float3 finalLight = diff * _LightColor0 + finalSpec + UNITY_LIGHTMODEL_AMBIENT;
    
                    fixed4 col = tex2D(_MainTex, i.uv);
                    return col * float4(finalLight, 1);
                }
                ENDCG
            }
        }
    }

    Blinn-phong光照模型

    blinn是一个人的名字,他叫吉姆·布林,图形学界的大牛,他发现了使用半角向量代替反射向量的计算方式
    原理是通过视线向量跟光向量的半角向量代替反射向量
    halfVector = normalize( L + V );
     
    http://blog.csdn.net/herox25000/article/details/50491483



    求反射向量

    
    

    在图形学中,计算光照模型时,经常需要求取反射向量,一般的shader函数库都提供计算反射向量的方法,下面介绍一下如何手动计算反射向量。

    给定入射光线向量I和平面法向量N,求反射向量R,如下图。为了方便计算,这里假定I和N都是单位向量(模为1,编程时可先将I和N单位化)

    方法一

    设入射光线向量I和反射平面的法向量N之间的夹角为theta。连接I的始端和R的末端,则有

    R = 2P - I              (1)

    现在问题变成了如何求取P,设入射点0到P与N的交点的向量为S,那么有

    P = I + S               (2)

    现在问题变成了如何求取向量S,向量S即向量-N(注意,这里是-N,因为S和N的方向相反。)在向量N上的投影,根据向量的投影公式有

    因为N是单位向量,简化一下得到

    将S代入公式(2),再将P代入公式(1)得到

    方法二

    将R平移一下,与向量N的延长线相交。

    由于入射角和反射角相等,且I和R的长度也相等,所以三角形ION是等腰三角形。故有

    ON = 2S

    所以有

    R = I + 2S

    而S是-I在N上的投影,所以有

    由于N是单位向量,简化一下得到

    所以

    貌似方法二更直观些。

     
  • 相关阅读:
    Linux日志分析和管理
    Linux日志分析和管理
    Linux中的网络配置
    Linux中的网络配置
    安全之路 —— C++实现进程守护
    Linux内核升级、GRUB2引导故障处理与密码破解
    Linux内核升级、GRUB2引导故障处理与密码破解
    Linux启动流程和服务管理(init和systemd)
    Linux启动流程和服务管理(init和systemd)
    Linux下逻辑卷LVM的管理和RAID磁盘阵列
  • 原文地址:https://www.cnblogs.com/alps/p/7629820.html
Copyright © 2011-2022 走看看