漫反射实现+逐像素漫反射+逐像素漫反射实现

标准光照的构成结构

自发光:材质本身发出的光,模拟环境使用的光

漫反射光:光照在粗糙材质后,光的反射方向随机,还有一些光发生了折射,造成材质

表面没有明显的光斑。

高光反射光:光照到材质表面后,无(低)损失直接反射给观察者眼睛,材质表面能观察

到光斑。

环境光:模拟场景光照(简单理解为太阳光)

裴祥凤提出的光照理论:标准光照=自发光+漫发射光+高光反射光+环境光这个理论是模拟

光照效果,并不是真实效果。

以他的名字命名:Phong光照模型

逐顶点光照和逐像素光照

顶点着色器:会在模型渲染点上运行,其他的点会线性插值

片元着色器:会在模型的所有像素点上运行。

逐顶点光照:会在顶点着色器上进行光照运算(高洛德着色)

逐像素光照:会在片元着色器上运行光照运算(phong着色)

逐像素比逐顶点效果好,逐顶点比逐像素性能好

漫反射光照(兰伯特定律)

漫反射光照=光源的颜色*材质的漫反射颜色*MAX(0,标准化后物体表面法向量·标准化

后光源方向向量)

光源颜色:场景中光GameObject取得

材质的漫反射颜色:材质球配置

Max是数学函数,标准化也有函数

表面法线向量:CPU加载模型后,传递到GPU中的

光源方向向量:场景中光GameObject取得

实现:所有数据拿到,拿公式计算

半兰伯特定律:将整体颜色降低一半,再加一半

漫反射光照=(光源的颜色·材质的漫反射颜色)·((标准化后物体表面法线向量·标准化后光源

方向向量)·0.5+0.5)

高光反射光照

高光光照=光源的颜色*材质高光反射颜色*MAX(0,标准化后的观察方向向量·标准化后的反射方向)^光晕系数

逐顶点光照测试相关代码如下所示:

