コード例 #1
0
            public void Build(CommandList commandList, LightSpot lightSpot)
            {
                int[] indices;

                if (lightSpot.ProjectiveTexture != null)    // If no projection texture has been supplied, we render the regular cone:
                {
                    indices      = BuildRectangleIndexBuffer();
                    vertexBuffer = Buffer.Vertex.New(graphicsDevice, new VertexPositionNormalTexture[9], GraphicsResourceUsage.Dynamic);
                    RebuildRectangleVertexBuffer(commandList, lightSpot);
                }
                else    // If a projection texture has been supplied, we render a rectangular frustum instead:
                {
                    indices      = BuildConeIndexBuffer();
                    vertexBuffer = Buffer.Vertex.New(graphicsDevice, new VertexPositionNormalTexture[4 * Tesselation + 1], GraphicsResourceUsage.Dynamic);
                    RebuildConeVertexBuffer(commandList, lightSpot);
                }

                MeshDraw = new MeshDraw
                {
                    PrimitiveType = PrimitiveType.LineList,
                    DrawCount     = indices.Length,
                    IndexBuffer   = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices), true, indices.Length),
                    VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, VertexPositionNormalTexture.Layout, vertexBuffer.ElementCount) },
                };
            }
コード例 #2
0
            public void Build(CommandList commandList, CameraParameters parameters)
            {
                var indices = new []
                {
                    0, 1,
                    1, 2,
                    2, 3,
                    3, 0,

                    4, 5,
                    5, 6,
                    6, 7,
                    7, 4,

                    0, 4,
                    1, 5,
                    2, 6,
                    3, 7
                };

                vertexBuffer = Buffer.Vertex.New(graphicsDevice, new VertexPositionNormalTexture[8], GraphicsResourceUsage.Dynamic);
                RebuildVertexBuffer(commandList, parameters);

                MeshDraw = new MeshDraw
                {
                    PrimitiveType = PrimitiveType.LineList,
                    DrawCount     = indices.Length,
                    IndexBuffer   = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices), true, indices.Length),
                    VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, VertexPositionNormalTexture.Layout, vertexBuffer.ElementCount) },
                };
            }
コード例 #3
0
        private void InitEntity(Color color, GraphicsDevice graphicsDevice)
        {
            vertexBuffer = Buffer.Vertex.New(this.graphicsDevice, vertexArray, GraphicsResourceUsage.Dynamic);
            indexBuffer  = Buffer.Index.New(this.graphicsDevice, indexArray, GraphicsResourceUsage.Dynamic);

            var model = new Model
            {
                Meshes =
                {
                    new Mesh {
                        Draw = new MeshDraw
                        {
                            PrimitiveType = PrimitiveType.LineList,
                            VertexBuffers = new[]{
                                new VertexBufferBinding(vertexBuffer,
                                                        VertexPositionColorTexture.Layout,
                                                        vertexArray.Length * VertexPositionColorTexture.Layout.CalculateSize())
                            },
                            IndexBuffer = new IndexBufferBinding(indexBuffer, true, indexArray.Length * sizeof(int)),
                            DrawCount   = vertexArray.Length
                        }
                    }
                }, Materials = { Materials.CreateDebugMaterial(color, true, graphicsDevice) }
            };

            Entity = new Entity
            {
                Name       = color.ToString(),
                Components = { new ModelComponent(model) }
            };
        }
コード例 #4
0
 public void ReleaseBuffers(RenderDrawContext renderDrawContext)
 {
     // Release the temporary vertex buffer
     if (VertexBuffer != null)
     {
         renderDrawContext.GraphicsContext.Allocator.ReleaseReference(VertexBuffer);
         VertexBuffer = null;
     }
 }
コード例 #5
0
        public static bool DisposeBufferBySpecs(Stride.Graphics.Buffer buf, int count)
        {
            if (buf == null || buf.ElementCount != count)
            {
                if (buf != null)
                {
                    buf.Dispose();
                }

                return(true);
            }
            return(false);
        }
コード例 #6
0
        public void UpdateTempStorage(VoxelStorageContext context)
        {
            storageUints       = (tempStorageCounter + 31) / 32;
            tempStorageCounter = 0;

            var resolution = ClipMapResolution;
            int fragments  = (int)(resolution.X * resolution.Y * resolution.Z) * ClipMapCount;

            if (VoxelUtils.DisposeBufferBySpecs(FragmentsBuffer, storageUints * fragments) && storageUints * fragments > 0)
            {
                FragmentsBuffer = Stride.Graphics.Buffer.Typed.New(context.device, storageUints * fragments, PixelFormat.R32_UInt, true);
            }
        }
コード例 #7
0
            public void Build()
            {
                var indices  = new int[2 * Tesselation * 3];
                var vertices = new VertexPositionNormalTexture[(Tesselation + 1) * 3];

                int indexCount  = 0;
                int vertexCount = 0;

                // the two rings
                for (int j = 0; j < 3; j++)
                {
                    var rotation = Matrix.Identity;
                    if (j == 1)
                    {
                        rotation = Matrix.RotationX(MathF.PI / 2);
                    }
                    else if (j == 2)
                    {
                        rotation = Matrix.RotationY(MathF.PI / 2);
                    }

                    for (int i = 0; i <= Tesselation; i++)
                    {
                        var longitude = (float)(i * 2.0 * Math.PI / Tesselation);
                        var dx        = MathF.Cos(longitude);
                        var dy        = MathF.Sin(longitude);

                        var normal = new Vector3(dx, dy, 0);
                        Vector3.TransformNormal(ref normal, ref rotation, out normal);

                        if (i < Tesselation)
                        {
                            indices[indexCount++] = vertexCount;
                            indices[indexCount++] = vertexCount + 1;
                        }

                        vertices[vertexCount++] = new VertexPositionNormalTexture(normal, normal, new Vector2(0));
                    }
                }

                vertexBuffer = Buffer.Vertex.New(graphicsDevice, vertices);
                MeshDraw     = new MeshDraw
                {
                    PrimitiveType = PrimitiveType.LineList,
                    DrawCount     = indices.Length,
                    IndexBuffer   = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices), true, indices.Length),
                    VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, VertexPositionNormalTexture.Layout, vertexBuffer.ElementCount) },
                };
            }
