shader光照和阴影

一.标准光照模型
OpenGL与Direct3D提供了几乎相同的固定功能光照模型。什么是固定功能光照模型?在过去只有固定绘制流水线的时候,该流水线被限制只能使用一个光照模型,也即是固定功能光照模型。该模型基于phong光照模型。在下面的这个例子里,我们使用一个“基本”模型对固定功能光照模型提供了简化版本。这个基本模型的数学描述为高级公式为:
   surfaceColor = emissive + ambient + diffuse + specular
从式子可以看出:物体表面的颜色是自发光(放射 emissive)、环境反射(ambient)、漫反射(diffuse)和镜面反射(specular)等光照作用的总和。每种光照作用取决于表面材质性质(例如亮度和材质颜色)和光源的性质(例如光的位置和颜色)。
下面对这个基本模型的各个部分进行讲解,最后我们使用CG语言写出该基本模型。

图片1.png

    
1.)自发光(emissive)
自发光光照作用独立于所有的光源。物体的自发光并不能照亮场景中的其他物体。换句话说,物体自发光不能照亮其他物体或者投下阴影。因此,一个放射性物体本身并不是一个光源。
另一个解释放射项的方法:它是一种在计算完其他所有光照项后添加的颜色。
自发光的数学公式:emissive = Ke
其中Ke代表材质的放射光颜色

2.)环境光(ambient)
环境光来自于四面八方,故环境放射光照项并不依赖于光源的位置。
1.环境放射项依赖:1.材质的反射能力 2.照射到材质上的环境光的颜色。
2.用于环境放射项的数学公式:
ambient = Ka * globalAmbient
其中ka是材质的环境反射系数,globalAmbient是入射环境光的颜色。
ka= tex2D(_MainTex, i.uv.xy).rgb
globalAmbient=UNITY_LIGHTMODEL_AMBIENT.xyz

环境光.png

3.)漫反射项(diffuse)

图片2.png

兰伯特(Lambert )光照模型是目前最简单通用的模拟漫反射的光照模型,定义如下:模型表面的明亮度直接取决于光线向量(light vector)和表面法线(normal)两个向量夹角的余弦值。光线向量是指这个点到光从哪个方向射入,表面法线则定义了这个表面的朝向。

diffuse = kd * lightColor * max ( NL(点积) , 0 )
max ( N
L(点积) , 0 )
规范化的向量N和L的点积是两个向量之间夹角的一个度量,夹角越小,P点受到更多的入射光照。而背向光源的表面将产生负数点积值,因此,公式*max ( NL(点积) , 0 )使得背向光源的表面的漫反射光为0,确保这些表面不会显示漫反射光照。

_WorldSpaceLightPos0这是一个表示世界做表中的光源的位置矢量或者方向矢量;
如果_WorldSpaceLightPos0.w为0,则表示该光源为平行光,_WorldSpaceLightPos0.xyz为此平行光的方向向量;
反之_WorldSpaceLightPos0.w不为0,则表示光源为点光源,_WorldSpaceLightPos0.xyz为此点光源.

半兰伯特光照模型
半兰伯特光照模型,解了决光照无法到达的区域, 背光面更亮一些
diffuse = kd * lightColor * (N * L *0.5 +0.5)
cos的值是-1到1之间,乘上0.5再加0.5后,值域是(0,1)

4.)镜面反射项(specular)

5366d0160924ab18b03b605431fae6cd7b890ba7.jpg

Phong光照模型:

图片3.png

Ks:材质的镜面反射颜色
facing的取值为0或1:当N* L大于0时为1,当N *L小于0时为0
R = reflect(-worldLightDir, worldNormal) ;

BlinnPhong光照模型
BlinnPhong光照模型混合和了Lambert的漫反射和标准的高光,渲染有时比Phong高光更柔和、更平滑,此外它的处理速度相当快,因此成为许多CG软件中默认的光照渲染方法。
specular = KslightColor pow(( dot(N,H), shininess )
其中H = (L + V) / | L+V |,实际就是normalize(L + V) , 计算H比计算反射向量R更快速。

4.)UnityCG.cginc常用内置函数
float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向。
float3 UnityWorldSpaceViewDir(float4 v) 输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向。
float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向。
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。
float3 UnityWorldSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向。
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向。没有被归一化。
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从模型空间转换到世界空间中。
float3 UnityObjectToWorldDir(flaot3 dir) 把方向矢量从模型空间变换到世界空间中。
float3 UnityWorldToObjectDir(float dir) 把方向矢量从世界空间变换到模型空间中。

二.法线贴图
逐像素计算光照时,我们每一个像素都会根据该点的法向量来计算最终该点的光照结果,那么,我们如果能够改变这个法线的方向,不是就可以改变这个点的光照结果了呢!那么,把纹理采样的思想用在这里,我们直接用一张图来存储法线(或者法线偏移值,见下文),逐像素计算时,在采样diffuse贴图的时候,再采样一张法线的贴图,就可以修改法线了,进而修改最终的效果。

什么是切线空间?
切线空间就是,基于模型上的一个顶点建立的坐标空间,它的X轴是这个顶点在模型中的切线分量,Z轴是改点在模型上的法线,Y轴就是这个顶点的副切线,因为坐标空间XYZ三个面都是互相垂直的嘛,所以这个副切线我们是可以求出来的(以为同样是与一个平面垂直的单位向量是有两方向的,在Unity中模型会提供一个副切线的方向的数据)。
来上一个图,让我们更好的理解这个所谓的切线空间。

QQ截图20170424172859.png

