Unity中的混合光照

  • Baked Indirect
  • Shadowmask
  • Distance Shadowmask
  • Subtractive
  • Reference

Unity支持三种混合光照模式,分别是Baked Indirect,Subtractive,Shadowmask。Shadowmask模式又分为两种,Shadowmask和Distance Shadowmask。这次我们来研究一下这三种光照模式,对光照,静态/动态物体,阴影,以及前向/延迟渲染的影响。首先三种模式的设置放在Window/Rendering/Lighting Settings下:

Shadowmask模式的设置现在放到了Edit/Project Settings下,位于Quality选项:

其次,要开启混合光照,需要将光源的模式设置为mixed:

下面让我们对这几个光照模式逐一进行分析。

Baked Indirect

如图所示的场景,我们只启用一个平行光源并设置为mixed,将光照模式调置baked indirect:

该模式只会将光源间接光照的部分烘焙到lightmap和light probe中,实时光照则不受影响。由于它只烘焙间接光照,因此lightmap看起来会比较暗:

lightmap用于为标记为静态static的物体添加间接光照的信息,动态dynamic的物体是使用light probe来获取间接光照。baked indirect模式天然对多个光源支持友好,例如我们再开启一个平行光源:

此时看一下烘焙的lightmap,对比发现变亮了一些,这是因为多了一个光源的间接光照:

baked indirect模式下前向渲染的流程与实时光照基本相同,由一个base pass加上多个光源的add pass组成:


由于lightmap中已经包含所有光源的间接光照,因此只要在forward base pass中对lightmap采样一次即可,避免forward add pass多次采样。延迟渲染的流程也基本不变,几个光源就有几个light pass:

不过这里注意到light pass中并没有开启LIGHTMAP_ON宏。LIGHTMAP_ON宏是在geometry pass中生效的:

这就意味着我们需要在geometry pass中对lightmap进行采样,将间接光照的信息写入G-Buffer。最后来看下阴影,baked indirect模式下前向渲染的阴影都是实时渲染的,和实时光源的流程基本一致:

场景中有两个平行光源,因此会做两次阴影收集。但是注意在base pass中渲染阴影时,要避免使用unity内置的UNITY_LIGHT_ATTENUATION宏,此时shadow fade会失效:


两张截图都是shadow distance设置为10的效果。第一张截图是自定义材质,第二张截图是使用standard shader的默认材质,对比可以发现第二张截图shadow fade的效果更明显。那么为什么此时shadow fade会失效呢?

首先我们打开frame debug,观察到base pass下渲染静态物体时定义了LIGHTMAP_ONSHADOWS_SCREEN这两个宏:

在这种情况下,unity在UnityShadowLibrary.cginc中还会定义另外一个宏:

#if defined( SHADOWS_SCREEN ) && defined( LIGHTMAP_ON )#define HANDLE_SHADOWS_BLENDING_IN_GI 1
#endif

而如果定义了这个宏,unity对shadow的采样函数就会发生变化:

#if defined(HANDLE_SHADOWS_BLENDING_IN_GI) // handles shadows in the depths of the GI function for performance reasons
#   define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1)
#   define UNITY_TRANSFER_SHADOW(a, coord) TRANSFER_SHADOW(a)
#   define UNITY_SHADOW_ATTENUATION(a, worldPos) SHADOW_ATTENUATION(a)
#else...
#endif

在没有定义HANDLE_SHADOWS_BLENDING_IN_GI这个宏的情况下,UNITY_SHADOW_ATTENUATION宏都会走到UnityComputeForwardShadows这个函数中:

// -----------------------------
//  Shadow helpers (5.6+ version)
// -----------------------------
// This version depends on having worldPos available in the fragment shader and using that to compute light coordinates.
// if also supports ShadowMask (separately baked shadows for lightmapped objects)half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos)
{//fade valuefloat zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist);half  realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist);...
}

可以看到此时调用了unity内置的计算shadow fade的函数。而SHADOW_ATTENUATION这个宏并不会:

