前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shader-基础光照-漫反射光照模型

Shader-基础光照-漫反射光照模型

作者头像
祝你万事顺利
发布2019-05-28 23:13:14
9160
发布2019-05-28 23:13:14
举报
文章被收录于专栏:Unity游戏开发Unity游戏开发
漫反射(diffuse)

当光线从光源照射到模型表面,该表面回向每个方向散射多少辐射量 漫反射符合兰伯特定律:反射光线的强度与表面法线与光源方向之间的夹角的余弦值成正比. 漫反射的计算:

Diffuse.png

n表面法线和l指向光源的向量的单位向量点乘来表示余弦值,用max防止点乘结果为负数,防止物体被从后面来的光源照亮. 由公式可知,计算漫反射的结果需要四个参数: 1.入射光线颜色和强度 2.材质的漫反射系数 3.表面法线 4.光源方向 在cg中我们使用saturate函数来事先max的操作

逐顶点光照:也被称为高落德着色,在每个顶点计算光照,在渲染图元内部进行插值.光照模型中出现非线性的计算时,会出现问题. 逐像素光照:Phong着色,在片面之间对顶点法线进行插值.

漫反射的逐顶点光照的实现:

代码语言:javascript
复制
Properties{
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }

在Properties中声明一个color用来得到材质的漫反射材质

代码语言:javascript
复制
SubShader{
            Pass{
                Tags{"LightMode" = "ForwardBase"}

LightMode是一种Pass标签,用来定义该Pass在Unity流水线中的角色

代码语言:javascript
复制
CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"

导入Unity的内置文件Lighting.cginc,使用Unity内置变量需要 为了在Shader中使用Properties的属性,需要定义一个和该属性类型相匹配的变量

代码语言:javascript
复制
fixed4 _Diffuse;

两个结构体

代码语言:javascript
复制
                struct a2v {
                    float4 vertex : POSITION;
                    float4 normal : NORMAL;
                };
                struct v2f {
                    float4 pos : SV_POSITION;
                    fixed3 color : COLOR;
                };

在顶点着色器中计算漫反射部分

代码语言:javascript
复制
v2f vert(a2v v) {
                    v2f o;
                    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                    fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                    float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                    fixed3 diffuse = _LightColor0 * _Diffuse.rgb * saturate(dot(worldLight,worldNormal));
                    o.color = diffuse + ambient;
                    return o;
                }

1.基本任务将模型顶点从模型空间转换到裁剪空间. 2.通过Unity内置变量获取环境光部分 3.法线变换,将法线与变换矩阵的逆转置的矩阵进行矩阵乘法,得到正确的变换后的法线(在世界坐标下),这里法线是一个三维矢量,变换矩阵只需截取3x3即可 4.直接使用_WorldSpaceLightPos()得到平行光 5.通过上面的公式计算得到diffuse 6.将得到的颜色信息在frag中进行输出

逐像素光照

对Shader进行一些修改来实现逐像素的漫反射效果,代码改变部分

代码语言:javascript
复制
struct v2f {
                    float4 pos : SV_POSITION;
                    fixed3 worldNormal : TEXCOORD0;
                };
                v2f vert(a2v v) {
                    v2f o;
                    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                    o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
                    return o;
                }
                fixed4 frag(v2f i) : SV_Target{
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                    fixed3 worldNormal = normalize(i.worldNormal);
                    float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                    fixed3 diffuse = _LightColor0 * _Diffuse.rgb * saturate(dot(worldLight, worldNormal));
                    fixed3 color = diffuse + ambient;

                    return  fixed4(color, 1.0);
                }

我们将每次的计算放在fragment中进行,得到的结果更加平滑.但是即使我们加入了环境光,仍然无法解决背光面明暗一样的情况,为了改善这种情况,我们使用下面的光照模型

半兰伯特模型

半兰伯特模型.png

我们对点乘结果进行α倍数的缩放在加上β的偏移,大多数情况下两个值为0.5 这样我们将[-1,1]映射到[0,1],在此模型下背光面也有明暗变化,此模型没有物理依据,仅作为视觉增强的效果. 背面效果图:

halfLambert.png

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 漫反射(diffuse)
  • 漫反射的逐顶点光照的实现:
  • 逐像素光照
  • 半兰伯特模型
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档