private void RenderShadows(RenderTarget renderTarget, Light light, Stage stage, Camera camera, int cascadeIndex, out Matrix4 viewProjection, out Vector2 clipPlane) { Backend.BeginPass(renderTarget, new Vector4(0, 0, 0, 1), true); var modelViewProjection = Matrix4.Identity; var orientation = Vector3.GetRotationTo(Vector3.UnitY, light.Direction); clipPlane = new Vector2(light.ShadowNearClipDistance, light.Range * 2.0f); Matrix4 view, projection; if (light.Type == LighType.Directional) { var cameraFrustum = camera.GetFrustum(); var lightDir = -light.Direction; lightDir.Normalize(); Matrix4 lightRotation = Matrix4.LookAt(Vector3.Zero, lightDir, Vector3.UnitY); Vector3[] corners = cameraFrustum.GetCorners(); for (var i = 0; i < corners.Length; i++) { corners[i] = Vector3.Transform(corners[i], lightRotation); } var lightBox = BoundingBox.CreateFromPoints(corners); var boxSize = lightBox.Max - lightBox.Min; Vector3 halfBoxSize; Vector3.Multiply(ref boxSize, 0.5f, out halfBoxSize); var lightPosition = lightBox.Min + halfBoxSize; lightPosition.Z = lightBox.Min.Z; lightPosition = Vector3.Transform(lightPosition, Matrix4.Invert(lightRotation)); view = Matrix4.LookAt(lightPosition, lightPosition - lightDir, Vector3.UnitY); projection = Matrix4.CreateOrthographic(boxSize.X, boxSize.Y, -boxSize.Z, boxSize.Z); clipPlane.X = -boxSize.Z; clipPlane.Y = boxSize.Z; } else { view = Matrix4.LookAt(light.Position, light.Position + light.Direction, Vector3.UnitY); projection = Matrix4.CreatePerspectiveFieldOfView(light.OuterAngle, renderTarget.Width / (float)renderTarget.Height, clipPlane.X, clipPlane.Y); } viewProjection = view * projection; ShadowRenderOperations.Reset(); stage.PrepareRenderOperations(view, ShadowRenderOperations, true, false); RenderOperation[] operations; int count; ShadowRenderOperations.GetOperations(out operations, out count); for (var i = 0; i < count; i++) { var world = operations[i].WorldMatrix; modelViewProjection = world * view * projection; Resources.ShaderProgram program; RenderShadowsParams shadowParams; if (operations[i].Skeleton != null) { program = RenderShadowsSkinnedShader; shadowParams = RenderShadowsSkinnedParams; } else { program = RenderShadowsShader; shadowParams = RenderShadowsParams; } Backend.BeginInstance(program.Handle, null, null, ShadowsRenderState); Backend.BindShaderVariable(shadowParams.ModelViewProjection, ref modelViewProjection); Backend.BindShaderVariable(shadowParams.ClipPlane, ref clipPlane); if (light.Type == LighType.Directional) { float shadowBias = 0.05f * (cascadeIndex + 1); Backend.BindShaderVariable(shadowParams.ShadowBias, shadowBias); } if (operations[i].Skeleton != null) { Backend.BindShaderVariable(shadowParams.Bones, ref operations[i].Skeleton.FinalBoneTransforms); } Backend.DrawMesh(operations[i].MeshHandle); Backend.EndInstance(); } Backend.EndPass(); }
private void RenderShadowsCube(RenderTarget renderTarget, Light light, Stage stage, Camera camera, out Matrix4 viewProjection, out Vector2 clipPlane) { Backend.BeginPass(renderTarget, new Vector4(0, 0, 0, 1), true); var modelViewProjection = Matrix4.Identity; var orientation = Vector3.GetRotationTo(Vector3.UnitY, light.Direction); clipPlane = new Vector2(light.ShadowNearClipDistance, light.Range * 2.0f); var projection = Matrix4.CreatePerspectiveFieldOfView(OpenTK.MathHelper.DegreesToRadians(90), renderTarget.Width / (float)renderTarget.Height, clipPlane.X, clipPlane.Y); var viewProjectionMatrices = new Matrix4[] { (Matrix4.CreateTranslation(-light.Position) * new Matrix4(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1)) * projection, (Matrix4.CreateTranslation(-light.Position) * new Matrix4(0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)) * projection, (Matrix4.CreateTranslation(-light.Position) * new Matrix4(1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1)) * projection, (Matrix4.CreateTranslation(-light.Position) * new Matrix4(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1)) * projection, (Matrix4.CreateTranslation(-light.Position) * new Matrix4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)) * projection, (Matrix4.CreateTranslation(-light.Position) * new Matrix4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)) * projection }; viewProjection = projection; ShadowRenderOperations.Reset(); stage.PrepareRenderOperations(light.Position, light.Range * 2, ShadowRenderOperations, true); RenderOperation[] operations; int count; ShadowRenderOperations.GetOperations(out operations, out count); for (var i = 0; i < count; i++) { var world = operations[i].WorldMatrix; Resources.ShaderProgram program; RenderShadowsParams shadowParams; if (operations[i].Skeleton != null) { program = RenderShadowsSkinnedCubeShader; shadowParams = RenderShadowsSkinnedCubeParams; } else { program = RenderShadowsCubeShader; shadowParams = RenderShadowsCubeParams; } Backend.BeginInstance(program.Handle, null, null, ShadowsRenderState); Backend.BindShaderVariable(shadowParams.Model, ref world); Backend.BindShaderVariable(shadowParams.ClipPlane, ref clipPlane); Backend.BindShaderVariable(shadowParams.ViewProjectionMatrices, ref viewProjectionMatrices); Backend.BindShaderVariable(shadowParams.LightPosition, ref light.Position); if (operations[i].Skeleton != null) { Backend.BindShaderVariable(shadowParams.Bones, ref operations[i].Skeleton.FinalBoneTransforms); } Backend.DrawMesh(operations[i].MeshHandle); Backend.EndInstance(); } Backend.EndPass(); }
private void RenderScene(Stage stage, Camera camera, ref Matrix4 view, ref Matrix4 projection) { var viewProjection = view * projection; RenderOperations.Reset(); stage.PrepareRenderOperations(viewProjection, RenderOperations); RenderOperation[] operations; int count; RenderOperations.GetOperations(out operations, out count); Resources.Material activeMaterial = null; Matrix4 worldView, world, itWorld, worldViewProjection; for (var i = 0; i < count; i++) { world = operations[i].WorldMatrix; Matrix4.Mult(ref world, ref viewProjection, out worldViewProjection); Matrix4.Mult(ref world, ref view, out worldView); itWorld = Matrix4.Transpose(Matrix4.Invert(world)); if (activeMaterial == null || activeMaterial.Id != operations[i].Material.Id) { operations[i].Material.BeginInstance(Backend, camera, 0); } operations[i].Material.BindPerObject(Backend, ref world, ref worldView, ref itWorld, ref worldViewProjection, operations[i].Skeleton); Backend.DrawMesh(operations[i].MeshHandle); } }