/// <inheritdoc/> public override unsafe void Prepare(RenderDrawContext context) { // Reset pipeline states if necessary for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.ParticleEmitter.VertexBuilder.IsBufferDirty) { // Reset pipeline state, so input layout is regenerated if (renderNode.RenderEffect != null) { renderNode.RenderEffect.PipelineState = null; } } } foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; renderParticleEmitter.ParticleEmitter.PrepareForDraw(); var materialInfo = (ParticleMaterialInfo)renderParticleEmitter.ParticleMaterialInfo; // Handle vertex element changes if (renderParticleEmitter.ParticleEmitter.VertexBuilder.IsBufferDirty) { // Create new buffers renderParticleEmitter.ParticleEmitter.VertexBuilder.RecreateBuffers(RenderSystem.GraphicsDevice); } // TODO: ParticleMaterial should set this up materialInfo?.Material.Parameters.Set(ParticleBaseKeys.ColorScale, renderParticleEmitter.RenderParticleSystem.ParticleSystemComponent.Color); } base.Prepare(context); // Assign descriptor sets to each render node var resourceGroupPool = ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; var materialParameters = material.Parameters; if (!MaterialRenderFeature.UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } // Per view // TODO: Transform sub render feature? for (int index = 0; index < RenderSystem.Views.Count; index++) { var view = RenderSystem.Views[index]; var viewFeature = view.Features[Index]; // TODO GRAPHICS REFACTOR: Happens in several places Matrix.Multiply(ref view.View, ref view.Projection, out view.ViewProjection); // Copy ViewProjection to PerFrame cbuffer foreach (var viewLayout in viewFeature.Layouts) { var viewProjectionOffset = viewLayout.GetConstantBufferOffset(this.view); if (viewProjectionOffset == -1) { continue; } var resourceGroup = viewLayout.Entries[view.Index].Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; var perView = (Matrix *)((byte *)mappedCB + viewProjectionOffset); * perView = view.ViewProjection; } } }
/// <inheritdoc/> public override unsafe void Prepare(RenderDrawContext context) { // Inspect each RenderObject (= ParticleEmitter) to determine if its required vertex buffer size has changed foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; renderParticleEmitter.ParticleEmitter.PrepareForDraw(out renderParticleEmitter.HasVertexBufferChanged, out renderParticleEmitter.VertexSize, out renderParticleEmitter.VertexCount); // TODO: ParticleMaterial should set this up var materialInfo = (ParticleMaterialInfo)renderParticleEmitter.ParticleMaterialInfo; var colorShade = renderParticleEmitter.Color.ToColorSpace(context.GraphicsDevice.ColorSpace); materialInfo?.Material.Parameters.Set(ParticleBaseKeys.ColorScale, colorShade); } // Calculate the total vertex buffer size required int totalVertexBufferSize = 0; int highestIndexCount = 0; var renderParticleNodeData = RenderData.GetData(renderParticleNodeKey); // Reset pipeline states if necessary for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.HasVertexBufferChanged) { // Reset pipeline state, so input layout is regenerated if (renderNode.RenderEffect != null) { renderNode.RenderEffect.PipelineState = null; } } // Write some attributes back which we will need for rendering later var vertexBuilder = renderParticleEmitter.ParticleEmitter.VertexBuilder; var newNodeData = new RenderAttributesPerNode { VertexBufferOffset = totalVertexBufferSize, VertexBufferSize = renderParticleEmitter.VertexSize * renderParticleEmitter.VertexCount, VertexBufferStride = renderParticleEmitter.VertexSize, IndexCount = vertexBuilder.LivingQuads * vertexBuilder.IndicesPerQuad, }; renderParticleNodeData[new RenderNodeReference(renderNodeIndex)] = newNodeData; totalVertexBufferSize += newNodeData.VertexBufferSize; if (newNodeData.IndexCount > highestIndexCount) { highestIndexCount = newNodeData.IndexCount; } } base.Prepare(context); // Assign descriptor sets to each render node var resourceGroupPool = ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; var materialParameters = material.Parameters; if (!MaterialRenderFeature.UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } particleBufferContext.AllocateBuffers(context, totalVertexBufferSize, highestIndexCount); BuildParticleBuffers(context); }
/// <inheritdoc/> public override unsafe void Prepare(RenderDrawContext context) { // Inspect each RenderObject (= ParticleEmitter) to determine if its required vertex buffer size has changed foreach (var renderObject in RenderObjects) { var renderParticleEmitter = (RenderParticleEmitter)renderObject; renderParticleEmitter.ParticleEmitter.PrepareForDraw(out renderParticleEmitter.HasVertexBufferChanged, out renderParticleEmitter.VertexSize, out renderParticleEmitter.VertexCount); // TODO: ParticleMaterial should set this up var materialInfo = (ParticleMaterialInfo)renderParticleEmitter.ParticleMaterialInfo; materialInfo?.Material.Parameters.Set(ParticleBaseKeys.ColorScale, renderParticleEmitter.RenderParticleSystem.ParticleSystemComponent.Color); } // Calculate the total vertex buffer size required int totalVertexBufferSize = 0; int highestIndexCount = 0; var renderParticleNodeData = RenderData.GetData(renderParticleNodeKey); // Reset pipeline states if necessary for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; if (renderParticleEmitter.HasVertexBufferChanged) { // Reset pipeline state, so input layout is regenerated if (renderNode.RenderEffect != null) { renderNode.RenderEffect.PipelineState = null; } } // Write some attributes back which we will need for rendering later var vertexBuilder = renderParticleEmitter.ParticleEmitter.VertexBuilder; var newNodeData = new RenderAttributesPerNode { VertexBufferOffset = totalVertexBufferSize, VertexBufferSize = renderParticleEmitter.VertexSize * renderParticleEmitter.VertexCount, VertexBufferStride = renderParticleEmitter.VertexSize, IndexCount = vertexBuilder.LivingQuads * vertexBuilder.IndicesPerQuad, }; renderParticleNodeData[new RenderNodeReference(renderNodeIndex)] = newNodeData; totalVertexBufferSize += newNodeData.VertexBufferSize; if (newNodeData.IndexCount > highestIndexCount) { highestIndexCount = newNodeData.IndexCount; } } base.Prepare(context); // Assign descriptor sets to each render node var resourceGroupPool = ResourceGroupPool; for (int renderNodeIndex = 0; renderNodeIndex < RenderNodes.Count; renderNodeIndex++) { var renderNodeReference = new RenderNodeReference(renderNodeIndex); var renderNode = RenderNodes[renderNodeIndex]; var renderParticleEmitter = (RenderParticleEmitter)renderNode.RenderObject; // Ignore fallback effects if (renderNode.RenderEffect.State != RenderEffectState.Normal) { continue; } // Collect materials and create associated MaterialInfo (includes reflection) first time // TODO: We assume same material will generate same ResourceGroup (i.e. same resources declared in same order) // Need to offer some protection if this invariant is violated (or support it if it can actually happen in real scenario) var material = renderParticleEmitter.ParticleEmitter.Material; var materialInfo = renderParticleEmitter.ParticleMaterialInfo; var materialParameters = material.Parameters; if (!MaterialRenderFeature.UpdateMaterial(RenderSystem, context, materialInfo, perMaterialDescriptorSetSlot.Index, renderNode.RenderEffect, materialParameters)) { continue; } var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference); resourceGroupPool[descriptorSetPoolOffset + perMaterialDescriptorSetSlot.Index] = materialInfo.Resources; } // Per view // TODO: Transform sub render feature? for (int index = 0; index < RenderSystem.Views.Count; index++) { var view = RenderSystem.Views[index]; var viewFeature = view.Features[Index]; // TODO GRAPHICS REFACTOR: Happens in several places Matrix.Multiply(ref view.View, ref view.Projection, out view.ViewProjection); // Copy ViewProjection to PerFrame cbuffer foreach (var viewLayout in viewFeature.Layouts) { var resourceGroup = viewLayout.Entries[view.Index].Resources; var mappedCB = resourceGroup.ConstantBuffer.Data; // PerView constant buffer var perViewOffset = viewLayout.GetConstantBufferOffset(this.perViewCBufferOffset); if (perViewOffset != -1) { var perView = (ParticleUtilitiesPerView *)((byte *)mappedCB + perViewOffset); perView->ViewMatrix = view.View; perView->ProjectionMatrix = view.Projection; perView->ViewProjectionMatrix = view.ViewProjection; perView->ViewFrustum = new Vector4(view.ViewSize.X, view.ViewSize.Y, view.NearClipPlane, view.FarClipPlane); } } } particleBufferContext.AllocateBuffers(context, totalVertexBufferSize, highestIndexCount); BuildParticleBuffers(context); }