/// <summary> /// Update the 6-sides of the cube map using a single pass via Geometry shader instancing with the provided context /// </summary> /// <param name="context">The context to render within</param> /// <param name="renderScene">The method that will render the scene</param> public void UpdateSinglePass(DeviceContext context, Action<DeviceContext, Matrix, Matrix, RenderTargetView, DepthStencilView, DynamicCubeMap> renderScene) { // Don't render the reflector itself if (Reflector != null) { Reflector.Show = false; } // Prepare pipeline context.OutputMerger.SetRenderTargets(EnvMapDSV, EnvMapRTV); context.Rasterizer.SetViewport(Viewport); // Prepare the view projections Matrix[] viewProjections = new Matrix[6]; for (var i = 0; i < 6; i++) viewProjections[i] = Matrix.Transpose(Cameras[i].View * Cameras[i].Projection); // Update per env map buffer with the ViewProjections context.UpdateSubresource(viewProjections, PerEnvMapBuffer); // Assign the per environment map buffer to the GS stage at slot 4 context.GeometryShader.SetConstantBuffer(4, PerEnvMapBuffer); // Render the scene using the view, projection, RTV and DSV renderScene(context, Cameras[0].View, Cameras[0].Projection, EnvMapRTV, EnvMapDSV, this); // Unbind the RTV and DSV context.OutputMerger.ResetTargets(); // Prepare the SRV mip levels context.GenerateMips(EnvMapSRV); // Re-enable the Reflector renderer if (Reflector != null) { Reflector.Show = true; } }
protected override void DoRender(DeviceContext context) { // Calculate elapsed seconds var time = clock.ElapsedMilliseconds / 1000.0f; // Calculate skin matrices for each bone ConstantBuffers.PerArmature skinMatrices = new ConstantBuffers.PerArmature(); if (mesh.Bones != null) { // Retrieve each bone's local transform for (var i = 0; i < mesh.Bones.Count; i++) { skinMatrices.Bones[i] = mesh.Bones[i].BoneLocalTransform; } // Load bone transforms from animation frames if (CurrentAnimation.HasValue) { // Keep track of the last key-frame used for each bone Mesh.Keyframe?[] lastKeyForBones = new Mesh.Keyframe?[mesh.Bones.Count]; // Keep track of whether a bone has been interpolated bool[] lerpedBones = new bool[mesh.Bones.Count]; for (var i = 0; i < CurrentAnimation.Value.Keyframes.Count; i++) { // Retrieve current key-frame var frame = CurrentAnimation.Value.Keyframes[i]; // If the current frame is not in the future if (frame.Time <= time) { // Keep track of last key-frame for bone lastKeyForBones[frame.BoneIndex] = frame; // Retrieve transform from current key-frame skinMatrices.Bones[frame.BoneIndex] = frame.Transform; } // Frame is in the future, check if we should interpolate else { // Only interpolate a bone's key-frames ONCE if (!lerpedBones[frame.BoneIndex]) { // Retrieve the previous key-frame if exists Mesh.Keyframe prevFrame; if (lastKeyForBones[frame.BoneIndex] != null) prevFrame = lastKeyForBones[frame.BoneIndex].Value; else continue; // nothing to interpolate // Make sure we only interpolate with // one future frame for this bone lerpedBones[frame.BoneIndex] = true; // Calculate time difference between frames var frameLength = frame.Time - prevFrame.Time; var timeDiff = time - prevFrame.Time; var amount = timeDiff / frameLength; // Interpolation using Lerp on scale and translation, and Slerp on Rotation (Quaternion) Vector3 t1, t2; // Translation Quaternion q1, q2;// Rotation float s1, s2; // Scale // Decompose the previous key-frame's transform prevFrame.Transform.DecomposeUniformScale(out s1, out q1, out t1); // Decompose the current key-frame's transform frame.Transform.DecomposeUniformScale(out s2, out q2, out t2); // Perform interpolation and reconstitute matrix skinMatrices.Bones[frame.BoneIndex] = Matrix.Scaling(MathUtil.Lerp(s1, s2, amount)) * Matrix.RotationQuaternion(Quaternion.Slerp(q1, q2, amount)) * Matrix.Translation(Vector3.Lerp(t1, t2, amount)); } } } } // Apply parent bone transforms // We assume here that the first bone has no parent // and that each parent bone appears before children for (var i = 1; i < mesh.Bones.Count; i++) { var bone = mesh.Bones[i]; if (bone.ParentIndex > -1) { var parentTransform = skinMatrices.Bones[bone.ParentIndex]; skinMatrices.Bones[i] = (skinMatrices.Bones[i] * parentTransform); } } // Change the bone transform from rest pose space into bone space (using the inverse of the bind/rest pose) for (var i = 0; i < mesh.Bones.Count; i++) { skinMatrices.Bones[i] = Matrix.Transpose(mesh.Bones[i].InvBindPose * skinMatrices.Bones[i]); } // Check need to loop animation if (!PlayOnce && CurrentAnimation.HasValue && CurrentAnimation.Value.EndTime <= time) { this.Clock.Restart(); } } // Update the constant buffer with the skin matrices for each bone context.UpdateSubresource(skinMatrices.Bones, PerArmatureBuffer); // Draw sub-meshes grouped by material for (var mIndx = 0; mIndx < mesh.Materials.Count; mIndx++) { // Retrieve sub meshes for this material var subMeshesForMaterial = (from sm in mesh.SubMeshes where sm.MaterialIndex == mIndx select sm).ToArray(); // If the material buffer is available and there are submeshes // using the material update the PerMaterialBuffer if (PerMaterialBuffer != null && subMeshesForMaterial.Length > 0) { // update the PerMaterialBuffer constant buffer var material = new ConstantBuffers.PerMaterial() { Ambient = new Color4(mesh.Materials[mIndx].Ambient), Diffuse = new Color4(mesh.Materials[mIndx].Diffuse), Emissive = new Color4(mesh.Materials[mIndx].Emissive), Specular = new Color4(mesh.Materials[mIndx].Specular), SpecularPower = mesh.Materials[mIndx].SpecularPower, UVTransform = mesh.Materials[mIndx].UVTransform, }; // Bind textures to the pixel shader int texIndxOffset = mIndx * Common.Mesh.MaxTextures; material.HasTexture = (uint)(textureViews[texIndxOffset] != null ? 1 : 0); // 0=false context.PixelShader.SetShaderResources(0, textureViews.GetRange(texIndxOffset, Common.Mesh.MaxTextures).ToArray()); // Set texture sampler state context.PixelShader.SetSampler(0, samplerState); // If this mesh has a cube map assigned set // the material buffer accordingly if (this.EnvironmentMap != null) { material.IsReflective = 1; material.ReflectionAmount = 0.4f; context.PixelShader.SetShaderResource(1, this.EnvironmentMap.EnvMapSRV); } // Update material buffer context.UpdateSubresource(ref material, PerMaterialBuffer); } // For each sub-mesh foreach (var subMesh in subMeshesForMaterial) { // Ensure the vertex buffer and index buffers are in range if (subMesh.VertexBufferIndex < vertexBuffers.Count && subMesh.IndexBufferIndex < indexBuffers.Count) { // Retrieve and set the vertex and index buffers var vertexBuffer = vertexBuffers[(int)subMesh.VertexBufferIndex]; context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBuffer, Utilities.SizeOf<Vertex>(), 0)); context.InputAssembler.SetIndexBuffer(indexBuffers[(int)subMesh.IndexBufferIndex], Format.R16_UInt, 0); // Set topology context.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList; } // Draw the sub-mesh (includes Primitive count which we multiply by 3) // The submesh also includes a start index into the vertex buffer context.DrawIndexed((int)subMesh.PrimCount * 3, (int)subMesh.StartIndex, 0); } // Unbind the cubemap SRV if (this.EnvironmentMap != null) context.PixelShader.SetShaderResource(1, null); } }
/// <summary> /// Update the 6-sides of the cube map using a single pass via Geometry shader instancing with the provided context /// </summary> /// <param name="context">The context to render within</param> /// <param name="renderScene">The method that will render the scene</param> public void UpdateSinglePass(DeviceContext context, Action<DeviceContext, Matrix, Matrix, RenderTargetView, DepthStencilView, DualParaboloidMap> renderScene) { // Don't render the reflector itself if (Reflector != null) { Reflector.Show = false; } // Prepare pipeline context.OutputMerger.SetRenderTargets(EnvMapDSV, EnvMapRTV); context.Rasterizer.SetViewport(Viewport); // Update perCubeMap with the ViewProjections PerEnvMap pem = this.DualMapView; pem.View.Transpose(); // Must transpose the matrix for HLSL context.UpdateSubresource(ref pem, PerEnvMapBuffer); // Assign the per dual map buffer to the VS and PS stages at slot 4 context.VertexShader.SetConstantBuffer(4, PerEnvMapBuffer); context.PixelShader.SetConstantBuffer(4, PerEnvMapBuffer); // Render the scene using the view, projection, RTV and DSV // Note that we use an identity matrix for the projection! renderScene(context, this.DualMapView.View, Matrix.Identity, EnvMapRTV, EnvMapDSV, this); // Unbind the RTV and DSV context.OutputMerger.ResetTargets(); // Prepare the SRV mip levels context.GenerateMips(EnvMapSRV); // Re-enable the Reflector renderer if (Reflector != null) { Reflector.Show = true; } }