#if defined (SHADOWS_SCREEN)#define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
#endif#if defined (SHADOWS_DEPTH) && defined (SPOT)#define SHADOW_ATTENUATION(a) UnitySampleShadowmap(a._ShadowCoord)
#endif#if defined (SHADOWS_CUBE)#define SHADOW_ATTENUATION(a) UnitySampleShadowmap(a._ShadowCoord)
#endif#if !defined (SHADOWS_SCREEN) && !defined (SHADOWS_DEPTH) && !defined (SHADOWS_CUBE)#define SHADOW_ATTENUATION(a) 1.0
#endif

unitySampleShadowUnitySampleShadowmap这两个接口只会对shadowmap进行采样,返回平滑过的采样结果,并不会考虑shadow fade的情况,因此我们需要在定义HANDLE_SHADOWS_BLENDING_IN_GI这个宏的条件下,在调用完UNITY_SHADOW_ATTENUATION之后手动补上shadow fade的处理,处理方式可以参考UnityComputeForwardShadows这个函数。处理之后效果如下:

可以看出此时已经有了shadow fade的效果。另外值得一提的是,设置shadow distance,会在渲染shadowmap时对超出distance范围的物体进行剔除,使得最后渲染出的shadow map本身就不包含超出shadow distance物体的投射阴影信息:

在shadow distance设置为10时,RenderShadowMap只用了17个pass,而设置为200时,需要41个pass:

那么,如果是延迟渲染路径的话,shadow fade会失效吗?答案是不会的。因为在延迟渲染中,采样lightmap的时机和绘制阴影的时机是分开的,一个在geometry pass,一个在light pass:


Shadowmask

baked indirect模式开销比较昂贵,它实际上是直接光使用实时光照,间接光使用lightmap,所有的阴影也都是实时渲染的。shadowmask模式除了烘焙间接光之外,还会烘焙阴影。阴影不存储在lightmap中,而是存储在另外一张名为shadowmask的map中:


可以发现,shadowmask看上去是红色的,这是因为Unity将烘焙的阴影信息保存在不同的通道上。这里我们只用了一个平行光源,因此信息保存到了R通道上。如果我们使用两个平行光源,此时shadowmask如图所示:

shadowmask模式只烘焙静态物体所投射的阴影,动态物体不受影响。我们来看下前向渲染的流程,也是由一个base pass加上其他光源的add pass组成:


另外我们可以发现,RenderShadowMap的pass数量大量减少,shadowmask模式不再为static物体渲染实时阴影了。与baked indirect模式类似地,base pass渲染静态物体会同时定义LIGHTMAP_ONSHADOWS_SCREEN这两个宏,这会使得HANDLE_SHADOWS_BLENDING_IN_GI这个宏生效,因此shadowmask模式下我们也需要处理base pass的shadow fade。

我们可以使用unity内置的APIUnitySampleBakedOcclusion对shadowmask进行采样:

// ------------------------------------------------------------------
// Used by the forward rendering path
fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
{#if defined (SHADOWS_SHADOWMASK)#if defined(LIGHTMAP_ON)fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);#elsefixed4 rawOcclusionMask = fixed4(1.0, 1.0, 1.0, 1.0);#if UNITY_LIGHT_PROBE_PROXY_VOLUME...#elserawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);#endif#endifreturn saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));#else...#endif
}

unity_OcclusionMaskSelector是一个四维的向量,用于根据当前是哪个光源提取shadowmask对应的通道值:


shadowmask模式中物体接收到的阴影,既可能来自于静态物体,也可能来自于动态物体,而静态物体投射的阴影是烘焙在shadowmask和light probe中,动态物体投射的阴影是实时渲染在shadowmap中的,因此shadowmask模式需要对这两种阴影进行混合。Unity提供了内置的API,UnityMixRealtimeAndBakedShadows来做这件事情:

