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, Color4.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 }); }
private void UpdateLightProbeWireframe() { var lightProbeProcessor = game.SceneSystem.SceneInstance.GetProcessor <LightProbeProcessor>(); var lightProbeRuntimeData = lightProbeProcessor?.VisibilityGroup.Tags.Get(LightProbeRenderer.CurrentLightProbes); if (lightProbeRuntimeData == null) { // Nothing, just remove existing wireframe and exit Cleanup(); return; } var needWireframeRefresh = false; if (lightProbeRuntimeData != currentLightProbeRuntimeData) { // LightProbe runtime data changed (light probe added or removed) => force a wireframe refresh currentLightProbeRuntimeData = lightProbeRuntimeData; needWireframeRefresh = true; } else { // check if we need to trigger a manual refresh (the LightProbeProcessor only reacts to LightProbe added/removed at runtime) var needPositionRefresh = false; var needCoefficientsRefresh = false; for (var lightProbeIndex = 0; lightProbeIndex < lightProbeRuntimeData.LightProbes.Length; lightProbeIndex++) { // check if lightprobe moved var lightProbe = lightProbeRuntimeData.LightProbes[lightProbeIndex] as LightProbeComponent; if (lightProbe == null) { continue; } if (lightProbe.Entity.Transform.WorldMatrix.TranslationVector != lightProbeRuntimeData.Vertices[lightProbeIndex]) { needPositionRefresh = true; needWireframeRefresh = true; } // check if lightprobe coefficients changed var coefficientIndex = lightProbeIndex * LightProbeGenerator.LambertHamonicOrder * LightProbeGenerator.LambertHamonicOrder; for (int i = 0; i < LightProbeGenerator.LambertHamonicOrder * LightProbeGenerator.LambertHamonicOrder; ++i) { var expectedCoefficient = lightProbe.Coefficients != null ? lightProbe.Coefficients[i] : default(Color3); if (expectedCoefficient != lightProbeRuntimeData.Coefficients[coefficientIndex + i]) { needCoefficientsRefresh = true; } } } if (needPositionRefresh) { lightProbeProcessor.UpdateLightProbePositions(); lightProbeRuntimeData = lightProbeProcessor.VisibilityGroup.Tags.Get(LightProbeRenderer.CurrentLightProbes); if (lightProbeRuntimeData == null) { Cleanup(); return; } } else if (needCoefficientsRefresh) { lightProbeProcessor.UpdateLightProbeCoefficients(); } } // Do we need to regenerate the wireframe? if (!needWireframeRefresh) { return; } Cleanup(); // Need at least a tetrahedron to not have empty buffers if (lightProbeRuntimeData.Tetrahedra.Count > 0) { var mesh = ConvertToMesh(game.GraphicsDevice, PrimitiveType.LineList, lightProbeRuntimeData); var model = new Model { mesh, wireframeMaterial, }; wireframeModelComponent = new ModelComponent(model) { RenderGroup = LightProbeWireGroup, Enabled = IsLightProbeVolumesVisible }; var lightProbeWireframe = new Entity("LightProbe Wireframe") { wireframeModelComponent }; debugEntity.AddChild(lightProbeWireframe); } }