《Unity Shader入门精要》笔记(四) 光照and阴影的理解

6 篇文章 0 订阅

第九章 更复杂的光照

  1. 渲染路径是指什么?什么作用?

    • 一种能让Unity知道设定哪些预制变量数据的参数。有前向渲染路径、延迟渲染路径和顶点照明渲染路径
      通过在每个Pass中设置Tags{“LightMode” = “ForwardBase”}来实现
      参考UntiyPassTags设置
    • 前向渲染:深度检测,对各片元进行依次进行多个光照计算,每个光源都要计算一次Pass。(缺点:多光源计算量大)
    • 延迟渲染:深度检测,并将计算需要的数据存储到G缓冲,然后执行依次光照计算的Pass。主要是多光源的时候应用不同。固定两个Pass。(缺点:不支持真正的抗锯齿;不能处理半透明;显卡需要支持MRT) 参考GBuff实现细节
    • 顶点照明渲染:前向渲染的特化方式,在一个Pass内可以访问所有的光照,计算出所有的结果。
      参考Unity中的Multi预定义
      参考UnityShader中常用变量
  2. Unity中的光源有哪些?有什么特点?

    • 平行光:只有方向,所有点看到的方向都一样。不会衰减。
    • 点光源:有位置,有范围,有衰减
    • 聚光灯:有位置,有方向,锥形范围,有衰减。计算范围和衰减相对来说最复杂。
  3. 多光源的光照如何计算?

    多Pass,第一个Pass设置Tags{“LightMode”=”ForwardBase”},另一个Pass设置{“LightMode”=”ForwardAdd”}。
    BasePass中计算平行光(最强的一个平行光)、环境光。Additional Pass对每个光照调用一次,依次计算所有的光照。一般Additional Pass混合为颜色叠加即Blend One One
    如果worldNormal传给frag,那么在frag函数中需要再normalize一次,因为自动差值之后,可能已经不是单位向量了。

  4. 如果光照设置为不重要,只能在BasePass中处理了吗?但BasePass中只能访问4个非重要光照的信息,其他的怎么解决?AdditionalPass应该能在顶点函数中处理光照吧?

  5. 光照衰减怎么计算?

    Unity使用一个_LightTexture0纹理(_LightTextureB0如果开启了cookie)来作为查表数据,减少计算。减少了一定灵活性。
    点光源的衰减计算:

        float3 lightCoord = mul(_LightMatrix0, float4(i.worldPos, 1)).xyz;
        fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;

    spot衰减计算:

    float4 lightCoord = mul(_LightMatrix0, float4(i.worldPos, 1));
    fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
  6. 什么是阴影,生成阴影的原理是什么?有没有什么限制?透明物体的阴影有什么不一样的地方?

    假设从灯光所在的地方有个摄像机,那么该这相机看不到的地方,实际就是阴影产生的区域。这就是阴影贴图的思想。当然不同的光照实际计算的方式不太一样,在Unity开启阴影之后,直接得到结果阴影纹理。
    那么又如何使用这个阴影纹理呢?
    传统方法:对于一个需要绘制的像素坐标,转换到对应的光照空间之后,计算深度,如果该深度大于阴影纹理中对应的该点的深度值,那说明这点就在阴影中。

    • 为了减少这个空间转换的计算,Unity现在采用屏幕空间的阴影映射技术(并不是所有都支持,不支持的话采用传统方式),阴影纹理在存储的时候已经转到屏幕坐标空间下,当前摄像机也同时产生一个屏幕空间下的深度纹理。那么在计算投影的时候,就只需要比较两个纹理中同一点的深度值就可以了。相机深度纹理中的值较大的话,就说明在阴影中。

    • 看一下TRANSFER_SHADOW宏源码的实现可以验证上面的说法:
      不支持屏幕映射的情况,可以看到是做了两次坐标空间转换,就是上面说的传统方法将坐标转换到对应的光照空间下。
      #define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );
      支持屏幕映射的情况,直接计算屏幕坐标。

      #define TRANSFER_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);

    • 三个重要的宏:
      SHADOW_COORDS(n)
      TRANSFER_SHADOW(o);
      UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
    • 透明物体的阴影使用不同fallback,可以需要再设置双面投影。

链接汇总:
UntiyPassTags设置
GBuff实现细节
Unity中的Multi预定义
UnityShader中常用变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值