// ------------------------------------------------------------------
// Used by both the forward and the deferred rendering path
half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{// -- Static objects --// FWD BASE PASS// ShadowMask mode          = LIGHTMAP_ON + SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING// Distance shadowmask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK// Subtractive mode         = LIGHTMAP_ON + LIGHTMAP_SHADOW_MIXING// Pure realtime direct lit = LIGHTMAP_ON// FWD ADD PASS// ShadowMask mode          = SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING// Distance shadowmask mode = SHADOWS_SHADOWMASK// Pure realtime direct lit = LIGHTMAP_ON// DEFERRED LIGHTING PASS// ShadowMask mode          = LIGHTMAP_ON + SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING// Distance shadowmask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK// Pure realtime direct lit = LIGHTMAP_ON// -- Dynamic objects --// FWD BASE PASS + FWD ADD ASS// ShadowMask mode          = LIGHTMAP_SHADOW_MIXING// Distance shadowmask mode = N/A// Subtractive mode         = LIGHTMAP_SHADOW_MIXING (only matter for LPPV. Light probes occlusion being done on CPU)// Pure realtime direct lit = N/A// DEFERRED LIGHTING PASS// ShadowMask mode          = SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING// Distance shadowmask mode = SHADOWS_SHADOWMASK// Pure realtime direct lit = N/A#if !defined(SHADOWS_DEPTH) && !defined(SHADOWS_SCREEN) && !defined(SHADOWS_CUBE)#if defined(LIGHTMAP_ON) && defined (LIGHTMAP_SHADOW_MIXING) && !defined (SHADOWS_SHADOWMASK)//In subtractive mode when there is no shadow we kill the light contribution as direct as been baked in the lightmap.return 0.0;#elsereturn bakedShadowAttenuation;#endif#endif#if (SHADER_TARGET <= 20) || UNITY_STANDARD_SIMPLE//no fading nor blending on SM 2.0 because of instruction count limit.#if defined(SHADOWS_SHADOWMASK) || defined(LIGHTMAP_SHADOW_MIXING)return min(realtimeShadowAttenuation, bakedShadowAttenuation);#elsereturn realtimeShadowAttenuation;#endif#endif#if defined(LIGHTMAP_SHADOW_MIXING)//Subtractive or shadowmask moderealtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);#endif//In distance shadowmask or realtime shadow fadeout we lerp toward the baked shadows (bakedShadowAttenuation will be 1 if no baked shadows)return lerp(realtimeShadowAttenuation, bakedShadowAttenuation, fade);
}

函数看起来很复杂,不过这里我们只需要考虑shadowmask模式下前向渲染路径的情况。主要可以细分为以下几种类型:

(1)forward base pass下的静态物体

可以看到此时有LIGHTMAP_ONLIGHTMAP_SHADOW_MIXINGSHADOWS_SCREENSHADOWS_SHADOWMASK这几个宏生效了。LIGHTMAP_ON表明我们需要对lightmap进行采样;SHADOWS_SCREEN表明我们需要用到shadowmap采样实时阴影,这里特指平行光用到的screen space shadowmap;SHADOWS_SHADOWMASK表明我们需要用到shadowmask采样烘焙阴影;由于实时和烘焙的阴影都需要用到,LIGHTMAP_SHADOW_MIXING表明需要对这两种阴影进行混合。综合这些宏再去看上面这个函数,会简化成这样:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{realtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);
}

(2)forward base pass下的动态物体

可以看到此时有LIGHTMAP_SHADOW_MIXINGLIGHTPROBE_SHSHADOWS_SCREEN这几个宏生效。因为是动态物体所以没有用到lightmap和shadowmask采样。LIGHTPROBE_SH表示动态物体接收到了静态物体产生的烘焙阴影,需要通过light probe获得,因此此时LIGHTMAP_SHADOW_MIXING宏也会生效,函数也会走到相同的逻辑上:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{realtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);
}

(3)forward base pass下没有实时阴影的静态物体

有些静态物体不会接收到动态物体产生的阴影,进而也不需要对shadowmap采样:

可以看到此时SHADOWS_SCREEN 宏不生效,那么实际上也不需要进行阴影混合:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{return bakedShadowAttenuation;
}

(4)forward base pass下没有实时阴影的动态物体

与情形(3)类似,此时也不需要对shadowmap采样,阴影全部来自light probe,因而只有LIGHTPROBE_SH宏生效:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{return bakedShadowAttenuation;
}

(5)forward add pass下的静态物体

如前文所述,add pass主要少了对lightmap的采样,add pass不会定义LIGHTMAP_ON宏:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{realtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);
}

(6)forward add pass下的动态物体

add pass也不会对light probe进行处理,因此不会定义LIGHTPROBE_SH宏:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{realtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);
}