コード例 #8
0
ファイル: MeshRenderFeature.cs プロジェクト: vvvv/stride
        /// <inheritdoc/>
        protected override void InitializeCore()
        {
            base.InitializeCore();

            RenderFeatures.CollectionChanged += RenderFeatures_CollectionChanged;

            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.AttachRootRenderFeature(this);
                renderFeature.Initialize(Context);
            }

            // Create an empty buffer to compensate for missing vertex streams
            emptyBuffer = Buffer.Vertex.New(Context.GraphicsDevice, new Vector4[1]);
        }
コード例 #9
0
ファイル: MeshRenderFeature.cs プロジェクト: vvvv/stride
        protected override void Destroy()
        {
            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.Dispose();
            }

            RenderFeatures.CollectionChanged -= RenderFeatures_CollectionChanged;

            descriptorSets.Dispose();

            emptyBuffer?.Dispose();
            emptyBuffer = null;

            base.Destroy();
        }
コード例 #10
0
ファイル: IndexExtensions.cs プロジェクト: vvvv/stride
        private static byte[] GetDataSafe(this Buffer buffer, CommandList commandList = null)
        {
            var data = buffer.GetSerializationData();

            if (data != null)
            {
                return(data.Content);
            }

            if (commandList == null)
            {
                throw new InvalidOperationException("Could not find underlying CPU buffer data and no command list was given to extract them from GPU");
            }

            return(buffer.GetData <byte>(commandList));
        }
コード例 #11
0
        public override void Unload()
        {
            // Dispose GPU resources
            lightClusters?.Dispose();
            lightClusters = null;

            lightIndicesBuffer?.Dispose();
            lightIndicesBuffer = null;

            pointLightsBuffer?.Dispose();
            pointLightsBuffer = null;

            spotLightsBuffer?.Dispose();
            spotLightsBuffer = null;

            base.Unload();
        }
コード例 #12
0
            public void Build()
            {
                var indices  = new int[12 * 2];
                var vertices = new VertexPositionNormalTexture[8];

                vertices[0] = new VertexPositionNormalTexture(new Vector3(-1, 1, -1), Vector3.UnitY, Vector2.Zero);
                vertices[1] = new VertexPositionNormalTexture(new Vector3(-1, 1, 1), Vector3.UnitY, Vector2.Zero);
                vertices[2] = new VertexPositionNormalTexture(new Vector3(1, 1, 1), Vector3.UnitY, Vector2.Zero);
                vertices[3] = new VertexPositionNormalTexture(new Vector3(1, 1, -1), Vector3.UnitY, Vector2.Zero);

                int indexOffset = 0;

                // Top sides
                for (int i = 0; i < 4; i++)
                {
                    indices[indexOffset++] = i;
                    indices[indexOffset++] = (i + 1) % 4;
                }

                // Duplicate vertices and indices to bottom part
                for (int i = 0; i < 4; i++)
                {
                    vertices[i + 4]            = vertices[i];
                    vertices[i + 4].Position.Y = -vertices[i + 4].Position.Y;

                    indices[indexOffset++] = indices[i * 2] + 4;
                    indices[indexOffset++] = indices[i * 2 + 1] + 4;
                }

                // Sides
                for (int i = 0; i < 4; i++)
                {
                    indices[indexOffset++] = i;
                    indices[indexOffset++] = i + 4;
                }

                vertexBuffer = Buffer.Vertex.New(graphicsDevice, vertices);
                MeshDraw     = new MeshDraw
                {
                    PrimitiveType = PrimitiveType.LineList,
                    DrawCount     = indices.Length,
                    IndexBuffer   = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices), true, indices.Length),
                    VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, VertexPositionNormalTexture.Layout, vertexBuffer.ElementCount) },
                };
            }
        // TODO: make this more easy and clear, improve instancing component to support this better
        protected override void ManageInstancingData()
        {
            var transformUsage = (ModelTransformUsage)(((int)Game.UpdateTime.Total.TotalSeconds) % 3);

            instancingUserBuffer.ModelTransformUsage = ModelTransformUsage.PostMultiply;
            instancingUserBuffer.InstanceCount       = instanceWorldTransformations.Length;

            // Make sure inverse matrices are big enough
            if (worldInverseTransformations.Length != instanceWorldTransformations.Length)
            {
                worldInverseTransformations = new Matrix[instanceWorldTransformations.Length];
            }

            // Invert matrices and update bounding box
            var ibb = BoundingBox.Empty;

            for (int i = 0; i < instanceWorldTransformations.Length; i++)
            {
                Matrix.Invert(ref instanceWorldTransformations[i], out worldInverseTransformations[i]);
                var pos = instanceWorldTransformations[i].TranslationVector;
                BoundingBox.Merge(ref ibb, ref pos, out ibb);
            }

            instancingUserBuffer.BoundingBox = ibb;

            // Manage buffers
            if (InstanceWorldBuffer == null || InstanceWorldBuffer.ElementCount < instancingUserBuffer.InstanceCount)
            {
                InstanceWorldBuffer?.Dispose();
                InstanceWorldInverseBuffer?.Dispose();

                InstanceWorldBuffer = CreateMatrixBuffer(GraphicsDevice, instancingUserBuffer.InstanceCount);
                instancingUserBuffer.InstanceWorldBuffer = InstanceWorldBuffer;

                InstanceWorldInverseBuffer = CreateMatrixBuffer(GraphicsDevice, instancingUserBuffer.InstanceCount);
                instancingUserBuffer.InstanceWorldInverseBuffer = InstanceWorldInverseBuffer;
            }

            instancingUserBuffer.InstanceWorldBuffer.SetData(Game.GraphicsContext.CommandList, instanceWorldTransformations);
            instancingUserBuffer.InstanceWorldInverseBuffer.SetData(Game.GraphicsContext.CommandList, worldInverseTransformations);
        }
