文章目录
- 前言
- 一、把 Unity 中用到的 GI 的函数移植到我们自定义的 cginc 文件中
- 二、开始使用和 GI 相关的方法
- 1、了解 UnityGI 结构体的内容,并且准备 UnityGI 的数据
- 2、了解 SurfaceOutput 结构体,并且准备数据
- 3、了解并准备 UnityGIInput 结构体,并且准备其相关数据
- 这是目前准备完 GI 数据的代码
前言
Unity中Shader的GI相关数据的准备,这是基于上一篇文章中的自定义 cginc 文件的基础上续写的,主要是要把在 GI 中用到的 cginc 库,整合到自己的 cginc 文件中。
- Unity中Shader自定义cginc文件
一、把 Unity 中用到的 GI 的函数移植到我们自定义的 cginc 文件中
我们复制过来后,可以发现缺少一些相关的函数 和 类型,我们需要依次找到后,复制在该函数上方,因为 CG 不像C#一样可以读取到后面定义的函数
下面是依次解决完没有引入方法、结构体后的 代码:(在方法后加1,是为了和Unity自带方法区别开)
#ifndef MYGLOBALILLUMINATION_INCLUDE
#define MYGLOBALILLUMINATION_INCLUDE
inline void ResetUnityLight1(out UnityLight outLight)
{
outLight.color = half3(0, 0, 0);
outLight.dir = half3(0, 1, 0); // Irrelevant direction, just not null
outLight.ndotl = 0; // Not used
}
inline void ResetUnityGI1(out UnityGI outGI)
{
ResetUnityLight1(outGI.light);
outGI.indirect.diffuse = 0;
outGI.indirect.specular = 0;
}
inline UnityGI UnityGI_Base1(UnityGIInput data, half occlusion, half3 normalWorld)
{
UnityGI o_gi;
ResetUnityGI1(o_gi);
// Base pass with Lightmap support is responsible for handling ShadowMask / blending here for performance reason
#if defined(HANDLE_SHADOWS_BLENDING_IN_GI)
half bakedAtten = UnitySampleBakedOcclusion(data.lightmapUV.xy, data.worldPos);
float zDist = dot(_WorldSpaceCameraPos - data.worldPos, UNITY_MATRIX_V[2].xyz);
float fadeDist = UnityComputeShadowFadeDistance(data.worldPos, zDist);
data.atten = UnityMixRealtimeAndBakedShadows(data.atten, bakedAtten, UnityComputeShadowFade(fadeDist));
#endif
o_gi.light = data.light;
o_gi.light.color *= data.atten;
#if UNITY_SHOULD_SAMPLE_SH
o_gi.indirect.diffuse = ShadeSHPerPixel(normalWorld, data.ambient, data.worldPos);
#endif
#if defined(LIGHTMAP_ON)
// Baked lightmaps
half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
half3 bakedColor = DecodeLightmap(bakedColorTex);
#ifdef DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
o_gi.indirect.diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(o_gi.light);
o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap (o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);
#endif
#else // not directional lightmap
o_gi.indirect.diffuse += bakedColor;
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(o_gi.light);
o_gi.indirect.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap(o_gi.indirect.diffuse, data.atten, bakedColorTex, normalWorld);
#endif
#endif
#endif
#ifdef DYNAMICLIGHTMAP_ON
// Dynamic lightmaps
fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);
half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);
#ifdef DIRLIGHTMAP_COMBINED
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
o_gi.indirect.diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);
#else
o_gi.indirect.diffuse += realtimeColor;
#endif
#endif
o_gi.indirect.diffuse *= occlusion;
return o_gi;
}
inline UnityGI UnityGlobalIllumination1 (UnityGIInput data, half occlusion, half3 normalWorld)
{
return UnityGI_Base1(data, occlusion, normalWorld);
}
inline void LightingLambert_GI1 (SurfaceOutput s,UnityGIInput data,inout UnityGI gi)
{
gi = UnityGlobalIllumination1 (data, 1.0, s.Normal);
}
#endif
二、开始使用和 GI 相关的方法
1、了解 UnityGI 结构体的内容,并且准备 UnityGI 的数据
因为 GI = 直接光照 + 间接光照,所以UnityGI中的内容是存储一些相关的信息
准备 UnityGI 的数据
//3、准备 UnityGI 的数据
UnityGI gi;
//直接光照数据(主平行光)
gi.light.color = _LightColor0;
gi.light.dir = _WorldSpaceLightPos0;
//间接光照数据(目前先给0)
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
2、了解 SurfaceOutput 结构体,并且准备数据
该结构体主要存储 和物体表面相关的主要信息
准备 SurfaceOutput 数据
//1、准备 SurfaceOutput 的数据
SurfaceOutput o;
//目前先初始化为0,使用Unity自带的方法,把结构体中的内容初始化为0
UNITY_INITIALIZE_OUTPUT(SurfaceOutput,o)
3、了解并准备 UnityGIInput 结构体,并且准备其相关数据
主要是用来计算 GI 的相关数据
准备UnityGIInput数据
//2、准备 UnityGIInput 的数据
UnityGIInput giInput;
//初始化
UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput);
//修改用到的数据
giInput.light.color = _LightColor0;
giInput.light.dir = _WorldSpaceLightPos0;
giInput.worldPos = i.worldPos;
giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
giInput.atten = 1;
giInput.ambient = 0;
//giInput.lightmapUV = ?
这是目前准备完 GI 数据的代码
//在这里里面使用 自定义的 cginc 来实现全局GI
Shader "MyShader/P1_8_2"
{
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#include "CGIncludes/MyGlobalIllumination.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 worldPos : TEXCOORD0;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//1、准备 SurfaceOutput 的数据
SurfaceOutput o;
//目前先初始化为0,使用Unity自带的方法,把结构体中的内容初始化为0
UNITY_INITIALIZE_OUTPUT(SurfaceOutput,o)
//2、准备 UnityGIInput 的数据
UnityGIInput giInput;
//初始化
UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput);
//修改用到的数据
giInput.light.color = _LightColor0;
giInput.light.dir = _WorldSpaceLightPos0;
giInput.worldPos = i.worldPos;
giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
giInput.atten = 1;
giInput.ambient = 0;
//giInput.lightmapUV = ?
//3、准备 UnityGI 的数据
UnityGI gi;
//直接光照数据(主平行光)
gi.light.color = _LightColor0;
gi.light.dir = _WorldSpaceLightPos0;
//间接光照数据(目前先给0)
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
LightingLambert_GI1(o,giInput,gi);
return 1;
}
ENDCG
}
}
}