(7)forward add pass下没有实时阴影的静态物体

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{return bakedShadowAttenuation;
}

(8)forward add pass下没有实时阴影的动态物体

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{return bakedShadowAttenuation;
}

虽然用到了大量不同的宏,但是总结一下就是如果存在需要混合实时阴影和烘焙阴影的情况,无论静态物体还是动态物体,无论是base pass还是add pass,都会走到取min值的逻辑;如果只有烘焙阴影,则直接返回它的值;如果只有实时阴影,则会走到最后lerp插值的逻辑。

对于延迟渲染路径来说,我们需要在geometry pass阶段,单独采样shadowmask然后保存到新的G-Buffer中:

struct FragmentOutput {#if defined(DEFERRED_PASS)float4 gBuffer0 : SV_Target0;float4 gBuffer1 : SV_Target1;float4 gBuffer2 : SV_Target2;float4 gBuffer3 : SV_Target3;#if defined(SHADOWS_SHADOWMASK)float4 gBuffer4 : SV_Target4;#endif#elsefloat4 color : SV_Target;#endif
};#if defined(DEFERRED_PASS)#if defined(SHADOWS_SHADOWMASK)output.gBuffer4 = UnityGetRawBakedOcclusions(shadowUV, i.worldPos.xyz);#endif
#endif

UnityGetRawBakedOcclusions也是Unity提供的内置API,专门用于延迟渲染路径:

// ------------------------------------------------------------------
// Used by the deferred rendering path (in the gbuffer pass)
fixed4 UnityGetRawBakedOcclusions(float2 lightmapUV, float3 worldPos)
{#if defined (SHADOWS_SHADOWMASK)#if defined(LIGHTMAP_ON)return UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);#elsehalf4 probeOcclusion = unity_ProbesOcclusion;#if UNITY_LIGHT_PROBE_PROXY_VOLUME...#endifreturn probeOcclusion;#endif#elsereturn fixed4(1.0, 1.0, 1.0, 1.0);#endif
}

静态物体就是直接从shadowmask中采样:

动态物体返回unity_ProbesOcclusion这个默认值:

在light pass阶段,需要对刚才保存shadowmask的G-Buffer进行采样,然后进行阴影混合,这与前向渲染路径类似:

half UnityDeferredComputeShadow(float3 vec, float fadeDist, float2 uv)
{half fade                      = UnityComputeShadowFade(fadeDist);half shadowMaskAttenuation     = UnityDeferredSampleShadowMask(uv);half realtimeShadowAttenuation = UnityDeferredSampleRealtimeShadow(fade, vec, uv);return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, fade);
}//Note :
// SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING -> ShadowMask mode
// SHADOWS_SHADOWMASK only -> Distance shadowmask mode// --------------------------------------------------------
half UnityDeferredSampleShadowMask(float2 uv)
{half shadowMaskAttenuation = 1.0f;#if defined (SHADOWS_SHADOWMASK)half4 shadowMask = tex2D(_CameraGBufferTexture4, uv);shadowMaskAttenuation = saturate(dot(shadowMask, unity_OcclusionMaskSelector));#endifreturn shadowMaskAttenuation;
}

unity_OcclusionMaskSelector变量的含义与前向渲染相同,用来筛选当前光源对应的通道。

Distance Shadowmask

在distance shadowmask模式中,静态物体投射的阴影会发生变化。在shadow distance范围内,静态物体投射的阴影也变成了实时阴影,只有shadow distance范围外才使用shadowmask。distance shadowmask模式的设置位于Edit/Project Settings/Quality中:

与shadowmask模式类似,我们依旧可以使用内置APIUnityMixRealtimeAndBakedShadows计算最后的阴影值。由于这里物体接收到的阴影要么全部来自实时阴影,要么全部来自shadowmask/light probe,因此并不存在阴影混合的情况,也即LIGHTMAP_SHADOW_MIXING宏不生效:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{#if !defined(SHADOWS_DEPTH) && !defined(SHADOWS_SCREEN) && !defined(SHADOWS_CUBE)return bakedShadowAttenuation;#endif//In distance shadowmask or realtime shadow fadeout we lerp toward the baked shadows (bakedShadowAttenuation will be 1 if no baked shadows)return lerp(realtimeShadowAttenuation, bakedShadowAttenuation, fade);
}