コード例 #14
0
            public unsafe void AllocateBuffers(RenderDrawContext renderDrawContext, int vertexBufferSize, int requiredIndexCount)
            {
                // Build the shared vertex buffer - every frame
                if (vertexBufferSize > 0)
                {
                    {
                        vertexBufferSize--;
                        vertexBufferSize |= vertexBufferSize >> 1;
                        vertexBufferSize |= vertexBufferSize >> 2;
                        vertexBufferSize |= vertexBufferSize >> 3;
                        vertexBufferSize |= vertexBufferSize >> 8;
                        vertexBufferSize |= vertexBufferSize >> 16;
                        vertexBufferSize++;
                    }

                    VertexBufferSize = vertexBufferSize;

                    VertexBuffer = renderDrawContext.GraphicsContext.Allocator.GetTemporaryBuffer(
                        new BufferDescription(VertexBufferSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic));
                }

                // Build the shared index buffer - only when necessary
                var requiredIndexBufferSize = requiredIndexCount * IndexStride;

                if (requiredIndexBufferSize > IndexBufferSize)
                {
                    if (IndexBuffer != null)
                    {
                        renderDrawContext.GraphicsContext.Allocator.ReleaseReference(IndexBuffer);
                        IndexBuffer = null;
                    }

                    //  We start allocating from 64K (allowing 32K indices to be written at once - this is most probably going to be sufficient in all cases)
                    IndexBufferSize = requiredIndexBufferSize;
                    if (IndexBufferSize < 64 * 1024)
                    {
                        IndexBufferSize = 64 * 1024;
                    }

                    {
                        IndexBufferSize--;
                        IndexBufferSize |= IndexBufferSize >> 1;
                        IndexBufferSize |= IndexBufferSize >> 2;
                        IndexBufferSize |= IndexBufferSize >> 3;
                        IndexBufferSize |= IndexBufferSize >> 8;
                        IndexBufferSize |= IndexBufferSize >> 16;
                        IndexBufferSize++;
                    }

                    IndexBuffer = renderDrawContext.GraphicsContext.Allocator.GetTemporaryBuffer(
                        new BufferDescription(IndexBufferSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic));

                    var indexCount = IndexBufferSize / IndexStride;
                    indexCount = ((indexCount / 6) * 6);
                    {
                        var commandList = renderDrawContext.CommandList;

                        var mappedIndices = commandList.MapSubresource(IndexBuffer, 0, MapMode.WriteNoOverwrite, false, 0, IndexBufferSize);
                        var indexPointer  = mappedIndices.DataBox.DataPointer;

                        int indexStructSize = sizeof(short);
                        int verticesPerQuad = 4;

                        var k = 0;
                        for (var i = 0; i < indexCount; k += verticesPerQuad)
                        {
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 0);
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 1);
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 2);
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 0);
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 2);
                            *(short *)(indexPointer + indexStructSize * i++) = (short)(k + 3);
                        }

                        commandList.UnmapSubresource(mappedIndices);
                    }
                }
            }
        private unsafe Mesh ConvertToMesh(GraphicsDevice graphicsDevice, PrimitiveType primitiveType, LightProbeRuntimeData lightProbeRuntimeData)
        {
            // Generate data for vertex buffer
            var vertices = new VertexPositionNormalColor[lightProbeRuntimeData.LightProbes.Length];

            for (var i = 0; i < lightProbeRuntimeData.LightProbes.Length; i++)
            {
                vertices[i] = new VertexPositionNormalColor(lightProbeRuntimeData.Vertices[i], Vector3.Zero, Color.White);
            }

            // Generate data for index buffer
            var indices = new int[lightProbeRuntimeData.Faces.Count * 6];

            for (var i = 0; i < lightProbeRuntimeData.Faces.Count; ++i)
            {
                var currentFace = lightProbeRuntimeData.Faces[i];

                // Skip infinite edges to not clutter display
                // Maybe we could reenable it when we have better infinite nodes
                if (currentFace.Vertices[0] >= lightProbeRuntimeData.UserVertexCount ||
                    currentFace.Vertices[1] >= lightProbeRuntimeData.UserVertexCount ||
                    currentFace.Vertices[2] >= lightProbeRuntimeData.UserVertexCount)
                {
                    continue;
                }

                indices[i * 6 + 0] = currentFace.Vertices[0];
                indices[i * 6 + 1] = currentFace.Vertices[1];
                indices[i * 6 + 2] = currentFace.Vertices[1];
                indices[i * 6 + 3] = currentFace.Vertices[2];
                indices[i * 6 + 4] = currentFace.Vertices[2];
                indices[i * 6 + 5] = currentFace.Vertices[0];
            }

            var boundingBox = BoundingBox.Empty;

            for (int i = 0; i < vertices.Length; i++)
            {
                BoundingBox.Merge(ref boundingBox, ref vertices[i].Position, out boundingBox);
            }

            // Compute bounding sphere
            BoundingSphere boundingSphere;

            fixed(void *verticesPtr = vertices)
            BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere);

            var layout = vertices[0].GetLayout();

            var meshDraw = new MeshDraw
            {
                IndexBuffer   = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices).RecreateWith(indices), true, indices.Length),
                VertexBuffers = new[] { new VertexBufferBinding(Buffer.New(graphicsDevice, vertices, BufferFlags.VertexBuffer).RecreateWith(vertices), layout, vertices.Length) },
                DrawCount     = indices.Length,
                PrimitiveType = primitiveType,
            };

            wireframeResources.Add(meshDraw.VertexBuffers[0].Buffer);
            wireframeResources.Add(meshDraw.IndexBuffer.Buffer);

            return(new Mesh {
                Draw = meshDraw, BoundingBox = boundingBox, BoundingSphere = boundingSphere
            });
        }
