public Vector4 ReserveDirectionalShadows(Light light, int visibleLightIndex) { if (currentDirectionalLightShadowCount < maxDirectionalShadowCount && light.shadows != LightShadows.None && light.shadowStrength > 0f) { float maskChannel; LightBakingOutput lightBakingOutput = light.bakingOutput; if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBakingOutput.occlusionMaskChannel; // can not use the light index because it may be changed in runtime } else { maskChannel = -1; } // GetShadowCasterBounds now returns true for directional lights even when there is nothing within the shadow range if (!cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { // the shadow strength of light is negative, see GetDirectionalShadowAttenuation in WindsmoonShadow.hlsl // if the stength is positive, the shader may be handle the shadow as realtime shadow return(new Vector4(-light.shadowStrength, 0f, 0, maskChannel)); } directionalShadows[currentDirectionalLightShadowCount] = new DirectionalShadow() { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector4(light.shadowStrength, shadowSettings.DirectionalShadowSetting.CascadeCount * currentDirectionalLightShadowCount++, light.shadowNormalBias, maskChannel)); } return(new Vector4(0f, 0f, 0f, -1)); }
private void RenderDirectionalShadow(int index, int splitCount, int tileSize) { DirectionalShadow directionalShadow = directionalShadows[index]; ShadowDrawingSettings shadowDrawingSettings = new ShadowDrawingSettings(cullingResults, directionalShadow.visibleLightIndex); int cascadeCount = shadowSettings.DirectionalShadowSetting.CascadeCount; int tileOffset = index * cascadeCount; Vector3 cascadeRatios = shadowSettings.DirectionalShadowSetting.CascadeRatios; float cascadeCullingFactor = Mathf.Max(0f, 0.8f - shadowSettings.DirectionalShadowSetting.CascadeFade); // control how much shadow casters will cast shadow in larger cascade float inversedSplitCount = 1f / splitCount; for (int i = 0; i < cascadeCount; ++i) { // note : the split data contains information about how shadow caster objects should be culled cullingResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(directionalShadow.visibleLightIndex, i, cascadeCount, cascadeRatios, tileSize, directionalShadow.nearPlaneOffset, out Matrix4x4 viewMatrix, out Matrix4x4 projectionMatrix, out ShadowSplitData shadowSplitData); shadowSplitData.shadowCascadeBlendCullingFactor = cascadeCullingFactor; shadowDrawingSettings.splitData = shadowSplitData; if (index == 0) // set culling spheres, all directional light use only one group of culling spheres { // note : as the shadow projections are orthographic and square they end up closely fitting their culling sphere, but also cover some space around them // that's why some shadows can be seen outside the culling regions // also the light direction doesn't matter to the sphere, so all directional lights end up using the same culling spheres // the camera is not at the sphere's center, but the surface of the sphere, all spheres will intersect at this point Vector4 cullingSphere = shadowSplitData.cullingSphere; // w means sphere's radius SetCascadeInfo(i, cullingSphere, tileSize); } int tileIndex = tileOffset + i; SetShadowMapViewport(tileIndex, splitCount, tileSize, out Vector2 offset); // Matrix4x4 vpMatrix = projectionMatrix * viewMatrix directionalShadowMatrices[tileIndex] = ConvertClipSpaceToTileSpace(projectionMatrix * viewMatrix, offset, inversedSplitCount); // directionalShadowMatrices[index] = projectionMatrix * viewMatrix; commandBuffer.SetViewProjectionMatrices(viewMatrix, projectionMatrix); commandBuffer.SetGlobalDepthBias(0f, directionalShadow.slopeScaleBias); ExecuteBuffer(); renderContext.DrawShadows(ref shadowDrawingSettings); commandBuffer.SetGlobalDepthBias(0f, 0f); } }
public Vector3 ReserveDirectionalShadows(Light light, int visibleLightIndex) { // GetShadowCasterBounds return true if the light affects at least one shadow casting object in the Scene if (currentDirectionalLightShadowCount >= maxDirectionalShadowCount || light.shadows == LightShadows.None || light.shadowStrength <= 0f || cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds bouds) == false) { return(Vector3.zero); } LightBakingOutput lightBakingOutput = light.bakingOutput; if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; } directionalShadows[currentDirectionalLightShadowCount] = new DirectionalShadow() { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector3(light.shadowStrength, shadowSettings.DirectionalShadowSetting.CascadeCount * currentDirectionalLightShadowCount++, light.shadowNormalBias)); }