当前位置:首页 > 其他 > 正文内容

Unity中的光源类型(向前烘托途径进行光照核算)

邻居的猫1个月前 (12-09)其他342

Unity中的光源类型

Unity中共支撑4种光源类型:

  • 平行光
  • 点光源
  • 聚光灯
  • 面光源(在光照烘焙时才能够发挥作用)

光源的特点:

  • 方位
  • 方向(到某个点的方向)
  • 色彩
  • 强度
  • 衰减(到某个点的衰减)
  1. 平行光

    平行光的几许界说是最简略的,平行光能够照亮的规模是无限远的,且对与场景中的各个点的方向和强度都是共同的。在场景中作为太阳这样的人物呈现。

    img

  2. 点光源

    点光源照亮的空间是有限的,它是由空间中的一个球体界说的。其能够表明由一个点宣布的、向一切方向延伸的光。

    img

    需求留意的是点光源的方向特点是由某个点减去点光源方位所得出的向量,表明点光源在该点的光照方向。点光源会衰减,跟着物体逐步原理点光源,其接收到的光照强度也会逐步减小。

  3. 聚光灯

    聚光灯是这3种光源类型中最杂乱的一种。它的照亮空间相同是有限的,但不再是简略的球体,而是由空间中的一块锥形区域界说的。聚光灯能够用于表明由一个特定方位动身、向特定方向延伸的光。

    img

​ 这块锥形区域的半径由面板中的Range特点决议,而锥体的打开视点由Spot Angle特点决议。咱们相同也能够在 Scene视图中直接迁延聚光灯的线框(如中心的黄色控制点以及四周的黄色控制点)来修正它的特点。聚光灯的方位相同是由Transform组件中的Position特点界说的。关于方向特点,咱们需求用聚光灯的方位减去某点的方位来得到它到该点的方向。聚光灯的衰减也是跟着物体逐步远离点光源而逐步减小,在锥形的极点处光照强度最强,在锥形的鸿沟处强度为0。其中心的衰减值能够由一个函数界说,这个函数相关于点光源衰减核算公式要愈加杂乱,由于咱们需求判别一个点是否在锥体的规模内。

在向前烘托中处理不同的光照类型

Shader "Custom/ForwardRanderingLearn"
{
    Properties{
        _Diffuse("Diffuse", Color) = (1,1,1,1) //漫反射色彩
        _Specular("Specular",Color) = (1,1,1,1)//高光反射色彩
        _Gloss("Gloss",Range(8.0,256)) = 20 //高光反射强度
    }
    
    SubShader{
        Tags { "RenderType" ="Opaque" }
        
        Pass
        {
            //设置烘托形式
            Tags{ "LightMode"="ForwardBase" }
            
            CGPROGRAM
            //增加宏引证
            #pragma multi_compile_fwdbase

            #pragma  vertex vert
            #pragma  fragment frag

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //平行光的方向

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //环境光

                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal,worldLightDir));

                //核算高光反射
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);

                //平行光的衰减因子
                fixed atten = 1.0;

                return fixed4(ambient + (diffuse + specular) * atten,1.0);
            }
            ENDCG
        }
        
        Pass
        {
            Tags {"LightMode" = "ForwardAdd"}
            
            //敞开混合形式
            Blend One One
            
            CGPROGRAM
            
            #pragma multi_compile_fwdadd

            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            v2f vert(a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);

                //依据光照类型确认光源方向
                #ifdef USING_DIRECTIONAL_LIGHT
                //平行光
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                #else
                //非平行光
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
                #endif

                //漫反射光
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal,worldLightDir));

                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);

               
                //依据光源类型来设置衰减函数
                #ifdef  USING_DIRECTIONAL_LIGHT
                    fixed atten = 1.0;
                #else
                    #if defined(POINT)
                         float3 lightCoord = mul(unity_WorldToLight,float4(i.worldPos,1.0)).xyz;
                         fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;
                    #elif defined (SPOT)
                         float4 lightCoord = mul(unity_WorldToLight,float4(i.worldPos,1.0)).xyz;
                         fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
                    #else
                        fixed atten = 1.0;
                    #endif

                #endif

                return fixed4((diffuse + specular) * atten,1.0);
            }
            
            ENDCG
        }
    }
    FallBack "Specular"
   
}

在此shader中,在Base Pass中处理场景中最重要的平行光。

本场景中只要一个平行光,因而Base Pass只会履行一次。假如场景中包括多个平行光,Unity则会挑选最亮的平行光传递给Base Pass进行逐像素处理,其它平行光会依照逐极点或在Additional Pass中依照逐像素方法处理。

假如场景中没有任何平行光,那么Base Pass会当满足黑的光源处理。

关于Base Pass来说,它处理的逐像素光源类型一定是平行光。咱们能够运用__WorldSpaceLightPos0来得到这个平行光的方向(方位对平行光来说没有意义),运用_LightColor0来得到它的色彩和强度(_LightColor0已经是色彩和强度相乘后的成果),由于平行光能够认为是没有衰减的,因而这儿咱们直接令衰减值为1.0。相关代码如下:

        //  Compute  diffuse  term
        fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));

        ...

        //  Compute  specular  term
        fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)),
        _Gloss);

        //  The  attenuation  of  directional  light  is  always  1
        fixed  atten  =  1.0;

        return  fixed4(ambient  +  (diffuse  +  specular)  *  atten,  1.0);

