private void PrepareRenderMeshes(RenderModel renderModel, List <Mesh> meshes, ref FastListStruct <RenderMesh> renderMeshes, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Add new render meshes for (int i = renderMeshes.Count; i < meshes.Count; i++) { var renderMesh = new RenderMesh(renderModel, meshes[i]); renderMeshes.Add(renderMesh); } // Create the bounding frustum locally on the stack, so that frustum.Contains is performed with boundingBox that is also on the stack var frustum = new BoundingFrustum(ref ViewProjectionMatrix); var sceneCameraRenderer = Context.Tags.Get(SceneCameraRenderer.Current); var cullingMode = CullingModeOverride ?? (sceneCameraRenderer?.CullingMode ?? CameraCullingMode.None); for (int i = 0; i < renderMeshes.Count; i++) { var renderMesh = renderMeshes[i]; // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.ModelViewHierarchy; modelViewHierarchy.UpdateRenderMesh(renderMesh); if (!renderMesh.Enabled || !renderMesh.UpdateMaterial()) { continue; } // Upload skinning blend matrices BoundingBoxExt boundingBox; skinningUpdater.Update(modelViewHierarchy, renderMesh, out boundingBox); // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) // TODO: CameraCullingMode should be pluggable // TODO: This should not be necessary. Add proper bounding boxes to gizmos etc. if (cullingMode == CameraCullingMode.Frustum && boundingBox.Extent != Vector3.Zero && !frustum.Contains(ref boundingBox)) { continue; } // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(renderMesh.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref ViewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; renderMesh.RasterizerState = renderMesh.IsGeometryInverted ? RasterizerStateForInvertedGeometry : RasterizerState; renderMesh.ForceRasterizer = ForceRasterizer; var list = renderMesh.HasTransparency ? transparentList : opaqueList; list.Add(new RenderItem(this, renderMesh, projectedZ)); } }
/// <summary> /// Updates previously computed world matrices to TransformationKeys.World for each <see cref="RenderMesh" />. /// </summary> /// <param name="renderMesh">The render mesh.</param> internal void UpdateRenderMesh(RenderMesh renderMesh) { var nodeIndex = renderMesh.Mesh.NodeIndex; var enabled = nodeTransformations[nodeIndex].RenderingEnabledRecursive; renderMesh.Enabled = enabled; if (enabled && renderMesh.MatrixCounter != matrixCounter) { renderMesh.WorldMatrix = nodeTransformations[nodeIndex].WorldMatrix; renderMesh.IsGeometryInverted = nodeTransformations[nodeIndex].IsScalingNegative; renderMesh.MatrixCounter = matrixCounter; } }
public void Update(ModelViewHierarchyUpdater hierarchyUpdater, RenderMesh renderMesh, out BoundingBoxExt boundingBox) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) { // For unskinned meshes, use the original bounding box var boundingBoxExt = (BoundingBoxExt)mesh.BoundingBox; boundingBoxExt.Transform(renderMesh.WorldMatrix); boundingBox = boundingBoxExt; return; } var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (bones.Length > boneMatrices.Length) { boneMatrices = new Matrix[bones.Length]; } var bindPoseBoundingBox = new BoundingBoxExt(renderMesh.Mesh.BoundingBox); boundingBox = BoundingBoxExt.Empty; for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchyUpdater.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); // Calculate and extend bounding box for each bone // TODO: Move runtime bounding box into ModelViewHierarchyUpdater? // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) var boundingBoxExt = bindPoseBoundingBox; boundingBoxExt.Transform(boneMatrices[index]); BoundingBoxExt.Merge(ref boundingBox, ref boundingBoxExt, out boundingBox); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); }
public void Update(ModelViewHierarchyUpdater hierarchyUpdater, RenderMesh renderMesh, out BoundingBoxExt boundingBox) { var mesh = renderMesh.Mesh; var skinning = mesh.Skinning; if (skinning == null) { // For unskinned meshes, use the original bounding box var boundingBoxExt = (BoundingBoxExt)mesh.BoundingBox; boundingBoxExt.Transform(renderMesh.WorldMatrix); boundingBox = boundingBoxExt; return; } var bones = skinning.Bones; // Make sure there is enough spaces in boneMatrices if (bones.Length > boneMatrices.Length) boneMatrices = new Matrix[bones.Length]; var bindPoseBoundingBox = new BoundingBoxExt(renderMesh.Mesh.BoundingBox); boundingBox = BoundingBoxExt.Empty; for (int index = 0; index < bones.Length; index++) { var nodeIndex = bones[index].NodeIndex; // Compute bone matrix Matrix.Multiply(ref bones[index].LinkToMeshMatrix, ref hierarchyUpdater.NodeTransformations[nodeIndex].WorldMatrix, out boneMatrices[index]); // Calculate and extend bounding box for each bone // TODO: Move runtime bounding box into ModelViewHierarchyUpdater? // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) var boundingBoxExt = bindPoseBoundingBox; boundingBoxExt.Transform(boneMatrices[index]); BoundingBoxExt.Merge(ref boundingBox, ref boundingBoxExt, out boundingBox); } // Upload bones renderMesh.Parameters.Set(TransformationSkinningKeys.BlendMatrixArray, boneMatrices, 0, bones.Length); }
/// <summary> /// Create or update the Effect of the effect mesh. /// </summary> protected void UpdateEffect(RenderContext context, RenderMesh renderMesh, ParameterCollection passParameters) { if (dynamicEffectCompiler.Update(renderMesh, passParameters)) { try { renderMesh.Initialize(context.GraphicsDevice); } catch (Exception e) { Log.Error("Could not initialize RenderMesh, trying again with error fallback effect", e); // Try again with error effect to show user something failed with this model // TODO: What if an exception happens in this case too? Mark renderMesh as ignored or null? dynamicEffectCompiler.SwitchFallbackEffect(FallbackEffectType.Error, renderMesh, passParameters); renderMesh.Initialize(context.GraphicsDevice); } } }
private List <RenderMesh> PrepareModelForRendering(RenderContext context, RenderModel renderModel) { // Create the list of RenderMesh objects var renderMeshes = renderModel.RenderMeshesList[modelRenderSlot]; var modelMeshes = renderModel.ModelComponent.Model.Meshes; // If render mesh is new or the model changed, generate new render mesh if (renderMeshes == null || (renderMeshes.Count == 00 && modelMeshes.Count > 0)) { if (renderMeshes == null) { renderMeshes = new RenderMeshCollection(); renderModel.RenderMeshesList[modelRenderSlot] = renderMeshes; } foreach (var mesh in modelMeshes) { var renderMesh = new RenderMesh(renderModel, mesh); //UpdateEffect(context, renderMesh, null); // Register mesh for rendering renderMeshes.Add(renderMesh); } } // Update RenderModel transform if (!renderMeshes.TransformUpdated) { // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.ModelViewHierarchy; modelViewHierarchy.UpdateToRenderModel(renderModel, modelRenderSlot); // Upload skinning blend matrices MeshSkinningUpdater.Update(modelViewHierarchy, renderModel, modelRenderSlot); renderMeshes.TransformUpdated = true; } return(renderMeshes); }
private void PreRenderMesh(RenderContext context, RenderMesh renderMesh) { var contextParameters = context.Parameters; RenderModelLights renderModelLights; if (!modelToLights.TryGetValue(renderMesh.RenderModel, out renderModelLights)) { contextParameters.Set(LightingKeys.DirectLightGroups, null); contextParameters.Set(LightingKeys.EnvironmentLights, null); return; } // TODO: copy shadow receiver info to mesh var isShadowReceiver = renderMesh.IsShadowReceiver; if (currentModelLightShadersPermutationEntry != renderModelLights.LightShadersPermutation || currentModelShadersParameters != renderModelLights.Parameters || currentShadowReceiver != isShadowReceiver) { currentModelLightShadersPermutationEntry = renderModelLights.LightShadersPermutation; currentModelShadersParameters = renderModelLights.Parameters; currentShadowReceiver = isShadowReceiver; if (currentShadowReceiver) { currentModelShadersParameters.Parameters.CopySharedTo(contextParameters); } else { currentModelShadersParameters.ParametersNoShadows.CopySharedTo(contextParameters); } } }
/// <summary> /// Create or update the Effect of the effect mesh. /// </summary> protected void UpdateEffect(RenderContext context, RenderMesh renderMesh, ParameterCollection passParameters) { if (dynamicEffectCompiler.Update(renderMesh, passParameters)) { renderMesh.Initialize(context.GraphicsDevice); } }
private void PrepareRenderMeshes(RenderModel renderModel, List<Mesh> meshes, ref FastListStruct<RenderMesh> renderMeshes, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Add new render meshes for (int i = renderMeshes.Count; i < meshes.Count; i++) { var renderMesh = new RenderMesh(renderModel, meshes[i]); renderMeshes.Add(renderMesh); } // Create the bounding frustum locally on the stack, so that frustum.Contains is performed with boundingBox that is also on the stack var frustum = new BoundingFrustum(ref ViewProjectionMatrix); for (int i = 0; i < renderMeshes.Count; i++) { var renderMesh = renderMeshes[i]; // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.ModelViewHierarchy; modelViewHierarchy.UpdateRenderMesh(renderMesh); if (!renderMesh.Enabled) { continue; } // Upload skinning blend matrices BoundingBoxExt boundingBox; skinningUpdater.Update(modelViewHierarchy, renderMesh, out boundingBox); // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) // TODO: CullingMode should be pluggable // TODO: This should not be necessary. Add proper bounding boxes to gizmos etc. if (CullingMode == CullingMode.Frustum && boundingBox.Extent != Vector3.Zero && !frustum.Contains(ref boundingBox)) { continue; } // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(renderMesh.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref ViewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; renderMesh.RasterizerState = renderMesh.IsGeometryInverted ? RasterizerStateForInvertedGeometry : RasterizerState; renderMesh.UpdateMaterial(); var list = renderMesh.HasTransparency ? transparentList : opaqueList; list.Add(new RenderItem(this, renderMesh, projectedZ)); } }