Quantcast
Channel: Questions in topic: "compute shader"
Viewing all articles
Browse latest Browse all 287

Breaking large scalar field into smaller scalar fields

$
0
0
To start, I have a working script that dispatches a compute shader to genrate a 3d scalar field representatitive of a sphere. this script works fine, but after radii of about 40 units, the mesh begins to be too large and we start to lose triangles and vertices. Here is this code: using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; using UnityEngine.Rendering; public class Planet : MonoBehaviour { public int radius; ComputeShader densityShader; ComputeShader marchingCubesShader; ComputeShader cleanupMeshShader; // Start is called before the first frame update void Start() { densityShader = Resources.Load("CreateDensityField"); marchingCubesShader = Resources.Load("MarchingCubesShader"); cleanupMeshShader = Resources.Load("CleanupMesh"); createDensity(); } // Creates a spherical desnity field to represent the planet void createDensity () { int genBufferSize = (radius * 2) * (radius * 2) * (radius * 2); ComputeBuffer planetDensityBuffer = new ComputeBuffer(genBufferSize, sizeof(float)); densityShader.SetBuffer(0, "outputField", planetDensityBuffer); densityShader.SetInt("radius", radius); int numThreads = Mathf.CeilToInt(radius * 2f / 8f); densityShader.Dispatch(0, numThreads, numThreads, numThreads); generateMesh(planetDensityBuffer); } // duh public void generateMesh(ComputeBuffer scalarFieldBuffer) { Vector3[] edgeTable = new Vector3[] { new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 1, 0), new Vector3(1, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 1), new Vector3(1, 0, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(0, 1, 1), new Vector3(0, 1, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(1, 0, 1), new Vector3(1, 1, 0), new Vector3(1, 1, 1), new Vector3(0, 1, 0), new Vector3(0, 1, 1) }; int[] triangleTable = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //ommited for brevity -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; ComputeBuffer edgeTableBuffer = new ComputeBuffer(24, sizeof(float) * 3); edgeTableBuffer.SetData(edgeTable); marchingCubesShader.SetBuffer(0, "edgeTable", edgeTableBuffer); ComputeBuffer triangleTableBuffer = new ComputeBuffer(256 * 16, sizeof(int)); triangleTableBuffer.SetData(triangleTable); marchingCubesShader.SetBuffer(0, "triangleTable", triangleTableBuffer); marchingCubesShader.SetBuffer(0, "scalarField", scalarFieldBuffer); marchingCubesShader.SetInt("radius", radius); int numTriangles = (radius * 2) * (radius * 2) * (radius * 2) * 5; ComputeBuffer triangleBuffer = new ComputeBuffer(numTriangles, sizeof(float) * 9, ComputeBufferType.Append); marchingCubesShader.SetBuffer(0, "outputTriangles", triangleBuffer); int numThreads = Mathf.CeilToInt((radius * 2) / 8f); marchingCubesShader.Dispatch(0, numThreads, numThreads, numThreads); Triangle[] triangles = new Triangle[numTriangles]; triangleBuffer.GetData(triangles); Mesh mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; Vector3[] vertices = new Vector3[triangles.Length * 3]; int[] indices = new int[triangles.Length * 3]; for (int i = 0; i < triangles.Length; i++) { Triangle tri = triangles[i]; int index = i * 3; vertices[index] = tri.v0; vertices[index + 1] = tri.v1; vertices[index + 2] = tri.v2; indices[index] = index; indices[index + 1] = index + 1; indices[index + 2] = index + 2; } mesh.vertices = vertices; mesh.triangles = indices; mesh.RecalculateNormals(); MeshFilter meshy = gameObject.GetComponent(); meshy.mesh = mesh; GetComponent().mesh = mesh; triangleBuffer.Release(); edgeTableBuffer.Release(); triangleTableBuffer.Release(); } private struct Triangle { public Vector3 v0; public Vector3 v1; public Vector3 v2; } } The logical step, to me, was to fix the issue using chunks, as this would let me add other stuff later, such as level of detail. My implementation was to store the original scalar field, and then make smaller fields in "sections" of size chunksize that are passed to the generateMesh fucntion. Here is the attempt: using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; using UnityEngine.Rendering; public class NewGen : MonoBehaviour { public int radius; public int chunkSize; ComputeShader densityShader; ComputeShader marchingCubesShader; // Start is called before the first frame update void Start() { densityShader = Resources.Load("CreateDensityField"); marchingCubesShader = Resources.Load("MarchingCubesShader"); createDensity(); } // Creates a spherical desnity field to represent the planet public void createDensity() { int genBufferSize = (radius * 2) * (radius * 2) * (radius * 2); ComputeBuffer planetDensityBuffer = new ComputeBuffer(genBufferSize, sizeof(float)); densityShader.SetBuffer(0, "outputField", planetDensityBuffer); densityShader.SetInt("radius", radius); int numThreads = Mathf.CeilToInt(radius * 2f / 8f); densityShader.Dispatch(0, numThreads, numThreads, numThreads); float[] scalarField = new float[genBufferSize]; planetDensityBuffer.GetData(scalarField); int numChunks = Mathf.CeilToInt((float)(radius * 2) / chunkSize); for (int x = 0; x < numChunks; x++) { for (int y = 0; y < numChunks; y++) { for (int z = 0; z < numChunks; z++) { int chunkBufferSize = chunkSize * chunkSize * chunkSize; ComputeBuffer chunkScalarFieldBuffer = new ComputeBuffer(chunkBufferSize, sizeof(float)); float[] chunkScalarField = new float[chunkBufferSize]; for (int i = 0; i < chunkSize; i++) { for (int j = 0; j < chunkSize; j++) { for (int k = 0; k < chunkSize; k++) { int globalX = x * chunkSize + i; int globalY = y * chunkSize + j; int globalZ = z * chunkSize + k; int globalIndex = globalX + globalY * (radius * 2) + globalZ * (radius * 2) * (radius * 2); int chunkIndex = i + j * chunkSize + k * chunkSize * chunkSize; chunkScalarField[chunkIndex] = scalarField[globalIndex]; } } } chunkScalarFieldBuffer.SetData(chunkScalarField); generateMesh(chunkScalarFieldBuffer, new Vector3(x * chunkSize, y * chunkSize, z * chunkSize)); chunkScalarFieldBuffer.Release(); } } } } // duh public void generateMesh(ComputeBuffer scalarFieldBuffer, Vector3 position) { Vector3[] edgeTable = new Vector3[] { new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 1, 0), new Vector3(1, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 1), new Vector3(1, 0, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(0, 1, 1), new Vector3(0, 1, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(1, 0, 1), new Vector3(1, 1, 0), new Vector3(1, 1, 1), new Vector3(0, 1, 0), new Vector3(0, 1, 1) }; int[] triangleTable = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //ommited again -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; ComputeBuffer edgeTableBuffer = new ComputeBuffer(24, sizeof(float) * 3); edgeTableBuffer.SetData(edgeTable); marchingCubesShader.SetBuffer(0, "edgeTable", edgeTableBuffer); ComputeBuffer triangleTableBuffer = new ComputeBuffer(256 * 16, sizeof(int)); triangleTableBuffer.SetData(triangleTable); marchingCubesShader.SetBuffer(0, "triangleTable", triangleTableBuffer); marchingCubesShader.SetBuffer(0, "scalarField", scalarFieldBuffer); marchingCubesShader.SetInt("radius", radius); int numTriangles = chunkSize * chunkSize * chunkSize * 5; ComputeBuffer triangleBuffer = new ComputeBuffer(numTriangles, sizeof(float) * 9, ComputeBufferType.Append); marchingCubesShader.SetBuffer(0, "outputTriangles", triangleBuffer); int numThreads = Mathf.CeilToInt(chunkSize / 8f); marchingCubesShader.Dispatch(0, numThreads, numThreads, numThreads); Triangle[] triangles = new Triangle[numTriangles]; triangleBuffer.GetData(triangles); Mesh mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; Vector3[] vertices = new Vector3[triangles.Length * 3]; int[] indices = new int[triangles.Length * 3]; for (int i = 0; i < triangles.Length; i++) { Triangle tri = triangles[i]; int index = i * 3; vertices[index] = tri.v0; vertices[index + 1] = tri.v1; vertices[index + 2] = tri.v2; indices[index] = index; indices[index + 1] = index + 1; indices[index + 2] = index + 2; } GameObject section = new GameObject(); section.transform.parent = gameObject.transform; section.transform.position = position; mesh.vertices = vertices; mesh.triangles = indices; mesh.RecalculateNormals(); MeshFilter meshy = section.AddComponent(); MeshRenderer rendy = section.AddComponent(); meshy.mesh = mesh; triangleBuffer.Release(); edgeTableBuffer.Release(); triangleTableBuffer.Release(); } private struct Triangle { public Vector3 v0; public Vector3 v1; public Vector3 v2; } } this code doesnt do what I want. while it creates smaller meshes, it also makes them very jumbled. I suspect that the code isnot properly storing the scalar field inm the first place, or when it is translated to buffer there might be an issue. Here is the code for the scalar field compute (in case that helps) #pragma kernel GenerateScalarField RWStructuredBuffer outputField; int radius; [numthreads(8, 8, 8)] void GenerateScalarField(uint3 id : SV_DispatchThreadID) { int3 index = int3(id.x, id.y, id.z); int3 center = int3(radius, radius, radius); float dist = distance(float3(index), float3(center)); float fieldValue = (dist <= radius - 0.01f) ? 1.0f : 0.0f; uint linearIndex = id.x + id.y * (radius * 2) + id.z * (radius * 2) * (radius * 2); outputField[linearIndex] = fieldValue; } Here is what a radius 12 sphere looks like on the first script (looks great!): ![alt text][1] and here it is with a radius of 12, chunksize of 4 (on the newgen script): ![alt text][2] also, i tired using the globalxy and z to simply generate a 0 or 1 and pass that in c# (to skip the compute) and even that made the same result, so i think passing to the buffer is the issue Thank you for your time! [1]: /storage/temp/206814-good.png [2]: /storage/temp/206815-bad.png

Viewing all articles
Browse latest Browse all 287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>