private void DrawTransparentRenderGroups(GraphicsDevice device, ResourceFactory factory) { var alignment = device.UniformBufferMinOffsetAlignment; var modelBuffStride = 64u; var hostBuffStride = 1u; if (alignment > 64u) { hostBuffStride = alignment / 64u; modelBuffStride = alignment; } // // First sort the transparent render elements by distance to eye point (if not culled). // var drawOrderMap = new SortedList <float, List <Tuple <IRenderGroupState, RenderGroupElement, IPrimitiveSet, uint> > >(); drawOrderMap.Capacity = _cullVisitor.RenderElementCount; var transparentRenderGroupStates = _cullVisitor.TransparentRenderGroup.GetStateList(); var stateToUniformDict = new Dictionary <IRenderGroupState, Matrix4x4[]>(); foreach (var state in transparentRenderGroupStates) { var nDrawables = (uint)state.Elements.Count; var modelMatrixViewBuffer = new Matrix4x4[nDrawables * hostBuffStride]; // Iterate over all elements in this state for (var j = 0; j < nDrawables; ++j) { var renderElement = state.Elements[j]; modelMatrixViewBuffer[j * hostBuffStride] = state.Elements[j].ModelViewMatrix; // Iterate over all primitive sets in this state foreach (var pset in renderElement.PrimitiveSets) { var ctr = pset.GetBoundingBox().Center; // Compute distance eye point var modelView = renderElement.ModelViewMatrix; var ctr_w = Vector3.Transform(ctr, modelView); var dist = Vector3.Distance(ctr_w, Vector3.Zero); if (!drawOrderMap.TryGetValue(dist, out var renderList)) { renderList = new List <Tuple <IRenderGroupState, RenderGroupElement, IPrimitiveSet, uint> >(); drawOrderMap.Add(dist, renderList); } renderList.Add(Tuple.Create(state, renderElement, pset, (uint)j)); } } stateToUniformDict.Add(state, modelMatrixViewBuffer); } DeviceBuffer boundVertexBuffer = null; DeviceBuffer boundIndexBuffer = null; // Now draw transparent elements, back to front IRenderGroupState lastState = null; RenderGraph.RenderInfo ri = null; var currModelViewMatrix = Matrix4x4.Identity; foreach (var renderList in drawOrderMap.Reverse()) { foreach (var element in renderList.Value) { var state = element.Item1; if (null == lastState || state != lastState) { ri = state.GetPipelineAndResources(device, factory, _resourceLayout, Framebuffer); // Set this state's pipeline _commandList.SetPipeline(ri.Pipeline); _commandList.UpdateBuffer(ri.ModelViewBuffer, 0, stateToUniformDict[state]); // Set the resources _commandList.SetGraphicsResourceSet(0, _resourceSet); } uint offset = element.Item4 * modelBuffStride; // Set state-local resources _commandList.SetGraphicsResourceSet(1, ri.ResourceSet, 1, ref offset); var renderGroupElement = element.Item2; if (boundVertexBuffer != renderGroupElement.VertexBuffer) { // Set vertex buffer _commandList.SetVertexBuffer(0, renderGroupElement.VertexBuffer); boundVertexBuffer = renderGroupElement.VertexBuffer; } if (boundIndexBuffer != renderGroupElement.IndexBuffer) { // Set index buffer _commandList.SetIndexBuffer(renderGroupElement.IndexBuffer, IndexFormat.UInt32); boundIndexBuffer = renderGroupElement.IndexBuffer; } element.Item3.Draw(_commandList); lastState = state; } } }
/// <summary> /// Cull Visitor for billboard /// </summary> /// <param name="billboard"></param> public override void Apply(IBillboard billboard) { var bb = billboard.GetBoundingBox(); if (IsCulled(bb, ModelMatrixStack.Peek())) { return; } IPipelineState pso = null; // Node specific state if (billboard.HasPipelineState) { pso = billboard.PipelineState; } // Shared State else if (PipelineStateStack.Count != 0) { pso = PipelineStateStack.Peek(); } // Fallback else { pso = PipelineState.Create(); } var eyeLocal = GetEyeLocal(); var modelView = GetModelViewMatrix(); foreach (var drawable in billboard.Drawables) { // TODO - need to modify is culled to handle billboard matrix offset //if (IsCulled(drawable.GetBoundingBox(), ModelMatrixStack.Peek())) continue; var billboardMatrix = billboard.ComputeMatrix(modelView, eyeLocal); var drawablePso = pso; if (drawable.HasPipelineState) { drawablePso = drawable.PipelineState; } // // This allocates / updates vbo/ibos // drawable.ConfigureDeviceBuffers(GraphicsDevice, ResourceFactory); var renderElementCache = new Dictionary <IRenderGroupState, RenderGroupElement>(); foreach (var pset in drawable.PrimitiveSets) { // TODO - need to modify is culled to handle billboard matrix offset //if (IsCulled(pset.GetBoundingBox(), ModelMatrixStack.Peek())) continue; // // Sort into appropriate render group // IRenderGroupState renderGroupState = null; if (drawablePso.BlendStateDescription.AttachmentStates.Contains(BlendAttachmentDescription.AlphaBlend)) { renderGroupState = TransparentRenderGroup.GetOrCreateState(drawablePso, pset.PrimitiveTopology, drawable.VertexLayout); } else { renderGroupState = OpaqueRenderGroup.GetOrCreateState(drawablePso, pset.PrimitiveTopology, drawable.VertexLayout); } if (false == renderElementCache.TryGetValue(renderGroupState, out var renderElement)) { renderElement = new RenderGroupElement() { ModelViewMatrix = billboardMatrix.PostMultiply(modelView), VertexBuffer = drawable.GetVertexBufferForDevice(GraphicsDevice), IndexBuffer = drawable.GetIndexBufferForDevice(GraphicsDevice), PrimitiveSets = new List <IPrimitiveSet>() }; renderGroupState.Elements.Add(renderElement); renderElementCache.Add(renderGroupState, renderElement); } renderElement.PrimitiveSets.Add(pset); } } }
private void DrawTransparentRenderGroups(GraphicsDevice device, ResourceFactory factory) { // // First sort the transparent render elements by distance to eye point (if not culled). // var drawOrderMap = new SortedList <float, List <Tuple <IRenderGroupState, RenderGroupElement, IPrimitiveSet> > >(); drawOrderMap.Capacity = _cullVisitor.RenderElementCount; var transparentRenderGroupStates = _cullVisitor.TransparentRenderGroup.GetStateList(); foreach (var state in transparentRenderGroupStates) { // Iterate over all elements in this state foreach (var renderElement in state.Elements) { // Iterate over all primitive sets in this state foreach (var pset in renderElement.PrimitiveSets) { var ctr = pset.GetBoundingBox().Center; // Compute distance eye point var modelView = renderElement.ModelViewMatrix; var ctr_w = Vector3.Transform(ctr, modelView); var dist = Vector3.Distance(ctr_w, Vector3.Zero); if (!drawOrderMap.TryGetValue(dist, out var renderList)) { renderList = new List <Tuple <IRenderGroupState, RenderGroupElement, IPrimitiveSet> >(); drawOrderMap.Add(dist, renderList); } renderList.Add(Tuple.Create(state, renderElement, pset)); } } } DeviceBuffer boundVertexBuffer = null; DeviceBuffer boundIndexBuffer = null; // Now draw transparent elements, back to front IRenderGroupState lastState = null; RenderGraph.RenderInfo ri = null; var currModelViewMatrix = Matrix4x4.Identity; foreach (var renderList in drawOrderMap.Reverse()) { foreach (var element in renderList.Value) { var state = element.Item1; if (null == lastState || state != lastState) { ri = state.GetPipelineAndResources(device, factory, _resourceLayout); // Set this state's pipeline _commandList.SetPipeline(ri.Pipeline); // Set the resources _commandList.SetGraphicsResourceSet(0, _resourceSet); // Set state-local resources _commandList.SetGraphicsResourceSet(1, ri.ResourceSet); } if (element.Item2.ModelViewMatrix != currModelViewMatrix) { _commandList.UpdateBuffer(ri.ModelViewBuffer, 0, element.Item2.ModelViewMatrix); currModelViewMatrix = element.Item2.ModelViewMatrix; } var renderGroupElement = element.Item2; if (boundVertexBuffer != renderGroupElement.VertexBuffer) { // Set vertex buffer _commandList.SetVertexBuffer(0, renderGroupElement.VertexBuffer); boundVertexBuffer = renderGroupElement.VertexBuffer; } if (boundIndexBuffer != renderGroupElement.IndexBuffer) { // Set index buffer _commandList.SetIndexBuffer(renderGroupElement.IndexBuffer, IndexFormat.UInt16); boundIndexBuffer = renderGroupElement.IndexBuffer; } element.Item3.Draw(_commandList); lastState = state; } } }