コード例 #16
0
 private static Buffer <Matrix> CreateMatrixBuffer(GraphicsDevice graphicsDevice, int elementCount)
 {
     return(Buffer.New <Matrix>(graphicsDevice, elementCount, BufferFlags.ShaderResource | BufferFlags.StructuredBuffer, GraphicsResourceUsage.Dynamic));
 }
コード例 #17
0
        /// <summary>
        /// Bake lightprobes into buffers compatible with <see cref="LightProbeRenderer"/>
        /// </summary>
        /// <param name="drawContext">The drawing context</param>
        private unsafe void BakeLightProbes(RenderContext context, RenderDrawContext drawContext)
        {
            Texture ibl = null;
            Buffer  tetrahedronProbeIndices = null;
            Buffer  tetrahedronMatrices     = null;
            Buffer  lightprobesCoefficients = null;
            var     renderView = context.RenderView;

            var lightProbesData = context.VisibilityGroup.Tags.Get(LightProbeRenderer.CurrentLightProbes);

            if (lightProbesData == null || lightProbesData.Tetrahedra.Count == 0)
            {
                // No lightprobes, we still set GPU resources (otherwise rendering might fetch invalid data)
                goto SetGPUResources;
            }

            // First time initialization
            if (bakeLightProbes == null)
            {
                bakeLightProbes = new DynamicEffectInstance("StrideBakeLightProbeEffect");
                bakeLightProbes.Initialize(Services);

                bakeLightProbesPipeline = new MutablePipelineState(GraphicsDevice);
                bakeLightProbesPipeline.State.InputElements = LightProbeVertex.Layout.CreateInputElements();
                bakeLightProbesPipeline.State.PrimitiveType = PrimitiveType.TriangleList;
            }

            // Render IBL tetrahedra ID so that we can assign them per pixel
            //ibl = PushScopedResource(Context.Allocator.GetTemporaryTexture2D(drawContext.CommandList.DepthStencilBuffer.Width, drawContext.CommandList.DepthStencilBuffer.Height, PixelFormat.R16_UInt));
            ibl = PushScopedResource(Context.Allocator.GetTemporaryTexture2D(TextureDescription.New2D(drawContext.CommandList.DepthStencilBuffer.Width, drawContext.CommandList.DepthStencilBuffer.Height,
                                                                                                      1, PixelFormat.R16_UInt, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 1, GraphicsResourceUsage.Default, actualMultisampleCount)));
            using (drawContext.PushRenderTargetsAndRestore())
            {
                drawContext.CommandList.Clear(ibl, Color4.Black);
                drawContext.CommandList.SetRenderTarget(drawContext.CommandList.DepthStencilBuffer, ibl);

                bakeLightProbes.UpdateEffect(GraphicsDevice);

                bakeLightProbesPipeline.State.RootSignature  = bakeLightProbes.RootSignature;
                bakeLightProbesPipeline.State.EffectBytecode = bakeLightProbes.Effect.Bytecode;
                bakeLightProbesPipeline.State.RasterizerState.DepthClipEnable = false;
                bakeLightProbesPipeline.State.DepthStencilState = new DepthStencilStateDescription(true, false)
                {
                    StencilEnable = true,
                    FrontFace     = new DepthStencilStencilOpDescription
                    {
                        StencilDepthBufferFail = StencilOperation.Keep,
                        StencilFail            = StencilOperation.Keep,
                        StencilPass            = StencilOperation.Increment,
                        StencilFunction        = CompareFunction.Equal,
                    },
                };
                //bakeLightProbesPipeline.State.RasterizerState.DepthClipEnable = false;
                bakeLightProbesPipeline.State.Output.CaptureState(drawContext.CommandList);
                bakeLightProbesPipeline.Update();

                drawContext.CommandList.SetPipelineState(bakeLightProbesPipeline.CurrentState);
                drawContext.CommandList.SetStencilReference(0);

                // Apply the effect
                bakeLightProbes.Parameters.Set(BakeLightProbeShaderKeys.MatrixTransform, ref renderView.ViewProjection);
                bakeLightProbes.Apply(drawContext.GraphicsContext);

                /*int tetrahedrawGridSize = 5;
                 * Vector3 tetrahedraMin = new Vector3(-12.0f);
                 * Vector3 tetrahedraMax = new Vector3(12.0f);
                 * var lightprobePositions = new Vector3[tetrahedrawGridSize*tetrahedrawGridSize*tetrahedrawGridSize];
                 *
                 * for (int i = 0; i < lightprobePositions.Length; ++i)
                 * {
                 *  lightprobePositions[i] = new Vector3(
                 *      MathUtil.Lerp(tetrahedraMin.X, tetrahedraMax.X, (float)(i/(tetrahedrawGridSize*tetrahedrawGridSize))/(tetrahedrawGridSize - 1)),
                 *      MathUtil.Lerp(tetrahedraMin.Y, tetrahedraMax.Y, (float)((i/tetrahedrawGridSize)%tetrahedrawGridSize)/(tetrahedrawGridSize - 1)),
                 *      MathUtil.Lerp(tetrahedraMin.Z, tetrahedraMax.Z, (float)(i%tetrahedrawGridSize)/(tetrahedrawGridSize - 1)));
                 * }
                 *
                 * var tetra = new BowyerWatsonTetrahedralization();
                 * var tetraResult = tetra.Compute(lightprobePositions);*/

                Matrix.Invert(ref renderView.View, out var viewInverse);

                var eye = new Vector3(viewInverse.M41, viewInverse.M42, viewInverse.M43);

                var tetraResult         = lightProbesData.Tetrahedra;
                var lightprobePositions = lightProbesData.Vertices;
                var lightprobeFaces     = lightProbesData.Faces;

                // We build a graph of tetrahedron connectivity from back to front, then do a topological sort on top of it
                var tetraDepth          = new TetrahedronSortKey[tetraResult.Count];
                var faceDirection       = new bool[lightprobeFaces.Count];
                var incomingEdges       = new byte[tetraResult.Count];
                var processQueue        = new Queue <int>();
                int processedTetrahedra = 0;

                for (int i = 0; i < lightprobeFaces.Count; ++i)
                {
                    var face = lightprobeFaces[i];

                    // Compute face orientations
                    var vertex0 = lightprobePositions[face.Vertices[0]];
                    Vector3.Subtract(ref vertex0, ref eye, out vertex0);
                    bool faceFrontFacing = Vector3.Dot(face.Normal, vertex0) >= 0.0f;
                    faceDirection[i] = faceFrontFacing;

                    // Only process edges that connect two tetrahedra (ignore boundaries for now)
                    if (face.BackTetrahedron != -1)
                    {
                        // Build list of incoming edges (back to front)
                        if (faceFrontFacing)
                        {
                            incomingEdges[face.FrontTetrahedron] |= (byte)(1 << face.FrontFace);
                        }
                        else
                        {
                            incomingEdges[face.BackTetrahedron] |= (byte)(1 << face.BackFace);
                        }
                    }
                }

                for (int i = 0; i < tetraResult.Count; ++i)
                {
                    // Tetrahedron without any incoming edges means they should be drawn first (graph nodes with no incoming edges for our topological sort)
                    if (incomingEdges[i] == 0)
                    {
                        processQueue.Enqueue(i);
                    }
                }

                // Perform topological sort
                while (processQueue.Count > 0)
                {
                    var tetrahedronIndex = processQueue.Dequeue();
                    tetraDepth[tetrahedronIndex] = new TetrahedronSortKey(tetrahedronIndex, processedTetrahedra++);
                    var tetrahedron = tetraResult[tetrahedronIndex];
                    //var frontFacingFaces = frontFacing[tetrahedronIndex];

                    // Process each outgoing face (edges in the graph)
                    for (int tetrahedronFace = 0; tetrahedronFace < 4; ++tetrahedronFace)
                    {
                        // Check if there is a neighbour
                        if (tetrahedron.Neighbours[tetrahedronFace] == -1)
                        {
                            continue;
                        }

                        var faceIndex     = tetrahedron.Faces[tetrahedronFace];
                        var realFaceIndex = faceIndex >= 0 ? faceIndex : ~faceIndex;

                        // Only process faces going back to front (outgoing edges)
                        if (faceDirection[realFaceIndex] == faceIndex >= 0)
                        {
                            continue;
                        }

                        var face = lightprobeFaces[realFaceIndex];

                        int   tetrahedronNeighbourIndex;
                        sbyte tetrahedronNeighbourFace;
                        if (faceIndex >= 0)
                        {
                            tetrahedronNeighbourIndex = face.BackTetrahedron;
                            tetrahedronNeighbourFace  = face.BackFace;
                        }
                        else
                        {
                            tetrahedronNeighbourIndex = face.FrontTetrahedron;
                            tetrahedronNeighbourFace  = face.FrontFace;
                        }

                        var neighbourTraversedFaces    = incomingEdges[tetrahedronNeighbourIndex];
                        var newNeighbourTraversedFaces = (byte)(neighbourTraversedFaces & ~(1 << tetrahedronNeighbourFace));

                        // Proceed only if something changed
                        if (newNeighbourTraversedFaces != neighbourTraversedFaces)
                        {
                            incomingEdges[tetrahedronNeighbourIndex] = newNeighbourTraversedFaces;
                            if (newNeighbourTraversedFaces == 0) // are all incoming edges already marked? If yes, go on
                            {
                                processQueue.Enqueue(tetrahedronNeighbourIndex);
                            }
                        }
                    }
                }

                Array.Sort(tetraDepth);

                // Draw shape
                tetrahedronMatrices     = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 3 * sizeof(Vector4), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32A32_Float));
                tetrahedronProbeIndices = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 4 * sizeof(int), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32A32_UInt));
                lightprobesCoefficients = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(lightProbesData.Coefficients.Length * sizeof(Color3), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32_Float));

                var tetraInsideIndex = -1;

                fixed(Color3 *lightProbeCoefficients = lightProbesData.Coefficients)
                fixed(Vector4 * matrices  = lightProbesData.Matrices)
                fixed(Int4 * probeIndices = lightProbesData.LightProbeIndices)
                {
                    drawContext.CommandList.UpdateSubresource(lightprobesCoefficients, 0, new DataBox((IntPtr)lightProbeCoefficients, 0, 0));
                    drawContext.CommandList.UpdateSubresource(tetrahedronProbeIndices, 0, new DataBox((IntPtr)probeIndices, 0, 0));
                    drawContext.CommandList.UpdateSubresource(tetrahedronMatrices, 0, new DataBox((IntPtr)matrices, 0, 0));

                    // Find which probe we are currently in
                    // TODO: Optimize (use previous coherency info?)
                    for (int i = 0; i < tetraResult.Count; ++i)
                    {
                        // Get tetrahedra matrix
                        var tetrahedraMatrix = Matrix.Identity;
                        tetrahedraMatrix.Column1 = matrices[i * 3 + 0];
                        tetrahedraMatrix.Column2 = matrices[i * 3 + 1];
                        tetrahedraMatrix.Column3 = matrices[i * 3 + 2];

                        // Extract and zero-out position of 3rd vertex (we get the 3x3 matrix)
                        var vertex3 = tetrahedraMatrix.TranslationVector;
                        tetrahedraMatrix.TranslationVector = Vector3.Zero;

                        Vector3 tetraFactors = Vector3.TransformCoordinate(eye - vertex3, tetrahedraMatrix);
                        var     tetraFactorW = 1.0f - tetraFactors.X - tetraFactors.Y - tetraFactors.Z;
                        if (tetraFactors.X >= 0.0f && tetraFactors.X <= 1.0f &&
                            tetraFactors.Y >= 0.0f && tetraFactors.Y <= 1.0f &&
                            tetraFactors.Z >= 0.0f && tetraFactors.Z <= 1.0f &&
                            tetraFactorW >= 0.0f && tetraFactorW <= 1.0f)
                        {
                            tetraInsideIndex = i;
                            break;
                        }
                    }
                }

                // Fill vertex/index buffers
                var vertexBuffer = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription((tetraResult.Count * 4 + 3) * LightProbeVertex.Size, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic)));
                var indexBuffer  = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 12 * sizeof(uint), BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic)));

                var mappedVertexBuffer = drawContext.CommandList.MapSubresource(vertexBuffer, 0, MapMode.WriteDiscard);
                var vertices           = (LightProbeVertex *)mappedVertexBuffer.DataBox.DataPointer;
                // Upload sorted tetrahedron indices
                for (int i = 0; i < tetraResult.Count; ++i)
                {
                    var sortedIndex = tetraDepth[i].Index;
                    var tetrahedra  = tetraResult[sortedIndex];
                    for (int j = 0; j < 4; ++j)
                    {
                        vertices[i * 4 + j] = new LightProbeVertex(lightprobePositions[tetrahedra.Vertices[j]], (uint)sortedIndex);
                    }
                }
                // Full screen pass
                if (tetraInsideIndex != -1)
                {
                    vertices[tetraResult.Count * 4 + 0] = new LightProbeVertex(new Vector3(-1, 1, 0), (uint)tetraInsideIndex);
                    vertices[tetraResult.Count * 4 + 1] = new LightProbeVertex(new Vector3(3, 1, 0), (uint)tetraInsideIndex);
                    vertices[tetraResult.Count * 4 + 2] = new LightProbeVertex(new Vector3(-1, -3, 0), (uint)tetraInsideIndex);
                }
                drawContext.CommandList.UnmapSubresource(mappedVertexBuffer);

                var mappedIndexBuffer = drawContext.CommandList.MapSubresource(indexBuffer, 0, MapMode.WriteDiscard);
                var indices           = (int *)mappedIndexBuffer.DataBox.DataPointer;
                for (int i = 0; i < tetraResult.Count; ++i)
                {
                    indices[i * 12 + 0] = i * 4 + 0;
                    indices[i * 12 + 1] = i * 4 + 2;
                    indices[i * 12 + 2] = i * 4 + 1;

                    indices[i * 12 + 3] = i * 4 + 1;
                    indices[i * 12 + 4] = i * 4 + 2;
                    indices[i * 12 + 5] = i * 4 + 3;

                    indices[i * 12 + 6] = i * 4 + 3;
                    indices[i * 12 + 7] = i * 4 + 2;
                    indices[i * 12 + 8] = i * 4 + 0;

                    indices[i * 12 + 9]  = i * 4 + 3;
                    indices[i * 12 + 10] = i * 4 + 0;
                    indices[i * 12 + 11] = i * 4 + 1;
                }
                drawContext.CommandList.UnmapSubresource(mappedIndexBuffer);

                drawContext.CommandList.SetVertexBuffer(0, vertexBuffer, 0, LightProbeVertex.Size);
                drawContext.CommandList.SetIndexBuffer(indexBuffer, 0, true);

                // Draw until current tetrahedra
                drawContext.CommandList.DrawIndexed(tetraResult.Count * 12);

                // For now, drawing them one by one (easier to debug)
                //for (int i = 0; i < tetraResult.Count; ++i)
                //{
                //    context.CommandList.DrawIndexed(12, i * 12);
                //}

                // Draw current tetrahedron we are in as full screen (fill stencil holes)
                if (tetraInsideIndex != -1)
                {
                    bakeLightProbesPipeline.State.DepthStencilState.DepthBufferEnable = false;
                    bakeLightProbesPipeline.Update();

                    drawContext.CommandList.SetPipelineState(bakeLightProbesPipeline.CurrentState);

                    // Apply the effect
                    bakeLightProbes.Parameters.Set(BakeLightProbeShaderKeys.MatrixTransform, Matrix.Identity);
                    bakeLightProbes.Apply(drawContext.GraphicsContext);

                    drawContext.CommandList.Draw(3, tetraResult.Count * 4);
                }

                // TODO: Draw the tetrahedron we are in full screen
                // context.CommandList.Draw...
            }

            // Set LightProbes resources