如果在超出shadow distance范围的情况下,会直接返回bakedShadowAttenuation,否则就是根据shadow fade的值做一个线性插值。

Subtractive

最后来看一下subtractive模式。该模式相对来说最简单,渲染效率也最高,它把直接光照,间接光照,阴影信息都烘焙到了一张lightmap中:

subtractive模式下的前向渲染路径也是由一个forward base pass加上多个光源的add pass组成。此时静态物体投射的阴影全部来自于lightmap,因此没有渲染到shadowmap的过程;并且静态物体的直接光照也被烘焙到了lightmap,所以add pass中也没有渲染静态物体的过程:


此时,动态物体投射的阴影来自实时光源,而这个阴影与lightmap混合,还需要从lightmap中减去光照信息,才能得到相对正确的效果,也就是说实际上subtractive模式只支持一个平行光源的情况。由于阴影一部分来自lightmap,一部分来自shadow map,所以LIGHTMAP_SHADOW_MIXING宏开启。

由于直接光照不用实时计算,所以我们需要将其屏蔽掉:

#if defined(LIGHTMAP_ON) && defined(SHADOWS_SCREEN)#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK)#define SUBTRACTIVE_LIGHTING 1#endif
#endifUnityLight CreateLight (Interpolators i) {UnityLight light;#if SUBTRACTIVE_LIGHTINGlight.dir = float3(0, 1, 0);light.color = 0;#else...#endifreturn light;
}

接下来就是要在间接光照的处理中把光照和阴影分开来。首先还是使用UNITY_LIGHT_ATTENUATION来计算光照的衰减值,采样烘焙阴影的逻辑在UnitySampleBakedOcclusion中,但此时已经没有了shadowmask,只会走到以下的逻辑:

// ------------------------------------------------------------------
// Used by the forward rendering path
fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
{fixed atten = 1.0f;return atten;
}

相应地,用于混合实时阴影和烘焙阴影的函数UnityMixRealtimeAndBakedShadows会简化成这样:

half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
{#if !defined(SHADOWS_DEPTH) && !defined(SHADOWS_SCREEN) && !defined(SHADOWS_CUBE)#if defined(LIGHTMAP_ON) && defined (LIGHTMAP_SHADOW_MIXING) && !defined (SHADOWS_SHADOWMASK)//In subtractive mode when there is no shadow we kill the light contribution as direct as been baked in the lightmap.return 0.0;#endif#endif#if defined(LIGHTMAP_SHADOW_MIXING)//Subtractive or shadowmask moderealtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);return min(realtimeShadowAttenuation, bakedShadowAttenuation);#endif
}

在subtractive模式下,如果没有实时阴影,则直接返回attenuation为0,它表示阴影信息全部来自lightmap;否则,由于这里bakedShadowAttenuation为1,返回的就是实时阴影的衰减值。

前面提到过,subtractive模式下,光照和阴影都烘焙到lightmap中了:

但这里烘焙的只是静态物体投射的阴影,我们需要预估动态物体阴影带来的衰减影响,也就是要把这部分从lightmap采样中减去。由于lightmap烘焙的光照只包含diffuse,因此可以使用lambert diffuse计算公式来预估实时光照:

float ndotl = saturate(dot(i.normal, _WorldSpaceLightPos0.xyz));
float3 shadowedLightEstimate = ndotl * (1 - attenuation) * _LightColor0.rgb;

shadowedLightEstimate表示被实时阴影衰减掉的光照预估,而lightmap中只包含了被烘焙阴影衰减掉的光照,因此需要从中减掉:

float3 subtractedLight = indirectLight.diffuse - shadowedLightEstimate;
indirectLight.diffuse = min(subtractedLight, indirectLight.diffuse);

对比效果如下:

(a)未减去光照预估

(b)减去光照预估

不过,subtactive模式并不支持延迟渲染路径,就算开了延迟渲染,也会走到forward pass上:

最后,一张图来看这几种光照模式对静态/动态物体,和它们投射/接收阴影的影响:

如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路

