untiy 3d ShaderLab_第8章_ 基于光照贴图的烘焙照明
2016-10-07 10:38
253 查看
转载出处:http://blog.csdn.net/heyuchang666/article/details/51366116
第8章 基于光照贴图的烘焙照明
Lightmap即光照贴图,是游戏中应用很广泛的、便宜而且很出效果的一种模拟光照的方法。这种光照贴图需要提前渲染,因此可以应用在静态效果图中,是应用很广泛的全局照明技术。但是,这种方法一般只适用于静态物体。当然,Unity做了很多工作,可以让我们混合使用静态的光照贴图和动态的实时光源,无缝地照亮场景中静态或动态的物体。
光照贴图不只可以在Unity中被创建,事实上,我们可以使用任何可渲染软件来创建,但这里只提及使用已经整合到Unity中的Beast。
8.1单光照贴图和VertexLit渲染路径
有人会好奇,为什么叫单光照贴图(Single Lightmaps)呢?很简单,那肯定是因为还有双光照贴图(Dual Lighmaps)。双光照贴图是一种更复杂,也是一种效果更容易和动态光源物体整合的技术。下面先来了解简单的单光照贴图。
8.1.1测试烘焙的场景
首先打开Lab_1下的场景,如下图所示的是场景在烘焙(Bake)之前的样子,场景中的物体都是静态的(只有静态的物体才会被Unity输出到Beast中进行烘焙。这里也放了几个非静态的物体进行对比,其中有一个非静态的自发光物体。
8.1.2烘焙的前提:静态物体
现在可以打开Windows菜单F的Lightmapping子菜单,打开控制而板。我们可以勾选Show Resolution选项,同时在场景的物体上看到灰自棋盘格,只有被烘焙的静态物体上才会有,非静态物体不会显示。我们可以在Lightmapping面板的Bake子菜单下改变此分辨率。分辨率越大,最终的光照贴图越精细,但是相应的烘焙时间和最终的贴图大小都会增加。
现在可以单击Bake。按钮,Unity会将烘焙数据传递给Beast,经过一段时间后,Beast就会将烘焙结果输出给Unity,你可以同时在Game
View和Editor View看到此结果,场景中有了非实时GI照明以及通常不会出现在VertexLit模式下的阴影。
8.1.3如何在烘焙中使用自发光材质
首先我们注意一下光源,红色的自发光物体因为不是静态的,所以未被烘焙,其自发光未被Unity传递给Beast,而绿色的自定义的自发光物体则被Unity正确地传递给了Beast。其中EmissionLM.shader的代码如下:
[csharp] view
plain copy
Shader "Self-Illumin/Lighting/LightMapping/Lab_1/EmissionLM" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Color ("Illumi Color", Color) = (1,1,1,1)
_EmissionLM ("Emission (Lightmapper)", Float) = 1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
pass{
Tags{ "LightMode"="Vertex"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
uniform float4 _Color;
float4 _Illumi;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color+_Color;
}
ENDCG
}//end pass
}
}
这个自发光Shader有一个_EmissionLM属性,这是必需的,Unity会把_MainTex和_Illum贴图以及_Color相乘,然后在乘以_EmissionLM,把结果作为发光值传递给Beast。除此之外还需要待别注意,自发光Shader的名字必须以Self-Illum开头,就如本Shader所示。
8.1.4烘焙之后静态物体和非静态物体的实时照明
下面看黄色光源,其Lightmapping Mode被设置为RealTime Only,所以其未被烘焙。当烘焙结束之后,不论是黄色光源还是其他光源,不再影响被烘焙过的静态物体,但是非静态物体继续受灯光的光照影响。我们可以通过GUI控制移动光源1(白色光源)和光源2(绿色光源)的位置,改变光源1的颜色观察这一现象。移动绿色光源后的效果,注意它只影响了非静态的球体。
烘培后:
8.1.5应用光照贴图到VertexLit渲染路径下的材质中
最后需要注意观察的是自定义的两个材质。首先是myVertexLit.shader,其代码如下:
[csharp] view
plain copy
Shader "Tut/Lighting/LightMapping/Lab_1/myVertexLit" {
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"
uniform float4 _Color;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
}
}
这只有一个LightMode = Vertex的Pass的Shader,我们发现应用了该材质的静态Sphere影响了烘焙的结果,比较明显的是其投递的阴影。如果你眼力够好,还会发现它也影响了GI,当然,重要的是当烘焙结束之后,它就消失了,任何光源都无法使其现形。与其相对照的是应用了
VertexLMRGBM.shader的球体,其代码如下:
[csharp] view
plain copy
// Upgrade NOTE: commented out 'float4 unity_LightmapST', a built-in variable
// Upgrade NOTE: commented out 'sampler2D unity_Lightmap', a built-in variable
// Upgrade NOTE: replaced tex2D unity_Lightmap with UNITY_SAMPLE_TEX2D
Shader "Tut/Lighting/LightMapping/Lab_1/VertexLMRGBM" {
Properties {
_MainTex ("Base (RGB)", 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"
uniform float4 _Color;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
Pass {
Tags{"LightMode"="VertexLMRGBM"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
// sampler2D unity_Lightmap;
// float4 unity_LightmapST;
struct appdata {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float2 texcoord1: TEXCOORD1;
};
struct v2f {
float4 pos : SV_POSITION;
float2 txuv : TEXCOORD0;
float2 lmuv : TEXCOORD1;
};
v2f vert (appdata v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
o.lmuv = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
return o;
}
half4 frag( v2f i ) : COLOR {
half4 col = tex2D(_MainTex, i.txuv.xy);
half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv.xy);
col.rgb = col.rgb * DecodeLightmap(lm);
return col;
}
ENDCG
}
}
}
和刚刚的Shader不同的是,此Shader多了一个LightMode为VertexLMRGBM的Pass,在这个Pass中,我们读取了Beast的烘焙结果unity_Lightmap,然后将其输出。这样,我们就看到应用了刚刚烘焙结果的球体,就和场景中其他使用了默认材质的物体一样。
LightMode为VertexLMRGBM只适用于发布为桌面应用的情况,此时灯光贴图的编码为RGBM。如果是移动终端,大部分情况下,光照贴图的编码为double-LDR,此时应该提供一个LightMode为VertexLM的Pass来读取unity_Lightmap。
8.1.6通过自己的材质改变实时光源对烘焙后物体的照明
在Single Lightmap模式下,默认的Vertex Shader中,如果静态物体已经被光照贴图所照亮,是不会再受到实时光源影响的,不过我们可动手写个Shader来改变这一默认行为,就如下面这个VertexLMRGBM.shader一样:
[csharp] view
plain copy
Shader "Tut/Lighting/LightMapping/Lab_1/VertexLMRGBM_1" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Color ("Base Color", Color) =(1,1,1,1)
}
SubShader {
Pass {
Tags{"LightMode"="VertexLMRGBM"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
// sampler2D unity_Lightmap;
// float4 unity_LightmapST;
struct v2f {
float4 pos : SV_POSITION;
float2 txuv : TEXCOORD0;
float2 lmuv : TEXCOORD1;
float4 color:COLOR;
};
v2f vert (appdata_full v) {
float3 c=ShadeVertexLights(v.vertex,v.normal);
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
o.lmuv = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
o.color=_Color*float4(c,1);
return o;
}
half4 frag( v2f i ) : COLOR {
half4 col = tex2D(_MainTex, i.txuv.xy);
half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv.xy);
col.rgb = col.rgb * DecodeLightmap(lm);
return col+i.color;
}
ENDCG
}
}
}
第8章 基于光照贴图的烘焙照明
Lightmap即光照贴图,是游戏中应用很广泛的、便宜而且很出效果的一种模拟光照的方法。这种光照贴图需要提前渲染,因此可以应用在静态效果图中,是应用很广泛的全局照明技术。但是,这种方法一般只适用于静态物体。当然,Unity做了很多工作,可以让我们混合使用静态的光照贴图和动态的实时光源,无缝地照亮场景中静态或动态的物体。
光照贴图不只可以在Unity中被创建,事实上,我们可以使用任何可渲染软件来创建,但这里只提及使用已经整合到Unity中的Beast。
8.1单光照贴图和VertexLit渲染路径
有人会好奇,为什么叫单光照贴图(Single Lightmaps)呢?很简单,那肯定是因为还有双光照贴图(Dual Lighmaps)。双光照贴图是一种更复杂,也是一种效果更容易和动态光源物体整合的技术。下面先来了解简单的单光照贴图。
8.1.1测试烘焙的场景
首先打开Lab_1下的场景,如下图所示的是场景在烘焙(Bake)之前的样子,场景中的物体都是静态的(只有静态的物体才会被Unity输出到Beast中进行烘焙。这里也放了几个非静态的物体进行对比,其中有一个非静态的自发光物体。
8.1.2烘焙的前提:静态物体
现在可以打开Windows菜单F的Lightmapping子菜单,打开控制而板。我们可以勾选Show Resolution选项,同时在场景的物体上看到灰自棋盘格,只有被烘焙的静态物体上才会有,非静态物体不会显示。我们可以在Lightmapping面板的Bake子菜单下改变此分辨率。分辨率越大,最终的光照贴图越精细,但是相应的烘焙时间和最终的贴图大小都会增加。
现在可以单击Bake。按钮,Unity会将烘焙数据传递给Beast,经过一段时间后,Beast就会将烘焙结果输出给Unity,你可以同时在Game
View和Editor View看到此结果,场景中有了非实时GI照明以及通常不会出现在VertexLit模式下的阴影。
8.1.3如何在烘焙中使用自发光材质
首先我们注意一下光源,红色的自发光物体因为不是静态的,所以未被烘焙,其自发光未被Unity传递给Beast,而绿色的自定义的自发光物体则被Unity正确地传递给了Beast。其中EmissionLM.shader的代码如下:
[csharp] view
plain copy
Shader "Self-Illumin/Lighting/LightMapping/Lab_1/EmissionLM" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Color ("Illumi Color", Color) = (1,1,1,1)
_EmissionLM ("Emission (Lightmapper)", Float) = 1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
pass{
Tags{ "LightMode"="Vertex"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
uniform float4 _Color;
float4 _Illumi;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color+_Color;
}
ENDCG
}//end pass
}
}
这个自发光Shader有一个_EmissionLM属性,这是必需的,Unity会把_MainTex和_Illum贴图以及_Color相乘,然后在乘以_EmissionLM,把结果作为发光值传递给Beast。除此之外还需要待别注意,自发光Shader的名字必须以Self-Illum开头,就如本Shader所示。
8.1.4烘焙之后静态物体和非静态物体的实时照明
下面看黄色光源,其Lightmapping Mode被设置为RealTime Only,所以其未被烘焙。当烘焙结束之后,不论是黄色光源还是其他光源,不再影响被烘焙过的静态物体,但是非静态物体继续受灯光的光照影响。我们可以通过GUI控制移动光源1(白色光源)和光源2(绿色光源)的位置,改变光源1的颜色观察这一现象。移动绿色光源后的效果,注意它只影响了非静态的球体。
烘培后:
8.1.5应用光照贴图到VertexLit渲染路径下的材质中
最后需要注意观察的是自定义的两个材质。首先是myVertexLit.shader,其代码如下:
[csharp] view
plain copy
Shader "Tut/Lighting/LightMapping/Lab_1/myVertexLit" {
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"
uniform float4 _Color;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
}
}
这只有一个LightMode = Vertex的Pass的Shader,我们发现应用了该材质的静态Sphere影响了烘焙的结果,比较明显的是其投递的阴影。如果你眼力够好,还会发现它也影响了GI,当然,重要的是当烘焙结束之后,它就消失了,任何光源都无法使其现形。与其相对照的是应用了
VertexLMRGBM.shader的球体,其代码如下:
[csharp] view
plain copy
// Upgrade NOTE: commented out 'float4 unity_LightmapST', a built-in variable
// Upgrade NOTE: commented out 'sampler2D unity_Lightmap', a built-in variable
// Upgrade NOTE: replaced tex2D unity_Lightmap with UNITY_SAMPLE_TEX2D
Shader "Tut/Lighting/LightMapping/Lab_1/VertexLMRGBM" {
Properties {
_MainTex ("Base (RGB)", 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"
uniform float4 _Color;
struct vertOut{
float4 pos:SV_POSITION;
float4 color:COLOR;
};
vertOut vert(appdata_base v)
{
float3 c=ShadeVertexLights(v.vertex,v.normal);
vertOut o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.color=_Color*float4(c,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
Pass {
Tags{"LightMode"="VertexLMRGBM"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
// sampler2D unity_Lightmap;
// float4 unity_LightmapST;
struct appdata {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float2 texcoord1: TEXCOORD1;
};
struct v2f {
float4 pos : SV_POSITION;
float2 txuv : TEXCOORD0;
float2 lmuv : TEXCOORD1;
};
v2f vert (appdata v) {
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
o.lmuv = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
return o;
}
half4 frag( v2f i ) : COLOR {
half4 col = tex2D(_MainTex, i.txuv.xy);
half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv.xy);
col.rgb = col.rgb * DecodeLightmap(lm);
return col;
}
ENDCG
}
}
}
和刚刚的Shader不同的是,此Shader多了一个LightMode为VertexLMRGBM的Pass,在这个Pass中,我们读取了Beast的烘焙结果unity_Lightmap,然后将其输出。这样,我们就看到应用了刚刚烘焙结果的球体,就和场景中其他使用了默认材质的物体一样。
LightMode为VertexLMRGBM只适用于发布为桌面应用的情况,此时灯光贴图的编码为RGBM。如果是移动终端,大部分情况下,光照贴图的编码为double-LDR,此时应该提供一个LightMode为VertexLM的Pass来读取unity_Lightmap。
8.1.6通过自己的材质改变实时光源对烘焙后物体的照明
在Single Lightmap模式下,默认的Vertex Shader中,如果静态物体已经被光照贴图所照亮,是不会再受到实时光源影响的,不过我们可动手写个Shader来改变这一默认行为,就如下面这个VertexLMRGBM.shader一样:
[csharp] view
plain copy
Shader "Tut/Lighting/LightMapping/Lab_1/VertexLMRGBM_1" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Color ("Base Color", Color) =(1,1,1,1)
}
SubShader {
Pass {
Tags{"LightMode"="VertexLMRGBM"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
// sampler2D unity_Lightmap;
// float4 unity_LightmapST;
struct v2f {
float4 pos : SV_POSITION;
float2 txuv : TEXCOORD0;
float2 lmuv : TEXCOORD1;
float4 color:COLOR;
};
v2f vert (appdata_full v) {
float3 c=ShadeVertexLights(v.vertex,v.normal);
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
o.lmuv = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
o.color=_Color*float4(c,1);
return o;
}
half4 frag( v2f i ) : COLOR {
half4 col = tex2D(_MainTex, i.txuv.xy);
half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv.xy);
col.rgb = col.rgb * DecodeLightmap(lm);
return col+i.color;
}
ENDCG
}
}
}
相关文章推荐
- untiy 3d ShaderLab_第8章_ 基于光照贴图的烘焙照明
- untiy 3d ShaderLab_第8章_4_ 单光照贴图在Deferred 渲染路径下的实时阴影
- untiy 3d ShaderLab_第8章_3_ 单光贴图和Forward 渲染路径
- untiy 3d ShaderLab_第4章_基本的光照模型
- untiy 3d ShaderLab_第8章_2_在效果和性能间进行权衡
- untiy 3d ShaderLab_第9章_2_球体阴影(二) 阴影的淡入/淡出
- Unity3D ShaderLab 静态贴图光照模型
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_2_顶点照明和Unity存放光源的第一种方式
- untiy 3d ShaderLab_第7章_ Forward渲染路径_1_ForwardBase和ForwardAdd
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_4_顶点照明和Unity存放光源的第三种方式
- 基于 HTML5 Canvas 的 3D 模型列表贴图
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_1_Unity通过ShaderLab 来组织Shader
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_2_Unity中Shader的3种形态
- untiy 3d ShaderLab_第3章_Shader(着色器)中用到的各种空间概念
- untiy 3d ShaderLab_第6章_VertexLit渲染路径_3_顶点照明和Unity存放光源的第二种方式
- untiy 3d ShaderLab_第9章_1_平面阴影(二) 点光源对平面的投影
- untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_3_Shader的数据接口:属性和 uniform变量
- untiy 3d ShaderLab_第9章_2_球体阴影(一) 平行光对球体的投影
- untiy 3d ShaderLab_第7章_ Forward渲染路径_4_Forward渲染路径总结
- ShaderLab学习小结(十)简单的支持光照贴图的shader