我们的表面法线是单位向量, 位于范围 -1.0 到 1.0 之间. 而RGB的值域是(0,1) , 我们可以通过把法线范围转换为 0.0 到 1.0之间来把法线向量(x, y, z)存储到一个 RGB 纹理贴图中.
Color.rgb = Normal.xyz / 2.0 + 0.5;
现在我们可以分析为什么tangent space法线贴图是偏蓝色了.因为这个面渲染时计算机认为这个面的"弯曲"程度很小,即面上各个点插值得来的法线相互间偏差很小.基本跟整个面的垂直方向不会差太多.因此在tangent space里,这些法线都跟z轴偏差较小.而z轴是被保存在贴图里的b字节处(蓝色通道)里.所以贴图显示出来的颜色就偏蓝了.

http://blog.csdn.net/candycat1992/article/details/41605257

三.(渲染路径)Rendering Paths
1.Deferred Lighting,延迟光照路径。3者中最高质量地还原光照阴影。光照性能只与最终像素数目有关,光源数量再多都不会影响性能。
2.Forward Rendering,前向渲染路径。能发挥出Shader全部特性的渲染路径,当然也就支持像素级光照。最常用、功能最自由,性能与光源数目*受光照物体数目有关,具体性能视乎其具体使用到的Shader的复杂度。
3.Vertex Lit,顶点光照路径。顶点级光照。性能最高、兼容性最强、支持特性最少、品质最差。

1.)前向渲染
根据影响物体的光源的不同,正向渲染路径用单个或多个通道来渲染物体。在正向渲染中,光源本身也会根据他们的设置和强度受到不同的对待。
在正向渲染中,影响物体的最亮的几个光源使用逐像素光照模式。接下来,最多有4个点光源会以逐顶点渲染的方式被计算。其他光源将以球面调和(Spherical Harmonics)的方式进行计算,球面调和技术计算很快但只能得到近似值。根据以下的规则判断一个光源是否为逐像素光源:

渲染模式被设置为不重要(Not Important)的光源以逐顶点或球面调和的方式进行计算
最亮的方向光源为像素光源
渲染模式被设置重要(Important)的光源为像素光源
如根据以上规则得到的像素光源数量小于质量设置中的像素光源数量(Pixel Light Count),为了减少亮度,会有更多的光源以逐像素的方式进行渲染

Base Pass 基本通道
Base pass renders object with one per-pixel directional light and all SH/vertex lights. This pass also adds any lightmaps, ambient and emissive lighting from the shader. Directional light rendered in this pass can have Shadows. Note that Lightmapped objects do not get illumination from SH lights.
Note that when “OnlyDirectional” pass flag is used in the shader, then the forward base pass only renders main directional light, ambient/lightprobe and lightmaps (SH and vertex lights are not included into pass data).
需要在设置Pass的 Tags { "LightMode"="ForwardBase" }
定义宏#pragma multi_compile_fwdbase
Additional Passes附加通道
Additional passes are rendered for each additional per-pixel light that affect this object. Lights in these passes by default do not have shadows (so in result, Forward Rendering supports one directional light with shadows), unless multi_compile_fwdadd_fullshadows variant shortcut is used.
需要在设置Pass的 Tags { "LightMode"="ForwardAdd" }
定义宏#pragma multi_compile_fwdadd

https://docs.unity3d.com/Manual/RenderTech-ForwardRendering.html

四.投射阴影和接收阴影
1.)投射阴影
需要有平行光,且平行光开启阴影
物体的renderer组件需要开启Cast Shadow
物体的shader需要一个tags为”ShadowCaster”的pass来让物体加入阴影贴图的渲染内.可用FallBack "Specular"来让Unity自动查询可用的shader,注意透明物体需要特别指定.另外,如果有使用顶点动画,则需要自己定义可用的shader

2.)接收阴影
Unity中,对于衰减,主要是通过一张光照衰减纹理(_LightTexture0)的采样得到,其采样操作主要是在光照空间中进行。对于阴影,一般不会采用实时阴影的方式(性能耗费太高),但是现在随着技术的发展,越来越多的游戏采用的实时光照,当然这是对整体的光照的优化有一个极其高的情况下。一般情况下都是将场景烘培,对模型自身添加相应的光照设置。
在unity中,主要是通过一个shadowCaster的shader来实现对阴影的计算,对于物体是否投射阴影可以在其自身的组件上设置。而unity将阴影和衰减的计算合并在一起,主要通过三个基本的内部操作来实现:在a2v的结构体中设置SHADOW_COORDS(n),在vert shader中进行TRANSFER_SHADOW(o),最后在frag shader中进行 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos),此时得到的atten就是综合了衰减和阴影的结果,可以用其来作为衰减和阴影的因子与最终的光照颜色相乘。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • <转>我也忘了转自哪里,抱歉,感谢原作者 什么是Shader Shader(着色器)是一段能够针对3D对象进行操作...
    星易乾川阅读 5,574评论 1 16
  • 版本记录 前言 OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着...
    刀客传奇阅读 6,019评论 0 2
  • 一、Surface Output (表面着色器的标准输出结构)Surface Shader的标准输出结构-第一要素...
    CarlDonitz阅读 906评论 0 1
  • 给你 ——释白丁 时时想起的 是你那含羞时粉红的脸颊 在微微的笑容的衬托下 如春天含苞待放的花 我小心翼翼地...
    释白丁阅读 207评论 0 0
  • 每个人都有自己的舞台,都是自己生命中的主角。人有时可能会身不由己,但是我觉得坚持做真实的自己,就会成就一个...
    李嘉欣_d162阅读 264评论 0 1