庄懂课L05

目录

各种向量

常用向量:(全要记)

所在空间:(暂时只记WS,其余看热闹)

漫反射

镜面反射-Specular:

用连连看实现Phone

一步一步实现

用代码写一个OldShool


各种向量

常用向量:(全要记)

nDir:法线方向,点乘操作时简称n;

IDir:光照方向,点乘操作时简称I;

vDir:观察方向,点乘操作时简称V;

rDir:光反射方向,点乘操作时简称r;

hDir:半角方向(Halfway),IDir和vDir的中间角反向,点乘操作时简称h;

所在空间:(暂时只记WS,其余看热闹)

OS:ObjectSpace 物体空间,本地空间;

WS:WorldSpace世界空间;

VS:ViewSpace观察空间

CS:HomogenousClipSpace齐次裁剪空间;

TS:TangentSpace切线空间;

TXS:TextureSpace纹理空间;

漫反射

满反射-Diffuse

因其向四面八方均匀散射,所以反射亮度和观察者看的方向无关;

实现方式:Lambert(n dot I),显然vDir不参与计算;

镜面反射-Specular:

因其反射具有明显方向性,所以观察者的视角决定了反射光线的有无,明暗;

实现方式:

Phone(r dot v),即光反射方向和视角方向越重合,反射越强;

Bline-Phone(n dot h),即法线方向和半角方向越重合,反射越强;

用连连看实现Phone

思路:先获取正儿八经的光照方向,然后在求出光的反射方向,在与摄像机的观察反向做点积(计算机图形学常用来进行方向性判断,如两矢量点积大于0,则它们的方向朝向相近;如果小于0,则方向相反。)

一步一步实现

在shaderforge中拿到的光方向一般是光的反方向,所以要乘以-1得到真正的光方向,再利用Reflect反射节点和模型表面的法线方向来求得光的发射方向,然后再与摄像机的观察方向来做点积,然后用Max节点来截取掉小于零的部分,然后用Power节点来控制高光的范围大小(Power是啥?一般叫高光次幂; PS里正片叠底就是Power的效果)

但其实前面的大部分可以用光反射方向节点连接得到(上面下面的连接结果得到的效果是等价的)

用连连看实现BlinnPhone

用法线方向和半角方向做点积

正常视角看Phone和BlinnPhone高光区别不大,但是逆光看的话Phone更好看,blinnPhone的存在只是为了节省一点点性能(图形学刚开始都是能省则省)

用代码写一个OldShool

首先声明两个公开的美术可调的参数

 Properties {
        _MainCol ("颜色",color) = (1.0,1.0,1.0,1.0)
        _SpecularPow ("高光次幂",range(1,90)) = 30
    }

然后一些形式段,形式段之后就是  VertexInput前的参数声明要和Prooerties段定义的参数一一对应;选取参数类型

// uniform 共享于vert,frag
            // attibute 仅用于vert
            // varying 用于vert,frag
            // VertexInput前的参数声明:要和Prooerties段定义的参数一一对应;适当选取参数类型

            uniform float3 _MainCol;     // RGB够了 float3
            uniform float _SpecularPow;//标量 float

定义输入结构

 // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;   //顶点信息 Get
                float3 normal : NORMAL;      //法线信息 Get
            };

定义输出结构  TEXCOORD0 1 2 3这样的可以理解为学号卡,可以跳号但是不能重复

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 = i.nDirWS;
                float3 lDir = _WorldSpaceLightPos0.xyz;
                float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
                float3 hDir = normalize(vDir+lDir);

                // 准备点积结果
                float nDotI = dot(nDir,lDir);            //点乘法线方向和光方向
                float nDoth = dot(nDir,hDir);           //点乘法线方向和半角方向

                // 光照模型
                float lambert = max(0.0,nDotI); //对点积结果进行截断处理
                float blinnPhone = pow(max(0.0,nDoth),_SpecularPow);
                float3 finalRGB = _MainCol*lambert + blinnPhone;

                // 返回结果
                return float4(finalRGB,1.0);
            }

用连连看实现lambert+BlinnPhone

很简单直接把lambert和BlinnPhone连出来然后相加就可以

复习一下lambert:法线方向和光方向进行点积,然后使用Remap将点击结果从-1到1映射到0到1,halflambert就是乘0.5再加上0.5,但是我们这里只用Lambert就好

复习一下BlinnPhone:就是法线方向和半角方向进行点积,再使用max节点取相对于0的更大值,再用Power和Slider来控制一个高光点的效果

unity

猜你喜欢

转载自blog.csdn.net/xu1747902112/article/details/129991385