在shader调用unity内置lightmap和Light Probes

在编写unity shader的时候,有时候会有需求,希望写的shader能支持unity内置lightmap或者light probe (灯光探测器)。如果是用surface 编写的话,这些自然不用考虑,unity会自动编译支持,但如果是用vert&frag编写shader,这些需要自己添加相关代码调用了 。

unity内置lightmap的调用

为了使unity内置数据和各种宏定义(如本文的LIGHTMAP_OFF)起作用,需要添加#pragma指令:

pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON

在unity5.0之前的版本需要声明一下两个内置参数,unity5.0的话就不需要这两句了:

half4 unity_LightmapST;
sampler2D unity_Lightmap;

Lightmap是使用模型的uv2 ,因此接下来在顶点输入结构体里声明uv2:

float2 texcoord1 : TEXCOORD1;

在另一个顶点结构里面定义用来接收uv2的uv值:

ifndef LIGHTMAP_OFF

half2 uvLM : TEXCOORD4;

endif

在vert函数里面给uvLM赋值:

ifndef LIGHTMAP_OFF

o.uvLM = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;

endif

然后frag函数里对lightmap贴图采样并叠加给主颜色:

ifndef LIGHTMAP_OFF

fixed3 lm = DecodeLightmap (UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
col.rgb*=lm;

endif

在上面的代码中使用了DecodeLightmap解码unity的内置光照贴图,这是因为 Unity烘焙的LightMap是32bit的HDR图,在桌面端,光照贴图的编码为RGBM,而在移动端,大部分情况下,光照贴图的编码为double-LDR,因此需要针对不同平台提供不同的编码方式。DecodeLightmap作用就在这里,它可以针对不同的平台对光照贴图进行解码

VF版本代码01:

Shader “PengLu/Unlit/TextureLM” {
Properties {
_MainTex (“Base (RGB)”, 2D) = “white” {}
}

SubShader {
Tags { “RenderType”=”Opaque” }
LOD 100

Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#include “UnityCG.cginc”

    struct appdata_t {
        float4 vertex : POSITION;
        float2 texcoord : TEXCOORD0;
        float2 texcoord1 : TEXCOORD1;
    };

    struct v2f {
        float4 vertex : SV_POSITION;
        half2 texcoord : TEXCOORD0;
        #ifndef LIGHTMAP_OFF
        half2 uvLM : TEXCOORD1;
        #endif 
        UNITY_FOG_COORDS(1)
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;

    v2f vert (appdata_t v)
    {
        v2f o;
        o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
        o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
        #ifndef LIGHTMAP_OFF
        o.uvLM = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        #endif
        UNITY_TRANSFER_FOG(o,o.vertex);
        return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.texcoord);
        UNITY_APPLY_FOG(i.fogCoord, col);
        UNITY_OPAQUE_ALPHA(col.a);
        #ifndef LIGHTMAP_OFF
        fixed3 lm = DecodeLightmap (UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
        col.rgb*=lm;
        #endif
        return col;
    }
ENDCG

}

unity内置Light Probes的调用

在shader中我们是通过unity定义的half3 ShadeSH9(half4 normal)来调用Light Probes的,Light Probes照明使用的是一种叫球谐光照(Sphere Harmonic)的模拟,简称SH,因此在ShadeSH9函数需要一个世界坐标中的Normal来决定物体表面的光照。

首先我们在顶点输出结构定义一个参数SHLighting:

fixed3 SHLighting : COLOR;

然后在顶点函数里为它赋值:

float3 worldNormal = mul((float3x3)_Object2World, v.normal);//获得世界坐标中的normal

o.SHLighting= ShadeSH9(float4(worldNormal,1)) ;

VF版本代码02:

Shader “PengLu/Unlit/TextureLM” {
Properties {
_MainTex (“Base (RGB)”, 2D) = “white” {}
_SHLightingScale(“LightProbe influence scale”,float) = 1
}

SubShader {
Tags { “Queue”=”Geometry”“LightMode”=”ForwardBase”“RenderType”=”Opaque” }
LOD 100

Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog

    #include "UnityCG.cginc"



    struct v2f {
        float4 vertex : SV_POSITION;
        half2 texcoord : TEXCOORD0;
        fixed3  SHLighting : COLOR;
        UNITY_FOG_COORDS(1)
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _SHLightingScale;

    v2f vert (appdata_base v)
    {
        v2f o;
        o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
        o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
        float3 worldNormal = mul((float3x3)_Object2World, v.normal);
        o.SHLighting= ShadeSH9(float4(worldNormal,1)) ;
                        UNITY_TRANSFER_FOG(o,o.vertex);
        return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.texcoord);
        col.rgb*=i.SHLighting;
        UNITY_APPLY_FOG(i.fogCoord, col);
        UNITY_OPAQUE_ALPHA(col.a);

        return col*_SHLightingScale;
    }
ENDCG

}
}

}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,可以通过在Shader中使用Unity提供的内置属性来访问Lightmap。通过使用"_LightMap"和"_ShadowCoord"属性,我们可以将Lightmap数据传递到Shader中,并将其应用于模型表面。 以下是一个简单的例子,演示了如何在Shader中使用Lightmap: ``` Shader "Custom/LightmapShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float3 worldNormal : TEXCOORD1; float3 worldPos : TEXCOORD2; float4 screenPos : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4x4 unity_ObjectToWorld; float4x4 unity_WorldToObject; float4x4 unity_LightmapST; v2f vert (appdata v) { v2f o; o.screenPos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.worldNormal = mul(unity_WorldToObject, float4(v.normal, 0)).xyz; o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag (v2f i) : SV_Target { float3 lightmapCoord = mul(unity_LightmapST, float4(i.worldPos, 1)).xyw; fixed4 lightmapColor = tex2D(_LightMap, lightmapCoord); fixed4 texColor = tex2D(_MainTex, i.uv); fixed4 finalColor = texColor * lightmapColor; return finalColor; } ENDCG } } } ``` 在上面的Shader中,我们使用了"_LightMap"和"_ShadowCoord"属性来访问Lightmap数据,并将其与主纹理(_MainTex)相乘以获得最终的表面颜色。请注意,我们还使用了"unity_LightmapST"矩阵来转换世界坐标系下的顶点位置到Lightmap纹理坐标系下。 要将此Shader应用于模型,只需将其分配给材质即可。在材质上,您可以选择使用"Lightmap"纹理类型,并将Lightmap纹理分配给"_LightMap"属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值