SetGPUResources:
            foreach (var renderFeature in context.RenderSystem.RenderFeatures)
            {
                if (!(renderFeature is RootEffectRenderFeature))
                {
                    continue;
                }

                var logicalKey  = ((RootEffectRenderFeature)renderFeature).CreateViewLogicalGroup("LightProbes");
                var viewFeature = renderView.Features[renderFeature.Index];

                foreach (var viewLayout in viewFeature.Layouts)
                {
                    var resourceGroup = viewLayout.Entries[renderView.Index].Resources;

                    var logicalGroup = viewLayout.GetLogicalGroup(logicalKey);
                    if (logicalGroup.Hash == ObjectId.Empty)
                    {
                        continue;
                    }

                    resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart, ibl);
                    resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 1, tetrahedronProbeIndices);
                    resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 2, tetrahedronMatrices);
                    resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 3, lightprobesCoefficients);
                }
            }
        }
コード例 #18
0
        public static Mesh ToStrideMesh(GraphicsDevice graphicsDevice, SimpleMesh g3Mesh, Vector3 offset, float scaling = 1f)
        {
            if (g3Mesh is null || g3Mesh.VertexCount == 0)
            {
                return(null);
            }

            var vertexDeclaration = GetVertexDeclaration(g3Mesh);

            var            vertices    = new byte[g3Mesh.VertexCount * vertexDeclaration.VertexStride];
            var            boundingBox = BoundingBox.Empty;
            BoundingSphere boundingSphere;

            unsafe
            {
                fixed(byte *ptr = vertices)
                {
                    byte *current = ptr;

                    for (int i = 0; i < g3Mesh.VertexCount; i++)
                    {
                        var vi = g3Mesh.GetVertexAll(i);
                        var p  = (new Vector3((float)vi.v.x, (float)vi.v.y, (float)vi.v.z) + offset) * scaling;
                        BoundingBox.Merge(ref boundingBox, ref p, out boundingBox);
                        Unsafe.Write(current, p);

                        current += sizeof(Vector3);
                        if (vi.bHaveN)
                        {
                            Unsafe.Write(current, vi.n);
                            current += sizeof(Vector3);
                        }
                        if (vi.bHaveUV)
                        {
                            Unsafe.Write(current, vi.uv);
                            current += sizeof(Vector2);
                        }
                        if (vi.bHaveC)
                        {
                            Unsafe.Write(current, new Color(vi.c.x, vi.c.y, vi.c.z));
                            current += sizeof(Color);
                        }
                    }

                    BoundingSphere.FromPoints((IntPtr)ptr, 0, g3Mesh.VertexCount, vertexDeclaration.VertexStride, out boundingSphere);
                }
            }

            var vertexBuffer = Buffer.New(graphicsDevice, vertices, vertexDeclaration.VertexStride, BufferFlags.VertexBuffer);
            var indexBuffer  = Buffer.Index.New(graphicsDevice, g3Mesh.Triangles.Reverse().ToArray());

            return(new Mesh()
            {
                Draw = new MeshDraw()
                {
                    VertexBuffers = new VertexBufferBinding[]
                    {
                        new VertexBufferBinding(vertexBuffer, vertexDeclaration, g3Mesh.VertexCount)
                    },
                    IndexBuffer = new IndexBufferBinding(indexBuffer, is32Bit: true, g3Mesh.Triangles.Length),
                    DrawCount = g3Mesh.Triangles.Length,
                    PrimitiveType = PrimitiveType.TriangleList
                },
                BoundingBox = boundingBox,
                BoundingSphere = boundingSphere
            });
        }