Reference

[1] Mixed Lighting

[2] 如何理解Unity中的MixedLighting

[3] SHADOWS_SHADOWMASK与LIGHTMAP_SHADOW_MIXING

[4] 浅析Unity中的Enlighten与混合光照

[5] 聊聊LightProbe原理实现以及对LightProbe数据的修改

[6] Unity shader的内置宏与变体(一)

Unity中的混合光照相关推荐

  1. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  2. Unity 中的基础光照

    通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑三种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交:一些光被物体吸收了,而另一些光被散射到其他方向. 最后,摄像 ...

  3. unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.Unity 中的环境光和自发光 二.在Unity Shader 中实现漫反射光照模型 参考 前言 但这种模型有很多局限性.首先,有很 ...

  4. unity入门精要之第6 章 Unity 中的基础光照---实现高光反射光照模型

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 参考 前言 在6.2.4 节中,我们给出了基本光照模型中高光反射部分的计算公式: 从公式可以看出,要计算高光反射需要知道4 个参数:入射 ...

  5. unity入门精要之第6 章 Unity 中的基础光照概述-1

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 6.1 我们是如何看到这个世界的 6.2 标准光照模型 参考 前言 渲染总是围绕着一个基础问题:我们如何决定一个像素的颜色?从宏观上来说 ...

  6. 2d shader unity 阴影_Unity中实现2D光照系统

    在一些 2D 游戏中引入实时光影效果能给游戏带来非常大的视觉效果提升,亦或是利用 2D 光影实现视线遮挡机制.例如 Terraria, Starbound. 2D 光影效果需要一个动态光照系统实现, ...

  7. 浅析Unity中的Enlighten与混合光照

    0x00 前言 在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten[1]来提供实时全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapp ...

  8. 【Unity3D Shader编程】之五 圣诞夜篇 Unity中Shader的三种形态对比 混合操作合辑

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  9. 在Unity中实现基于粒子的水模拟(三:混合屏幕)

    在Unity中实现基于粒子的水模拟(三:混合屏幕) 文章目录 在Unity中实现基于粒子的水模拟(三:混合屏幕) 前言 一.着色算法介绍 1.折射 2.反射 二.准备纹理 1.获取纹理 2.模糊纹理 ...

最新文章

  1. 如何在NLP中有效利用Deep Transformer?
  2. Spring学习笔记(二)——Spring相关配置属性注入Junit整合
  3. layui table 列覆盖
  4. 济南python工资一般多少钱-济南Python+人工智能
  5. element-ui 分页索引问题
  6. python logging 模块之TimedRotatingFileHandler 实现每天一个日志文件
  7. linux各路径(目录)的解释(转载)
  8. Java 纸牌游戏 牛牛 逻辑代码 实现
  9. uniapp打包app教程
  10. 打开图片或者视频显示“文件系统错误-2147416359”
  11. VMware 安装ghost win7 gho
  12. 注册时要求获取手机短信码的实现(java)
  13. 使用mybatis的逆向工程易出现的错误
  14. opencv以图片名称为索引顺序读取多张图片
  15. 通达信公式-接近均线
  16. python爬取qq电话_用Python爬取整个学院MM的电话和QQ,爬虫这也太霸道了!
  17. 3DMax的中文版官方手册
  18. [Asp.Net Core]NET5跨平台的本质
  19. 怎么样使用vbs 恶搞包装让人看不出
  20. Cache replacement policies(缓存替换策略)/ LRU 和 LFU等算法

热门文章

  1. hadoop tyarn冲突_hadoop集群启动yarn时出现的问题和解决方法
  2. html盒子模型 正方形嵌套,前端box(盒子嵌套)
  3. ARCGIS 给面文件“挖洞”——Erase的用法
  4. Android 程序员的技术栈大全(1),中高级Android面试题目汇总解答
  5. 洗碗机,加速中国化才能更适合中国厨房
  6. 计算机图形学流体仿真mac网格,用于图形学的流体仿真20教程.docx
  7. Android 適配器的回調
  8. 我们过度解读了鲁迅了么?
  9. 项目分享之敲击床头盒控制床头灯的开关
  10. xaxis python_Python中的分组Xaxis可变性图