cs 复制代码
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "CreateTest/DiffuseVertex"
{
    Properties
    {
        _DiffuseColor("漫反射颜色",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            //设定光照模式为前向模式(才能正常获取光的颜色和光的方向)
            //Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //加载Cg语言的脚本,用来处理光照参数
            //处理光照的Cg库文件(cginc扩展名)
            //目录在Unity的安装目录下Editor/Data/CGIncludes/Lighting.cginc
            #include "Lighting.cginc"
            //导入材质颜色
            fixed4 _DiffuseColor;
            
            //如果在Cg编程中,顶点或片元着色器接收多个数值的时候,一般会用结构体实现

            //从CPU接收到的数据
            struct c2v
            {
                float4 vertex:POSITION;//从CPU接收到的模型空间下的点的位置
                float3 normal:NORMAL; //从CPU接收到的当前点的模型空间下的法线向量
            };

            //因为在顶点着色器中,需要计算裁剪空间下点的位置和Phong着色计算出的兰伯特定律计算后的颜色
            struct v2f
            {
                float4 pos:SV_POSITION;//经过顶点着色器计算后的,当前点的裁剪空间下的位置
                fixed3 color : COLOR;//经过兰伯特定律计算后的当前点的颜色
            };
            //高洛德着色(逐顶点光照),光照计算应该编写在顶点着色器中
            v2f vert(c2v data)
            {
                //顶点着色器传递给片元着色器的数据结构体声明
                v2f r;
                //必须做的:将点从模型空间下,转换到裁剪空间下
                r.pos=UnityObjectToClipPos(data.vertex);
                
                //兰伯特定律计算
                //漫反射光照=光源的颜色*材质的漫反射颜色*MAX(0,标准化后物体表面法线向量*标准化后光源方向向量)
    
                //光照是在世界中发生,需要将所有的数值,变换到世界坐标系下,再运算
                // _Object2World矩阵是Unity提供的,用于转换模型空间下到世界空间下的转换矩阵
                //因为法线传递过来的是3x1的列矩阵,_Object2World是4x4的齐次矩阵,如果想做矩阵乘法,需要将齐次矩阵,变成3x3矩阵
                fixed3 worldNormal = normalize(mul((float3x3)unity_ObjectToWorld, data.normal));
                //获得直射光的光方向
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                //公式运算
                fixed3 diffuse=_LightColor0.rgb* _DiffuseColor.rgb* max(0,dot(worldNormal,worldLightDir));
                
                //根据高洛德光照模型,将环境光追加在最终计算后的颜色上
                r.color = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuse;

                //r.color = _LightColor0.rgb;

                return r;
            }
            //千万记得带"数字",若未带4可能会出现材质球颜色为红色情况
            fixed4 frag(v2f data) :SV_Target
            {
                return fixed4(data.color,1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

逐像素光照测试相关代码如下:

cs 复制代码
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "CreateTest/DiffusePixel"
{
    Properties
    {
        _DiffuseColor("漫反射颜色",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            //设定光照模式为前向模式(才能正常获取光的颜色和光的方向)
            //Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //加载Cg语言的脚本,用来处理光照参数
            //处理光照的Cg库文件(cginc扩展名)
            //目录在Unity的安装目录下Editor/Data/CGIncludes/Lighting.cginc
            #include "Lighting.cginc"
            //导入材质颜色
            fixed4 _DiffuseColor;
            
            //如果在Cg编程中,顶点或片元着色器接收多个数值的时候,一般会用结构体实现

            //从CPU接收到的数据
            struct c2v
            {
                float4 vertex:POSITION;//从CPU接收到的模型空间下的点的位置
                float3 normal:NORMAL; //从CPU接收到的当前点的模型空间下的法线向量
            };

            //因为在顶点着色器中,需要计算裁剪空间下点的位置和Phong着色计算出的兰伯特定律计算后的颜色
            struct v2f
            {
                float4 pos:SV_POSITION;//经过顶点着色器计算后的,当前点的裁剪空间下的位置
                //fixed3 color : COLOR;//经过兰伯特定律计算后的当前点的颜色
                float3 worldNormal:NORMAL;//经过矩阵转换后世界空间下的,法线向量
            };
            //将渲染点,从模型空间下,转换到裁剪空间下
            //将渲染点对应的法线,从模型空间下,转换到世界空间下
            v2f vert(c2v data)
            {
                //顶点着色器传递给片元着色器的数据结构体声明
                v2f r;
                
                
                //必须做的:将点从模型空间下,转换到裁剪空间下
                
                r.pos=UnityObjectToClipPos(data.vertex);
                
                //几何运算,在顶点着色器中完成,再将运算好的数值,传递给片元着色器
                // _Object2World矩阵是Unity提供的,用于转换模型空间下到世界空间下的转换矩阵
                //因为法线传递过来的是3x1的列矩阵,_Object2World是4x4的齐次矩阵,如果想做矩阵乘法,需要将齐次矩阵,变成3x3矩阵
                r.worldNormal = mul((float3x3)unity_ObjectToWorld, data.normal);
           
                //r.color = _LightColor0.rgb;

                return r;
            }
            //phong着色(逐像素光照),光照计算应该编写在片元着色器中
            fixed4 frag(v2f data) :SV_Target
            {
                //兰伯特定律计算
                //漫反射光照=光源的颜色*材质的漫反射颜色*MAX(0,标准化后物体表面法线向量*标准化后光源方向向量)
                //光照是在世界中发生,需要将所有的数值,变换到世界坐标系下,再运算
                //世界空间下的,表面法线向量标准化
                fixed3 worldNormal = normalize(data.worldNormal);
                
                //获得直射光的光方向,标准化向量
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                
                //公式运算
                fixed3 diffuse = _LightColor0.rgb * _DiffuseColor.rgb * max(0, dot(worldNormal, worldLightDir));

                //根据Phong光照模型,将环境光追加在最终计算后的颜色上
                fixed3 color = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuse;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

两者之间的区别如下图所示:

该系列专栏为网课课程笔记,仅用于学习参考。

相关推荐
weixin_423995006 小时前
unity 读取csv
unity·c#
EQ-雪梨蛋花汤14 小时前
【Flutter】Flutter + Unity 插件结构与通信接口封装
flutter·unity·游戏引擎
折纸星空Unity课堂14 小时前
Unity之基于MVC的UI框架-含案例
ui·unity·mvc
暴走约伯14 小时前
【3DMax脚本MaxScript开发:创建高效模型虚拟体绑定和材质管理系统,从3DMax到Unreal和Unity引擎_系列第一篇】
3d·unity·材质·unreal·maxscript
SlowFeather1 天前
Unity 使用 ADB 实时查看手机运行性能
android·unity·adb·性能优化·profiler
小赖同学啊1 天前
Unity 和 Unreal Engine(UE) 两大主流游戏引擎的核心使用方法
unity·游戏引擎·虚幻
AgilityBaby1 天前
unity Animation学习,精准控制模型动画播放
学习·3d·unity·游戏引擎
EQ-雪梨蛋花汤1 天前
【Flutter】Unity 三端封装方案:Android / iOS / Web
android·flutter·unity
foenix661 天前
PicoVR眼镜在XR融合现实显示模式下无法显示粒子问题
android·unity·c#·xr·pico