Created by miccall (转载请注明出处 miccall.tech)
1. Lighting
2. shadow
在执行玩剔除之后 ,就需要去渲染阴影贴图。
阴影贴图本质上是一个深度图,把摄像机放在灯光的位置来获取
首先 ,我们需要一个renderTexture 来生成一个阴影贴图
// 生成一张阴影贴图
shadowMap = RenderTexture.GetTemporary(
shadowMapSize, shadowMapSize, 16, RenderTextureFormat.Shadowmap
);
//将纹理的滤镜模式设置为双线性,并使用clamp
shadowMap.filterMode = FilterMode.Bilinear;
shadowMap.wrapMode = TextureWrapMode.Clamp;
之后,我们把这张图与commandbuffer绑定
// 渲染阴影之前,我们首先告诉GPU渲染到阴影贴图
CoreUtils.SetRenderTarget(ShadowBuffer , shadowMap,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,ClearFlag.Depth);
现在就开始渲染纹理了
// 开始渲染纹理
ShadowBuffer.BeginSample("Render Shadows");
context.ExecuteCommandBuffer(ShadowBuffer);
ShadowBuffer.Clear();
我们需要对场景中所有的灯,只要他的设置为阴影投射,那么我们就得为他指定一个深度图
for (var i = 0; i < _cull.visibleLights.Count; i++)
{
// 超过最大的灯
if (i == maxVisibleLights) break;
// 强度为 0
if (shadowData[i].x <= 0f) continue;
}
之后,我们需要得到相机位置的 V p 矩阵 unity有方法为我们计算
// V P 矩阵 viewMatrix and projectionMatrix
if (!_cull.ComputeSpotShadowMatricesAndCullingPrimitives(
i, out var viewMatrix, out var projectionMatrix, out var splitData
)) {
//如果失败则跳过灯 将强度设置为零
shadowData[i].x = 0f;
continue;
}
之后,把得到的vp矩阵传入shader
// 设置矩阵 ,执行并清除
ShadowBuffer.SetViewProjectionMatrices(viewMatrix, projectionMatrix);
ShadowBuffer.SetGlobalFloat(shadowBiasId, _cull.visibleLights[i].light.shadowBias);
context.ExecuteCommandBuffer(ShadowBuffer);
ShadowBuffer.Clear();
因为 dx 和 opengl 的 zbuffer 是反着的,所以我们还要处理一下
// 是否反转矩阵
if (SystemInfo.usesReversedZBuffer) {
projectionMatrix.m20 = -projectionMatrix.m20;
projectionMatrix.m21 = -projectionMatrix.m21;
projectionMatrix.m22 = -projectionMatrix.m22;
projectionMatrix.m23 = -projectionMatrix.m23;
}