计算多个光源颜色——ShadeVertexLights

当场景中有多个光源的时候,如何计算多个光源叠加之后的颜色呢?
找到unity cginc中的ShadeVertexLights函数,其最终调用的函数为:ShadeVertexLightsFull

// Used in Vertex pass: Calculates diffuse lighting from lightCount lights. Specifying true to spotLight is more expensive
// to calculate but lights are treated as spot lights otherwise they are treated as point lights.
//注意这个计算多个光源颜色的函数只能在pass为Vertex中使用,为啥呢?我们后面会讲到。
float3 ShadeVertexLightsFull (float4 vertex, float3 normal, int lightCount, bool spotLight)
{
    float3 viewpos = UnityObjectToViewPos (vertex);
    float3 viewN = normalize (mul ((float3x3)UNITY_MATRIX_IT_MV, normal));

    float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz; //叠加了一个环境光颜色,这个你可以去除掉,直接写成:
    //float3 lightColor = float3(0,0,0);
    for (int i = 0; i < lightCount; i++) 
    {
        float3 toLight = unity_LightPosition[i].xyz - viewpos.xyz * unity_LightPosition[i].w;
        float lengthSq = dot(toLight, toLight);

        // don't produce NaNs if some vertex position overlaps with the light
        lengthSq = max(lengthSq, 0.000001);

        toLight *= rsqrt(lengthSq);

        float atten = 1.0 / (1.0 + lengthSq * unity_LightAtten[i].z);
        if (spotLight)
        {
            float rho = max (0, dot(toLight, unity_SpotDirection[i].xyz));
            float spotAtt = (rho - unity_LightAtten[i].x) * unity_LightAtten[i].y;
            atten *= saturate(spotAtt);
        }

        float diff = max (0, dot (viewN, toLight)); //计算入射光和顶点法线的点积
        lightColor += unity_LightColor[i].rgb * (diff * atten); //累加多个光源的的颜色
    }
    return lightColor;
}

补1:unity_LightAtten[i] / unity_LightColor[i] 在哪里可以看到其对应的值。答案是打开frame debug看到。
举例,我们的项目如下:
这里写图片描述
这里有一个cube,两个光源(包括红色光源和绿色光源)。其属性配置如下:
redlight:
这里写图片描述

greenlight:
这里写图片描述

camera:
这里写图片描述

然后我们的计算光源颜色的shader如下,我们是把unity中的那个光源函数移动到了自己的shader去之后,内容如下:

Shader "Demo/vertexLMRGBM"
{
    Properties
    {
        _MainTex("MainTexture",2D) = "white"{}
        _Color("Base Color",Color) = (1,1,1,1)
    }

        SubShader
        {
            Pass
            {
                Tags{"LightMode" = "Vertex"}
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"
                #include "Lighting.cginc"

                float4 _Color;

                struct vertOut
                {
                    float4 pos:SV_POSITION;
                    float4 color:COLOR;
                };

                float3 CalculateMultipleLights(float4 vertex, float3 normal, int lightCount, bool spotLight)
                {
                    float3 viewpos = UnityObjectToViewPos(vertex);
                    float3 viewN = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, normal));

                    float3 lightColor = float3(0,0,0); //忽略环境光颜色
                    for (int i = 0; i < lightCount; i++) {
                        float3 toLight = unity_LightPosition[i].xyz - viewpos.xyz * unity_LightPosition[i].w;
                        float lengthSq = dot(toLight, toLight);

                        // don't produce NaNs if some vertex position overlaps with the light
                        lengthSq = max(lengthSq, 0.000001);

                        toLight *= rsqrt(lengthSq);

                        float atten = 1.0 / (1.0 + lengthSq * unity_LightAtten[i].z);
                        if (spotLight)
                        {
                            float rho = max(0, dot(toLight, unity_SpotDirection[i].xyz));
                            float spotAtt = (rho - unity_LightAtten[i].x) * unity_LightAtten[i].y;
                            atten *= saturate(spotAtt);
                        }

                        float diff = max(0, dot(viewN, toLight));
                        lightColor += unity_LightColor[i].rgb * (diff * atten);
                    }
                    return lightColor;
                }

                vertOut vert(appdata_base v)
                {
                    float3 c = CalculateMultipleLights(v.vertex, v.normal, 2, false);
                    vertOut o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.color = _Color*float4(c,1);
                    return o;
                }

                float4 frag(vertOut i) :COLOR
                {
                    return i.color;
                }
                ENDCG
            }
        }
}

看到的效果为:
这里写图片描述

CalculateMultipleLights函数要写在调用之前声明,符合C规范。下面看看,其补1中的各个变量的值如何查看,打开framedebug:
这里写图片描述

这里找到画cube的那个batch,看到unity_LightColor0/unity_LightPosition0/unity_LightAtten0等多个变量都是可以查看到的。我们打开unity_LightColor0,可以看到:
这里写图片描述
[0] = (2,0,0,1),为redlight的Intensity*Color
[1] = (0,1,0,1),为greenlight的Intensity*Color
这样,你就可以很方便的知道各个灯对应的索引在哪里了,结束。

补2:上面提到这个计算多个光源颜色的函数只能用在pass为vertex中,为啥呢?我们不妨把上面的shader的改为:
Tags{“LightMode” = “ForwardBase”}。
此时我们看到的效果为:
这里写图片描述
为灰色,这个值哪里来的呢?我们不妨看下framedebug,如下:
这里写图片描述
可以看到除了[0]=(0.67,0.67,0.67,1)其余都为0,而这个值,正式我们立方体最终的颜色。因为我们在:
float3 c = CalculateMultipleLights(v.vertex, v.normal, 2, false);
中计算了两个光源的颜色,其中只有一个为灰色。所以这个函数只有在pass为vertex的时候,才能给出正确的灯光颜色数组。unity_LightColor0[8]才有意义。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值