コード例 #19
0
        /// <inheritdoc/>
        public void Generate(IServiceRegistry services, Model model)
        {
            if (model is null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            var needsTempDevice = false;
            var graphicsDevice  = services?.GetSafeServiceAs <IGraphicsDeviceService>().GraphicsDevice;

            if (graphicsDevice is null)
            {
                graphicsDevice  = GraphicsDevice.New();
                needsTempDevice = true;
            }

            var data = CreatePrimitiveMeshData();

            if (data.Vertices.Length == 0)
            {
                throw new InvalidOperationException("Invalid GeometricPrimitive [{0}]. Expecting non-zero Vertices array.");
            }

            // Translate if necessary
            if (LocalOffset != Vector3.Zero)
            {
                for (var index = 0; index < data.Vertices.Length; index++)
                {
                    data.Vertices[index].Position += LocalOffset;
                }
            }

            // Scale if necessary
            if (Scale != Vector3.One)
            {
                var inverseMatrix = Matrix.Scaling(Scale);
                inverseMatrix.Invert();

                for (var index = 0; index < data.Vertices.Length; index++)
                {
                    data.Vertices[index].Position *= Scale;
                    // TODO: Shouldn't be TransformNormal?
                    Vector3.TransformCoordinate(ref data.Vertices[index].Normal, ref inverseMatrix, out data.Vertices[index].Normal);
                }
            }

            var boundingBox = BoundingBox.Empty;

            for (int i = 0; i < data.Vertices.Length; i++)
            {
                BoundingBox.Merge(ref boundingBox, ref data.Vertices[i].Position, out boundingBox);
            }

            BoundingSphere boundingSphere;

            unsafe
            {
                fixed(void *verticesPtr = data.Vertices)
                BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, data.Vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere);
            }

            var originalLayout = data.Vertices[0].GetLayout();

            // Generate Tangent/BiNormal vectors
            var resultWithTangentBiNormal = VertexHelper.GenerateTangentBinormal(originalLayout, data.Vertices, data.Indices);

            // Generate Multi texturing coords
            var maxTexCoords = MathUtil.Clamp(NumberOfTextureCoordinates, 1, 10) - 1;
            var result       = VertexHelper.GenerateMultiTextureCoordinates(resultWithTangentBiNormal, vertexStride: 0, maxTexCoords);

            var meshDraw = new MeshDraw();

            var layout       = result.Layout;
            var vertexBuffer = result.VertexBuffer;
            var indices      = data.Indices;

            if (indices.Length < 0xFFFF)
            {
                // 16-bit indices
                var indicesShort = new ushort[indices.Length];
                for (int i = 0; i < indicesShort.Length; i++)
                {
                    indicesShort[i] = (ushort)indices[i];
                }

                var indexBuffer = Buffer.Index.New(graphicsDevice, indicesShort)
                                  .RecreateWith(indicesShort);

                meshDraw.IndexBuffer = new IndexBufferBinding(indexBuffer, is32Bit: false, indices.Length);

                if (needsTempDevice)
                {
                    var indexData = BufferData.New(BufferFlags.IndexBuffer, indicesShort);
                    meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), is32Bit: false, indices.Length);
                }
            }
            else
            {
                // 32-bit indices
                var indexBuffer = Buffer.Index.New(graphicsDevice, indices)
                                  .RecreateWith(indices);

                meshDraw.IndexBuffer = new IndexBufferBinding(indexBuffer, is32Bit: true, indices.Length);

                if (needsTempDevice)
                {
                    var indexData = BufferData.New(BufferFlags.IndexBuffer, indices);
                    meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), is32Bit: true, indices.Length);
                }
            }

            var geometryBuffer = Buffer.New(graphicsDevice, vertexBuffer, BufferFlags.VertexBuffer)
                                 .RecreateWith(vertexBuffer);

            meshDraw.VertexBuffers = new[] { new VertexBufferBinding(geometryBuffer, layout, data.Vertices.Length) };

            if (needsTempDevice)
            {
                var vertexData = BufferData.New(BufferFlags.VertexBuffer, vertexBuffer);
                meshDraw.VertexBuffers = new[] { new VertexBufferBinding(vertexData.ToSerializableVersion(), layout, data.Vertices.Length) };
            }

            meshDraw.DrawCount     = indices.Length;
            meshDraw.PrimitiveType = PrimitiveType.TriangleList;

            var mesh = new Mesh
            {
                Draw           = meshDraw,
                BoundingBox    = boundingBox,
                BoundingSphere = boundingSphere
            };

            model.BoundingBox    = boundingBox;
            model.BoundingSphere = boundingSphere;
            model.Add(mesh);

            if (MaterialInstance?.Material is not null)
            {
                model.Materials.Add(MaterialInstance);
            }

            if (needsTempDevice)
            {
                graphicsDevice.Dispose();
            }
        }