接下来,咱们需求为场景中其他逐像素光源界说Additional Pass。为此,咱们首要需求设置Pass的烘托途径标签:

        Pass  {
            //  Pass  for  other  pixel  lights
            Tags  {  "LightMode"="ForwardAdd"  }

            Blend  One  One

            CGPROGRAM

            //  Apparently  need  to  add  this  declaration
            #pragma  multi_compile_fwdadd

与Base Pass不同的是,咱们还运用Blend指令敞开和设置了混合形式。这是由于,咱们期望Additional Pass核算得到的光照成果能够在帧缓存中与之前的光照成果进行叠加。假如没有运用Blend指令的话,Additional Pass会直接覆盖掉之前的光照成果。在本例中,咱们挑选的混合系数是Blend One One,这不是必需的,咱们能够设置成Unity支撑的任何混合系数。常见的还有Blend SrcAlpha One。

一般来说,Additional Pass的光照处理和Base Pass的处理方法是相同的,因而咱们只需求把Base Pass的极点和片元着色器代码粘贴到Additional Pass中,然后再略微修正一下即可。这些修正往往是为了去掉Base Pass中环境光、自发光、逐极点光照、SH光照的部分,并增加一些对不同光源类型的支撑。因而,在Additional Pass的片元着色器中,咱们没有再核算场景中的环境光。

因而在核算光源的5个特点——方位、方向、色彩、强度以及衰减时,色彩和强度咱们依然能够运用_LightColor0来得到,但关于方位、方向和衰减特点,咱们就需求依据光源类型别离核算。首要,咱们来看怎么核算不同光源的方向:

        #ifdef  USING_DIRECTIONAL_LIGHT
              fixed3  worldLightDir  =  normalize(_WorldSpaceLightPos0.xyz);
        #else
              fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPosition.xyz);
        #endif

处理不同光源的衰减:

        #ifdef  USING_DIRECTIONAL_LIGHT
            fixed  atten  =  1.0;
        #else
            float3  lightCoord  =  mul(_LightMatrix0,  float4(i.worldPosition,  1)).xyz;
            fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
        #endif

咱们相同经过判别是否界说了USING_DIRECTIONAL_LIGHT来决议当时处理的光源类型。假如是平行光的话,衰减值为1.0。假如是其他光源类型,那么处理更杂乱一些。虽然咱们能够运用数学表达式来核算给定点相关于点光源和聚光灯的衰减,但这些核算往往触及开根号、除法等核算量相对较大的操作,因而Unity挑选了运用一张纹路作为查找表(Lookup Table, LUT),以在片元着色器中得到光源的衰减。咱们首要得到光源空间下的坐标,然后运用该坐标对衰减纹路进行采样得到衰减值。

image-20240923080110029

注:本文为冯乐乐《Unity Shader入门精要读书笔记》

扫描二维码推送至手机访问。

版权声明:本文由51Blog发布,如需转载请注明出处。

本文链接:https://www.51blog.vip/?id=693

标签: Unity Shader
分享给朋友:

“Unity中的光源类型(向前烘托途径进行光照核算)” 的相关文章

一点点排序

一点点排序

排序 归并排序 归并排序介绍与代码 大体思路:归并排序整体思路是,先把一串待排序数列分为前后两组,把这两组别离排为次序数组,再将两组次序数组合为一整个大的次序数组。 objection1:分组后别离排好序?用选择排序吗?递归的思路是什么? 并非选择排序,而是递归的办法。能够看到,第一次“将一串待排序...

区块链的缺点,区块链技术的缺点解析

区块链技术作为一种分布式账本技术,虽然具有许多优点,如去中心化、安全性高、透明性等,但也存在一些缺点,主要包括以下几点:1. 能耗问题:区块链的共识机制(如工作量证明)需要大量的计算资源,导致能源消耗巨大。例如,比特币挖矿所需的电力消耗已经引起了广泛关注。2. 扩容性问题:随着区块链上交易量的增加,...

成都区块链公司,引领区块链安全生态建设,护航全球数字经济

成都区块链公司,引领区块链安全生态建设,护航全球数字经济

1. 成都链安 成都链安科技有限公司专注于虚拟资产追踪溯源和调查取证服务,提供链上线索分析、资金扩线、混币追踪等一站式技术支持服务。公司参与了多项区块链安全标准的制定,并获得了多轮投资。2. 成都交子区块链产业创新中心有限公司 这家公司成立于2020年,位于中国(四川)自由贸易试验区成都...

云计算的基本特征,云计算的基本概念

云计算的基本特征,云计算的基本概念

云计算是一种基于互联网的计算方式,通过这种方式,共享的软硬件资源和信息可以按需提供给计算机和其他设备。云计算的基本特征包括:1. 按需自助服务:用户可以根据自己的需求,随时获取计算资源,无需与供应商交互。2. 广泛的网络访问:云计算资源可以通过标准的网络设备访问,如计算机、手机等。3. 资源池化:云...

北京云计算,引领科技浪潮,赋能产业升级

北京云计算,引领科技浪潮,赋能产业升级

北京超级云计算中心是由北京市人民政府主导的国家重要信息化基础平台,成立于2011年,现坐落于北京市怀柔综合性国家科学中心怀柔科学城。该中心由北京市人民政府和中科院计算机网络信息中心共同建设,旨在为科学计算、工业仿真、气象海洋、新能源、生物医药、人工智能等重点行业提供高效、精准的云计算服务。北京超级云...

云计算机教室,教育信息化发展的新趋势

云计算机教室是一种利用云计算技术来实现教学和管理的新型教育模式。以下是关于云计算机教室的一些主要功能和应用: 功能特性1. 桌面虚拟化: 云计算机教室采用桌面虚拟化技术(如IDV...