public void Update(List <BasicEntity> entities, GraphicsDevice graphics, DistanceFieldRenderModule distanceFieldRenderModule, FullScreenTriangle fullScreenTriangle, ref List <SignedDistanceField> sdfDefinitionsOut) { //First let's check which entities need building, if at all! sdfDefinitions.Clear(); //This should preferably be a list of meshes that are in the scene, instead of a list of entities for (var index0 = 0; index0 < entities.Count; index0++) { BasicEntity entity = entities[index0]; if (!entity.SignedDistanceField.IsUsed) { continue; } if (entity.SignedDistanceField.NeedsToBeGenerated) { GenerateDistanceFields(entity, graphics, distanceFieldRenderModule, fullScreenTriangle); } bool found = false; //Compile a list of all mbbs used right now for (var i = 0; i < sdfDefinitions.Count; i++) { if (entity.SignedDistanceField == sdfDefinitions[i]) { found = true; break; } } if (!found) { sdfDefinitions.Add(entity.SignedDistanceField); } } //Now for the model definitions for (var i = 0; i < sdfDefinitions.Count; i++) { if (GameSettings.sdf_regenerate) { sdfDefinitions[i].NeedsToBeGenerated = true; } } GameSettings.sdf_regenerate = false; sdfDefinitionsOut = sdfDefinitions; }
public void GenerateDistanceFields(BasicEntity entity, GraphicsDevice graphics, DistanceFieldRenderModule distanceFieldRenderModule, FullScreenTriangle fullScreenTriangle) { SignedDistanceField uncomputedSignedDistanceField = entity.SignedDistanceField; Model unprocessedModel = entity.Model; //Set to false so it won't get covered in future uncomputedSignedDistanceField.NeedsToBeGenerated = false; uncomputedSignedDistanceField.IsLoaded = false; uncomputedSignedDistanceField.SdfTexture?.Dispose(); //First generate tris Triangle[] triangles; GenerateTriangles(unprocessedModel, out triangles); int xsteps = (int)uncomputedSignedDistanceField.TextureResolution.X; int ysteps = (int)uncomputedSignedDistanceField.TextureResolution.Y; int zsteps = (int)uncomputedSignedDistanceField.TextureResolution.Z; Texture2D output; if (!GameSettings.sdf_cpu) { Stopwatch stopwatch = Stopwatch.StartNew(); int maxwidth = 4096; //16384 int requiredData = triangles.Length * 3; int x = maxwidth;//Math.Min(requiredData, maxwidth); int y = requiredData / x + 1; Vector4[] data = new Vector4[x * y]; int index = 0; for (int i = 0; i < triangles.Length; i++, index += 3) { data[index] = new Vector4(triangles[i].a, 0); data[index + 1] = new Vector4(triangles[i].b, 0); data[index + 2] = new Vector4(triangles[i].c, 0); } //16k Texture2D triangleData = new Texture2D(graphics, x, y, false, SurfaceFormat.Vector4); triangleData.SetData(data); output = distanceFieldRenderModule.CreateSDFTexture(graphics, triangleData, xsteps, ysteps, zsteps, uncomputedSignedDistanceField, fullScreenTriangle, triangles.Length); stopwatch.Stop(); Debug.Write("\nSDF generated in " + stopwatch.ElapsedMilliseconds + "ms on GPU"); float[] texData = new float[xsteps * ysteps * zsteps]; output.GetData(texData); string path = uncomputedSignedDistanceField.TexturePath; DataStream.SaveImageData(texData, xsteps, ysteps, zsteps, path); uncomputedSignedDistanceField.TextureResolution = new Vector4(xsteps, ysteps, zsteps, 0); uncomputedSignedDistanceField.SdfTexture = output; uncomputedSignedDistanceField.IsLoaded = true; } else { generateTask = Task.Factory.StartNew(() => { output = new Texture2D(graphics, xsteps * zsteps, ysteps, false, SurfaceFormat.Single); float[] data = new float[xsteps * ysteps * zsteps]; Stopwatch stopwatch = Stopwatch.StartNew(); int numberOfThreads = GameSettings.sdf_threads; if (numberOfThreads > 1) { Task[] threads = new Task[numberOfThreads - 1]; //Make local datas float[][] dataArray = new float[numberOfThreads][]; for (int index = 0; index < threads.Length; index++) { int i = index; dataArray[index + 1] = new float[xsteps * ysteps * zsteps]; threads[i] = Task.Factory.StartNew(() => { GenerateData(xsteps, ysteps, zsteps, uncomputedSignedDistanceField, ref dataArray[i + 1], i + 1, numberOfThreads, triangles); }); } dataArray[0] = data; GenerateData(xsteps, ysteps, zsteps, uncomputedSignedDistanceField, ref dataArray[0], 0, numberOfThreads, triangles); Task.WaitAll(threads); //Something broke? for (int i = 0; i < data.Length; i++) { //data[i] = dataArray[i % numberOfThreads][i]; for (int j = 0; j < numberOfThreads; j++) { if (dataArray[j][i] != 0) { data[i] = dataArray[j][i]; break; } } } for (var index2 = 0; index2 < threads.Length; index2++) { threads[index2].Dispose(); } } else { GenerateData(xsteps, ysteps, zsteps, uncomputedSignedDistanceField, ref data, 0, numberOfThreads, triangles); } stopwatch.Stop(); Debug.Write("\nSDF generated in " + stopwatch.ElapsedMilliseconds + "ms with " + GameSettings.sdf_threads + " thread(s)"); string path = uncomputedSignedDistanceField.TexturePath; DataStream.SaveImageData(data, xsteps, ysteps, zsteps, path); output.SetData(data); uncomputedSignedDistanceField.TextureResolution = new Vector4(xsteps, ysteps, zsteps, 0); uncomputedSignedDistanceField.SdfTexture = output; uncomputedSignedDistanceField.IsLoaded = true; }); } }