diff --git a/Assets/Custom RP.asset b/Assets/Custom RP.asset index c17738c5f932e9d41a5139d5352732dd03267219..8eec27c34c76d3e8f8c6418d5bf88222da0cfb59 100644 --- a/Assets/Custom RP.asset +++ b/Assets/Custom RP.asset @@ -15,6 +15,7 @@ MonoBehaviour: useDynamicBatching: 0 useGPUInstancing: 1 useSRPBatcher: 1 + useLightsPerObject: 1 shadows: maxDistance: 30 distanceFade: 0.1 diff --git a/Assets/Custom RP/Runtime/CustomRenderPipelineAsset.cs b/Assets/Custom RP/Runtime/CustomRenderPipelineAsset.cs index b43722a2345bac7262cc384e46cf222065ffbbd0..cb20536d9824b9e7dff228cbed7e4898cb6b86ec 100644 --- a/Assets/Custom RP/Runtime/CustomRenderPipelineAsset.cs +++ b/Assets/Custom RP/Runtime/CustomRenderPipelineAsset.cs @@ -10,6 +10,7 @@ public class CustomRenderPipelineAsset : RenderPipelineAsset [SerializeField] bool useDynamicBatching = true, useGPUInstancing = true, useSRPBatcher = true; // 是否使用逐对象光源 + [SerializeField] bool useLightsPerObject = true; [SerializeField] diff --git a/Assets/Custom RP/Runtime/Shadows.cs b/Assets/Custom RP/Runtime/Shadows.cs index ec2be2c1cf34514a3a66a1035dfe38f90de4c181..576e7ca4b78fa402e44a321dfc99d3346b2eb379 100644 --- a/Assets/Custom RP/Runtime/Shadows.cs +++ b/Assets/Custom RP/Runtime/Shadows.cs @@ -117,8 +117,21 @@ public class Shadows this.cullingResults = cullingResults; this.shadowSettings = shadowSettings; shadowedDirectionalLightCount = 0; - useShadowMask = false; shadowedOtherLightCount = 0; + useShadowMask = false; + } + + /// + /// 释放申请的RT内存 + /// + public void Cleanup() + { + buffer.ReleaseTemporaryRT(dirShadowAtlasId); + if (shadowedOtherLightCount > 0) + { + buffer.ReleaseTemporaryRT(otherShadowAtlasId); + } + ExecuteBuffer(); } /// @@ -201,7 +214,7 @@ public class Shadows normalBias = light.shadowNormalBias, isPoint = isPoint }; - Vector4 data = new Vector4(light.shadowStrength, shadowedOtherLightCount++, isPoint ? 1f : 0f, maskChannel); + Vector4 data = new Vector4(light.shadowStrength, shadowedOtherLightCount, isPoint ? 1f : 0f, maskChannel); shadowedOtherLightCount = newLightCount; return data; } @@ -307,7 +320,7 @@ public class Shadows int split = tiles <= 1 ? 1 : tiles <= 4 ? 2 : 4; int tileSize = atlasSize / split; // 遍历所有光源渲染阴影贴图 - for (int i = 0; i < shadowedOtherLightCount; i++) + for (int i = 0; i < shadowedOtherLightCount;) { if (shadowedOtherLights[i].isPoint) { @@ -427,18 +440,22 @@ public class Shadows { ShadowedOtherLight light = shadowedOtherLights[index]; var newShadowSettings = new ShadowDrawingSettings(cullingResults, light.visibleLightIndex); - for (int i = 0; i < 6; i++) + // 计算法线偏差 + float texelSize = 2f / tileSize; + float filterSize = texelSize * ((float)shadowSettings.other.filter + 1f); + float bias = light.normalBias * filterSize * 1.4142136f; + float tileScale = 1f / split; + float fovBias = Mathf.Atan(1f + bias + filterSize) * Mathf.Rad2Deg * 2f - 90f; + for (int i = 0; i < 6; i++) { - cullingResults.ComputePointShadowMatricesAndCullingPrimitives(light.visibleLightIndex, (CubemapFace)i, 0f, out Matrix4x4 viewMatrix, out Matrix4x4 projectionMatrix, out ShadowSplitData splitData); - newShadowSettings.splitData = splitData; + cullingResults.ComputePointShadowMatricesAndCullingPrimitives(light.visibleLightIndex, (CubemapFace)i, fovBias, out Matrix4x4 viewMatrix, out Matrix4x4 projectionMatrix, out ShadowSplitData splitData); + viewMatrix.m11 = -viewMatrix.m11; + viewMatrix.m12 = -viewMatrix.m12; + viewMatrix.m13 = -viewMatrix.m13; + newShadowSettings.splitData = splitData; int tileIndex = index + i; - // 计算法线偏差 - float texelSize = 2f / (tileSize * projectionMatrix.m00); - float filterSize = texelSize * ((float)shadowSettings.other.filter + 1f); - float bias = light.normalBias * filterSize * 1.4142136f; Vector2 offset = SetTileViewport(tileIndex, split, tileSize); - float tileScale = 1f / split; SetOtherTileData(tileIndex, offset, tileScale, bias); otherShadowMatrices[tileIndex] = ConvertToAtlasMatrix(projectionMatrix * viewMatrix, offset, tileScale); buffer.SetViewProjectionMatrices(viewMatrix, projectionMatrix); @@ -530,17 +547,4 @@ public class Shadows m.m23 = 0.5f * (m.m23 + m.m33); return m; } - - /// - /// 释放申请的RT内存 - /// - public void Cleanup() - { - buffer.ReleaseTemporaryRT(dirShadowAtlasId); - if (shadowedOtherLightCount > 0) - { - buffer.ReleaseTemporaryRT(otherShadowAtlasId); - } - ExecuteBuffer(); - } } diff --git a/Assets/Custom RP/ShaderLibrary/Light.hlsl b/Assets/Custom RP/ShaderLibrary/Light.hlsl index 0e60f4613c996603391ec12cb6753ac23bd7b9fd..93c7c4342e7f91268e6b8f1a198563e0f4f680cc 100644 --- a/Assets/Custom RP/ShaderLibrary/Light.hlsl +++ b/Assets/Custom RP/ShaderLibrary/Light.hlsl @@ -60,7 +60,9 @@ OtherShadowData GetOtherShadowData(int lightIndex) data.strength = _OtherLightShadowData[lightIndex].x; data.tileIndex = _OtherLightShadowData[lightIndex].y; data.shadowMaskChannel = _OtherLightShadowData[lightIndex].w; + data.isPoint = _OtherLightShadowData[lightIndex].z == 1.0; data.lightPositionWS = 0.0; + data.lightDirectionWS = 0.0; data.spotDirectionWS = 0.0; return data; } @@ -97,6 +99,7 @@ Light GetOtherLight(int index, Surface surfaceWS, ShadowData shadowData) OtherShadowData otherShadowData = GetOtherShadowData(index); otherShadowData.lightPositionWS = position; + otherShadowData.lightDirectionWS = light.direction; otherShadowData.spotDirectionWS = spotDirection; // 光照强度随范围和距离衰减 light.attenuation = GetOtherShadowAttenuation(otherShadowData, shadowData, surfaceWS) * spotAttenuation * rangeAttenuation / distanceSqr; diff --git a/Assets/Custom RP/ShaderLibrary/Shadows.hlsl b/Assets/Custom RP/ShaderLibrary/Shadows.hlsl index 1f9b7ebb0349264c7cf42fb8b5bb4c843256cedb..b2317ec572a9da4ea6ac85cd14ba27a216ec65f4 100644 --- a/Assets/Custom RP/ShaderLibrary/Shadows.hlsl +++ b/Assets/Custom RP/ShaderLibrary/Shadows.hlsl @@ -79,6 +79,7 @@ float GetBakedShadow(ShadowMask mask, int channel) return shadow; } +// 获取烘焙阴影的衰减值 float GetBakedShadow(ShadowMask mask, int channel, float strength) { if (mask.always || mask.distance) @@ -265,6 +266,7 @@ struct OtherShadowData { float strength; int tileIndex; + bool isPoint; int shadowMaskChannel; float3 lightPositionWS; float3 lightDirectionWS; @@ -302,7 +304,8 @@ float FilterOtherShadow(float3 positionSTS, float3 bonuds) #endif } -static const float3 pointShadowPlanes[6] = { +static const float3 pointShadowPlanes[6] = +{ float3(-1.0, 0.0, 0.0), float3(1.0, 0.0, 0.0), float3(0.0, -1.0, 0.0), @@ -315,9 +318,16 @@ static const float3 pointShadowPlanes[6] = { float GetOtherShadow(OtherShadowData other, ShadowData global, Surface surfaceWS) { float tileIndex = other.tileIndex; + float3 lightPlane = other.spotDirectionWS; + if (other.isPoint) + { + float faceOffset = CubeMapFaceID(-other.lightDirectionWS); + tileIndex += faceOffset; + lightPlane = pointShadowPlanes[faceOffset]; + } float4 tileData = _OtherShadowTiles[tileIndex]; float3 surfaceToLight = other.lightPositionWS - surfaceWS.position; - float distanceToLightPlane = dot(surfaceToLight, other.spotDirectionWS); + float distanceToLightPlane = dot(surfaceToLight, lightPlane); float3 normalBias = surfaceWS.interpolatedNormal * (distanceToLightPlane * tileData.w); float4 positionSTS = mul(_OtherShadowMatrices[tileIndex], float4(surfaceWS.position + normalBias, 1.0)); return FilterOtherShadow(positionSTS.xyz / positionSTS.w, tileData.xyz);