コード例 #20
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var inputTexture = RadianceMap;

            if (inputTexture == null)
            {
                return;
            }

            const int FirstPassBlockSize = 4;
            const int FirstPassSumsCount = FirstPassBlockSize * FirstPassBlockSize;

            var faceCount = inputTexture.ViewDimension == TextureDimension.TextureCube ? 6 : 1;

            if (faceCount == 1)
            {
                throw new NotSupportedException("Only texture cube are currently supported as input of 'LambertianPrefilteringSH' effect.");
            }
            var inputSize         = new Int2(inputTexture.Width, inputTexture.Height); // (Note: for cube maps width = height)
            var coefficientsCount = harmonicalOrder * harmonicalOrder;

            var sumsToPerfomRemaining = inputSize.X * inputSize.Y * faceCount / FirstPassSumsCount;
            var partialSumBuffer      = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true);

            // Project the radiance on the SH basis and sum up the results along the 4x4 blocks
            firstPassEffect.ThreadNumbers     = new Int3(FirstPassBlockSize, FirstPassBlockSize, 1);
            firstPassEffect.ThreadGroupCounts = new Int3(inputSize.X / FirstPassBlockSize, inputSize.Y / FirstPassBlockSize, faceCount);
            firstPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, FirstPassBlockSize);
            firstPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder);
            firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.RadianceMap, inputTexture);
            firstPassEffect.Parameters.Set(LambertianPrefilteringSHPass1Keys.OutputBuffer, partialSumBuffer);
            ((RendererBase)firstPassEffect).Draw(context);

            // Recursively applies the pass2 (sums the coefficients together) as long as needed. Swap input/output buffer at each iteration.
            var    secondPassInputBuffer  = partialSumBuffer;
            Buffer secondPassOutputBuffer = null;

            while (sumsToPerfomRemaining % 2 == 0)
            {
                // we are limited in the number of summing threads by the group-shared memory size.
                // determine the number of threads to use and update the number of sums remaining afterward.
                var sumsCount = 1;
                while (sumsCount < (1 << 10) && sumsToPerfomRemaining % 2 == 0) // shader can perform only an 2^x number of sums.
                {
                    sumsCount             <<= 1;
                    sumsToPerfomRemaining >>= 1;
                }

                // determine the numbers of groups (limited to 65535 groups by dimensions)
                var groupCountX = 1;
                var groupCountY = sumsToPerfomRemaining;
                while (groupCountX >= short.MaxValue)
                {
                    groupCountX <<= 1;
                    groupCountY >>= 1;
                }

                // create the output buffer if not existing yet
                if (secondPassOutputBuffer == null)
                {
                    secondPassOutputBuffer = NewScopedTypedBuffer(coefficientsCount * sumsToPerfomRemaining, PixelFormat.R32G32B32A32_Float, true);
                }

                // draw pass 2
                secondPassEffect.ThreadNumbers     = new Int3(sumsCount, 1, 1);
                secondPassEffect.ThreadGroupCounts = new Int3(groupCountX, groupCountY, coefficientsCount);
                secondPassEffect.Parameters.Set(LambertianPrefilteringSHParameters.BlockSize, sumsCount);
                secondPassEffect.Parameters.Set(SphericalHarmonicsParameters.HarmonicsOrder, harmonicalOrder);
                secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.InputBuffer, secondPassInputBuffer);
                secondPassEffect.Parameters.Set(LambertianPrefilteringSHPass2Keys.OutputBuffer, secondPassOutputBuffer);
                ((RendererBase)secondPassEffect).Draw(context);

                // swap second pass input/output buffers.
                var swapTemp = secondPassOutputBuffer;
                secondPassOutputBuffer = secondPassInputBuffer;
                secondPassInputBuffer  = swapTemp;
            }

            // create and initialize result SH
            prefilteredLambertianSH = new SphericalHarmonics(HarmonicOrder);

            // Get the data out of the final buffer
            var sizeResult   = coefficientsCount * sumsToPerfomRemaining * PixelFormat.R32G32B32A32_Float.SizeInBytes();
            var stagedBuffer = NewScopedBuffer(new BufferDescription(sizeResult, BufferFlags.None, GraphicsResourceUsage.Staging));

            context.CommandList.CopyRegion(secondPassInputBuffer, 0, new ResourceRegion(0, 0, 0, sizeResult, 1, 1), stagedBuffer, 0);
            var finalsValues = stagedBuffer.GetData <Vector4>(context.CommandList);

            // performs last possible additions, normalize the result and store it in the SH
            for (var c = 0; c < coefficientsCount; c++)
            {
                var coeff = Vector4.Zero;
                for (var f = 0; f < sumsToPerfomRemaining; ++f)
                {
                    coeff += finalsValues[coefficientsCount * f + c];
                }
                prefilteredLambertianSH.Coefficients[c] = 4 * MathUtil.Pi / coeff.W * new Color3(coeff.X, coeff.Y, coeff.Z);
            }
        }