private MyShadowMapData StandardShadowMap(ScriptableRenderContext context, MyRenderingData renderingData, ShadowSettings settings, int lightIndex) { var cmd = CommandBufferPool.Get(); cmd.Clear(); var depthBuf = IdentifierPool.Get(); cmd.GetTemporaryRT(depthBuf, settings.resolution, settings.resolution, 32, FilterMode.Point, RenderTextureFormat.Depth); RenderTargetBinding binding = new RenderTargetBinding(); binding.depthRenderTarget = depthBuf; cmd.SetRenderTarget(depthBuf); cmd.ClearRenderTarget(true, true, Color.black); MyShadowMapData shadowMapData = new MyShadowMapData() { shadowMapIdentifier = depthBuf, bias = settings.bias, shadowType = ShadowAlgorithms.Standard, }; var(view, projection) = GetShadowViewProjection(settings, renderingData, lightIndex); cmd.SetViewProjectionMatrices(view, projection); shadowMapData.world2Light = projection * view; cmd.SetGlobalDepthBias(settings.depthBias, settings.normalBias); context.ExecuteCommandBuffer(cmd); cmd.Clear(); DrawShadowCasters(context, renderingData, shadowMapData, PassSimple); cmd.SetViewProjectionMatrices(renderingData.camera.worldToCameraMatrix, renderingData.camera.projectionMatrix); context.ExecuteCommandBuffer(cmd); cmd.Clear(); CommandBufferPool.Release(cmd); return(shadowMapData); }
private MyShadowMapData PSMShadowMap(ScriptableRenderContext context, MyRenderingData renderingData, ShadowSettings settings, int lightIndex) { var(view, projection, inverseZ) = PSMProjection(lightIndex, renderingData, settings); //Debug.Log(inverseZ); Vector4 p = new Vector4(-0.46017f, 0.16764f, 0.01015f, 1.00f); var p1 = projection * view * p; var p2 = GL.GetGPUProjectionMatrix(projection, false) * Matrix4x4.Scale(new Vector3(1, 1, -1)) * view * p; MyShadowMapData shadowMapData = new MyShadowMapData() { shadowMapIdentifier = IdentifierPool.Get(), world2Light = GL.GetGPUProjectionMatrix(projection, true) * Matrix4x4.Scale(new Vector3(1, 1, -1)) * view, bias = settings.bias, shadowType = ShadowAlgorithms.PSM, shadowParameters = new Vector4(inverseZ ? 1 : 0, 0, 0), }; var cmd = CommandBufferPool.Get(); cmd.GetTemporaryRT(shadowMapData.shadowMapIdentifier, settings.resolution, settings.resolution, 32, FilterMode.Point, RenderTextureFormat.Depth); cmd.SetRenderTarget(shadowMapData.shadowMapIdentifier); cmd.SetGlobalVector("_ShadowParameters", shadowMapData.shadowParameters); cmd.SetGlobalDepthBias(1, 1); //cmd.SetViewProjectionMatrices(renderingData.camera.worldToCameraMatrix, renderingData.camera.projectionMatrix); cmd.ClearRenderTarget(true, true, Color.black); context.ExecuteCommandBuffer(cmd); cmd.Clear(); DrawShadowCasters(context, renderingData, shadowMapData, PassPSM); CommandBufferPool.Release(cmd); return(shadowMapData); }
public static Matrix4x4 TSMTransform(Camera camera, Matrix4x4 lightViewProjection, ShadowSettings shadowSettings) { var frustumVerts = ShadowUtils .GetCameraFrustumVerticies(camera, camera.nearClipPlane, shadowSettings.maxShadowDistance) .Select(p => ToPostPerspective(p, lightViewProjection)); var convex = GetConvexHull(frustumVerts.Select(p => p.ToVector2()).ToArray()); var nearCenter = ToPostPerspective(camera.transform.position + camera.transform.forward * camera.nearClipPlane, lightViewProjection).ToVector2(); var farCenter = ToPostPerspective( camera.transform.position + camera.transform.forward * shadowSettings.maxShadowDistance, lightViewProjection).ToVector2(); var focusPoint = ToPostPerspective(camera.transform.position + camera.transform.forward * shadowSettings.focusDistance, lightViewProjection).ToVector2(); var centralLine = farCenter - nearCenter; var centralLineVector = centralLine.normalized; var topPoint = nearCenter + centralLineVector * convex.Min(p => Vector2.Dot(p - nearCenter, centralLineVector)); var bottomVert = convex.MaxOf(p => Vector2.Dot(p - nearCenter, centralLineVector), p => p); var bottomPoint = topPoint + centralLineVector * Vector2.Dot(bottomVert - topPoint, centralLineVector); var tangent = (bottomVert - bottomPoint).normalized * Mathf.Sign(MathUtility.Cross2(bottomVert - topPoint, centralLineVector)); var height = (bottomPoint - topPoint).magnitude; var focusLen = Vector2.Dot(focusPoint - topPoint, centralLineVector); var λ = height; var ξ = -0.6f; var δ = focusLen; var η = (λ * δ + λ * δ * ξ) / (λ - 2 * δ - λ * ξ); var origin = -η * centralLineVector + topPoint; var cosMaxHalfAngle = convex.Min(p => Vector2.Dot((p - origin).normalized, centralLineVector)); var tan = Mathf.Sqrt(1 - cosMaxHalfAngle * cosMaxHalfAngle) / cosMaxHalfAngle; var minSinHalfAngle = convex.Min(p => MathUtility.Cross2((p - origin).normalized, centralLineVector)); var maxSinHalfAngle = convex.Max(p => MathUtility.Cross2((p - origin).normalized, centralLineVector)); var minTan = minSinHalfAngle / Mathf.Sqrt(1 - minSinHalfAngle * minSinHalfAngle); var maxTan = maxSinHalfAngle / Mathf.Sqrt(1 - maxSinHalfAngle * maxSinHalfAngle); var t0 = bottomPoint + (bottomPoint - origin).magnitude * minTan * tangent; var t1 = bottomPoint + (bottomPoint - origin).magnitude * maxTan * tangent; var t2 = topPoint + (topPoint - origin).magnitude * minTan * tangent; var t3 = topPoint + (topPoint - origin).magnitude * maxTan * tangent; // Transform trapezoid into unit cube // Following https://www.comp.nus.edu.sg/~tants/tsm/TSM_recipe.html var transform = Matrix4x4.identity; // #1 Vector4 u = (t2 + t3) / 2; transform = Matrix4x4.Translate(-u) * transform; // #2 u = (t2 - t3) / (t2 - t3).magnitude; transform = new Matrix4x4( new Vector4(u.x, u.y, 0, 0), new Vector4(u.y, -u.x, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) ) * transform; // #3 u = transform * origin.ToVector4(0, 1); transform = Matrix4x4.Translate(-u) * transform; // #4 u = (transform.MultiplyPoint((t2 + t3) / 2)); transform = new Matrix4x4( new Vector4(1, -u.x / u.y, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1) ).transpose *transform; // #5 u = transform.MultiplyPoint(t2); transform = Matrix4x4.Scale(new Vector3(1 / u.x, 1 / u.y, 1)) * transform; // #6 transform = new Matrix4x4( new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 1), new Vector4(0, 0, 1, 0), new Vector4(0, 1, 0, 0) ) * transform; // #7 u = transform * t0.ToVector4(0, 1); var v = transform * t2.ToVector4(0, 1); transform = Matrix4x4.Translate(new Vector3(0, -(u.y / u.w + v.y / v.w) / 2, 0)) * transform; // #8 u = transform * t0.ToVector4(0, 1); transform = Matrix4x4.Scale(new Vector3(1, -u.w / u.y, 1)) * transform; var trapezoidal = new Vector2[] { t0, t1, t3, t2 }; var t = trapezoidal.Select(p => transform.MultiplyPoint(p).ToVector2()).ToArray(); //DrawPolygonOnLightPlane(t, lightViewProjection, Color.blue); if (shadowSettings.debug) { ShadowUtils.DrawPolygonOnLightPlane(trapezoidal, lightViewProjection, Color.blue); ShadowUtils.DrawPolygonOnLightPlane(new Vector2[] { nearCenter, farCenter }, lightViewProjection, Color.red); ShadowUtils.DrawPolygonOnLightPlane(convex, lightViewProjection, Color.red); } return(transform); }
public static (Matrix4x4 view, Matrix4x4 projection) GetShadowViewProjection(ShadowSettings settings, MyRenderingData renderingData, int lightIndex) { var camera = renderingData.camera; if (settings.debug) { camera = GameObject.Find("Main Camera").GetComponent <Camera>(); } var cameraToWorld = camera.transform.localToWorldMatrix; var p0 = cameraToWorld.MultiplyPoint(new Vector3(0, 0, 0)); var h = Mathf.Tan(camera.fieldOfView * Mathf.Deg2Rad / 2); var w = h * camera.aspect; var p1 = cameraToWorld.MultiplyPoint(new Vector3(-w, -h, 1) * settings.maxShadowDistance); var p2 = cameraToWorld.MultiplyPoint(new Vector3(w, -h, 1) * settings.maxShadowDistance); var p3 = cameraToWorld.MultiplyPoint(new Vector3(w, h, 1) * settings.maxShadowDistance); var p4 = cameraToWorld.MultiplyPoint(new Vector3(-w, h, 1) * settings.maxShadowDistance); //左右手坐标转换 var view = Matrix4x4.Scale(new Vector3(1, 1, -1)) * settings.transform.worldToLocalMatrix; renderingData.cullResults.GetShadowCasterBounds(lightIndex, out var bounds); //阴影包围盒 var casterBoundVerts = new Vector3[8]; for (int x = -1, i = 0; x <= 1; x += 2) { for (int y = -1; y <= 1; y += 2) { for (int z = -1; z <= 1; z += 2) { casterBoundVerts[i++] = bounds.center + Vector3.Scale(bounds.extents, new Vector3(x, y, z)); } } } var debug = camera.name == "Main Camera" && settings.debug; if (settings.light.type == LightType.Point) { //朝向 + shadow框 var rotation = Matrix4x4.Rotate(Quaternion.FromToRotation(Vector3.forward, settings.transform.worldToLocalMatrix.MultiplyPoint(bounds.center).normalized)); var rotatedView = rotation.inverse * settings.light.transform.worldToLocalMatrix; var frustumCaster = BestfitFrustum(false, rotatedView, casterBoundVerts); if (debug) { ShadowUtils.DrawBound(bounds, Color.cyan); ShadowUtils.DrawFrustum(frustumCaster, false, rotatedView.inverse); } return(Matrix4x4.Scale(new Vector3(1, 1, -1)) * rotatedView, Matrix4x4.Frustum(frustumCaster)); } else if (settings.light.type == LightType.Spot) { Matrix4x4 lightView = settings.light.transform.worldToLocalMatrix; var frustumCamera = BestfitFrustum(false, lightView, p0, p1, p2, p3, p4); var frustumCaster = BestfitFrustum(false, lightView, casterBoundVerts); var near = settings.nearDistance; var far = Mathf.Min(frustumCaster.zFar, frustumCamera.zFar, settings.light.range); return(view, Matrix4x4.Perspective(settings.light.spotAngle, 1, near, far)); } else if (settings.light.type == LightType.Directional) { //shadow框和摄像机框 比较 选择最大/小的 var frustumCamera = BestfitFrustum(true, settings.light.transform.worldToLocalMatrix, p0, p1, p2, p3, p4); var frustumCaster = BestfitFrustum(true, settings.light.transform.worldToLocalMatrix, casterBoundVerts); var left = Mathf.Max(frustumCaster.left, frustumCamera.left); var right = Mathf.Min(frustumCaster.right, frustumCamera.right); var bottom = Mathf.Max(frustumCaster.bottom, frustumCamera.bottom); var top = Mathf.Min(frustumCaster.top, frustumCamera.top); var zNear = frustumCaster.zNear; var zFar = Mathf.Min(frustumCaster.zFar, frustumCamera.zFar); if (debug) { var bound = new Bounds(); bound.min = new Vector3(left, bottom, zNear); bound.max = new Vector3(right, top, zFar); ShadowUtils.DrawFrustum(new FrustumPlanes() { left = Mathf.Max(frustumCaster.left, frustumCamera.left), right = Mathf.Min(frustumCaster.right, frustumCamera.right), bottom = Mathf.Max(frustumCaster.bottom, frustumCamera.bottom), top = Mathf.Min(frustumCaster.top, frustumCamera.top), zNear = frustumCaster.zNear, zFar = Mathf.Min(frustumCaster.zFar, frustumCamera.zFar), }, true, settings.transform.localToWorldMatrix); //DrawBound(bounds, Color.cyan); Debug.DrawRay( settings.transform.localToWorldMatrix.MultiplyPoint(new Vector3(bound.center.x, bound.center.y, zNear)), settings.transform.forward * 5, Color.green); } return(view, Matrix4x4.Ortho(left, right, bottom, top, zNear, zFar)); } return(Matrix4x4.identity, Matrix4x4.identity); }
public static (Matrix4x4 view, Matrix4x4 projection, bool inverseZ) PSMProjection(int lightIndex, MyRenderingData renderingData, ShadowSettings settings) { var camera = GameObject.Find("Main Camera").GetComponent <Camera>(); var cameraView = camera.worldToCameraMatrix; var cameraProjection = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false); var light = renderingData.cullResults.visibleLights[lightIndex].light; var p = light.transform.forward.ToVector4(1); var l = light.transform.forward.ToVector4(0); var pView = cameraView * p; var lView = cameraView * l; var lClip = cameraProjection * lView.ToVector3().normalized.ToVector4(0); var pClip = cameraProjection * lView.ToVector3().normalized.ToVector4(1); var lightNDC = lClip / pClip.w; var lightView = Matrix4x4.LookAt(lightNDC.ToVector3(), Vector3.forward * .5f, Vector3.up).inverse; var ndcBounds = new Bounds(Vector3.forward * 0.5f, new Vector3(2, 2, 1)); var ndcBoundVerts = new Vector3[8]; for (int x = -1, i = 0; x <= 1; x += 2) { for (int y = -1; y <= 1; y += 2) { for (int z = -1; z <= 1; z += 2) { ndcBoundVerts[i++] = ndcBounds.center + Vector3.Scale(ndcBounds.extents, new Vector3(x, y, z)); } } } var frustum = BestfitFrustum(false, lightView, ndcBoundVerts); var inverseZ = Vector3.Dot(lView, -lightNDC.ToVector3()) < 0; if (settings.debug) { ShadowUtils.DrawFrustum(frustum, false, lightView.inverse); ShadowUtils.DrawBound(ndcBounds, Color.magenta); Debug.DrawLine(Vector3.forward * 0.5f, lightNDC.ToVector3()); } return(lightView, Matrix4x4.Frustum(frustum), inverseZ); }