Advertisement
JontePonte

meshgen before compute shader

Sep 27th, 2024
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.91 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Unity.Mathematics;
  5. using Unity.Collections;
  6. using Unity.Jobs;
  7. using Unity.VisualScripting;
  8. using Unity.Burst;
  9.  
  10. public class MeshGenerator : MonoBehaviour
  11. {
  12.     public static int3 chunkDimensions = new int3(32, 128, 32);
  13.  
  14.     public Material material;
  15.     public ComputeShader voxelGridShader;
  16.  
  17.     public int brushSize;
  18.     public float brushStrength;
  19.  
  20.     public int lod;
  21.     public int maxLod;
  22.  
  23.     public float surfaceLevel;
  24.  
  25.     public bool hideMeshOnPlay;
  26.  
  27.     [Header("Noise Settings")]
  28.     public float heightMultiplier;
  29.     public AnimationCurve heightCurve;
  30.     public float frequency;
  31.     public float lacunarity;
  32.     public float persistance;
  33.     public int octaves;
  34.     public float density;
  35.     public float warpingStrength;
  36.     public float warpingFrequency;
  37.     public float mountainHeightOffset;
  38.     public Vector2 offset;
  39.  
  40.     [Header("")]
  41.     public bool autoUpdate;
  42.     public string executionTime;
  43.  
  44.     int[] caseToNumpolys;
  45.     int[][] triTable;
  46.  
  47.     public static NativeArray<int3> cornerOffsets;
  48.  
  49.     Camera cam;
  50.  
  51.     Noise noise;
  52.  
  53.     public GameObject ChunkObject(Vector2 position)
  54.     {
  55.         GameObject chunk = new GameObject("Chunk");
  56.         chunk.AddComponent<MeshFilter>().mesh = ChunkMesh(position, 0);
  57.         chunk.AddComponent<MeshRenderer>().material = material;
  58.         chunk.GetComponent<MeshRenderer>().receiveShadows = false;
  59.         chunk.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  60.  
  61.         return chunk;
  62.     }
  63.  
  64.     public Mesh ChunkMesh(Vector2 position, int lod)
  65.     {
  66.         List<Vector3> vertices = new();
  67.         Dictionary<Vector3, int> vertDictionary = new();
  68.         List<int> indices = new();
  69.  
  70.         lod = lod == 0 ? 1 : lod * 2;
  71.  
  72.         NativeArray<float> voxelGrid = new NativeArray<float>(chunkDimensions.x * chunkDimensions.y * chunkDimensions.z / (lod * lod * lod) * 8, Allocator.TempJob);
  73.  
  74.         MeshData meshData = new MeshData
  75.         {
  76.             vertices = vertices,
  77.             indices = indices,
  78.             vertDictionary = vertDictionary,
  79.             voxelGrid = voxelGrid,
  80.             lod = lod
  81.         };
  82.  
  83.         //Create Voxel Grid
  84.         int length = chunkDimensions.x / lod * chunkDimensions.y / lod * chunkDimensions.z / lod;
  85.  
  86.         NativeArray<float> noiseMap2D = noise.FractalNoiseMap(position, lod);
  87.         NativeArray<float> noiseMap3D = noise.Fractal3DNoiseMap(position, lod);
  88.  
  89.         VoxelGridJob job = new VoxelGridJob
  90.         {
  91.             voxelGrid = voxelGrid,
  92.             noiseMap2D = noiseMap2D,
  93.             noiseMap3D = noiseMap3D,
  94.             cornerOffsets = cornerOffsets,
  95.             chunkDimensions = chunkDimensions,
  96.             lod = lod,
  97.             surfaceLevel = surfaceLevel,
  98.             heightMultiplier = heightMultiplier,
  99.             density = density
  100.         };
  101.  
  102.         job.Schedule(length, 64).Complete();
  103.  
  104.         //Create Mesh
  105.         for (int z = 0, i = 0; z < chunkDimensions.z; z += lod)
  106.         {
  107.             for (int y = 0; y < chunkDimensions.y; y += lod)
  108.             {
  109.                 for (int x = 0; x < chunkDimensions.x; x += lod, i++)
  110.                 {
  111.                     AddVertices(i, new Vector3Int(x, y, z), meshData);
  112.                 }
  113.             }
  114.         }
  115.  
  116.         noiseMap2D.Dispose();
  117.         noiseMap3D.Dispose();
  118.         voxelGrid.Dispose();
  119.  
  120.         Mesh mesh = new Mesh();
  121.         mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
  122.  
  123.         mesh.vertices = vertices.ToArray();
  124.         mesh.triangles = indices.ToArray();
  125.  
  126.         mesh.RecalculateNormals();
  127.  
  128.         return mesh;
  129.     }
  130.  
  131.     public void EditorMesh()
  132.     {
  133.         Initialize();
  134.  
  135.         float startTime = Time.realtimeSinceStartup;
  136.  
  137.         Mesh mesh = ChunkMesh(offset/10, lod);
  138.  
  139.         executionTime = ((Time.realtimeSinceStartup - startTime) * 1000f) + "ms";
  140.  
  141.         if (GameObject.Find("Mesh") == null)
  142.         {
  143.             GameObject obj = new GameObject("Mesh");
  144.             obj.transform.parent = transform;
  145.             obj.AddComponent<MeshFilter>().mesh = mesh;
  146.             obj.AddComponent<MeshRenderer>().material = material;
  147.             obj.AddComponent<MeshCollider>();
  148.         }
  149.  
  150.         else
  151.         {
  152.             var mf = GameObject.Find("Mesh").GetComponent<MeshFilter>();
  153.             var collider = GameObject.Find("Mesh").GetComponent<MeshCollider>();
  154.  
  155.             mf.mesh = mesh;
  156.             collider.sharedMesh = null;
  157.             collider.sharedMesh = mesh;
  158.         }
  159.     }
  160.  
  161.     private void Start()
  162.     {
  163.         Initialize();
  164.  
  165.         if (GameObject.Find("Mesh") != null)
  166.         {
  167.             GameObject.Find("Mesh").SetActive(!hideMeshOnPlay);
  168.         }
  169.        
  170.     }
  171.  
  172.     private void Update()
  173.     {
  174.         if (Input.GetKeyDown(KeyCode.Space))
  175.         {
  176.             EditorMesh();
  177.         }
  178.  
  179.         //if (Input.GetMouseButton(1))
  180.         //{
  181.         //    Ray ray = cam.ScreenPointToRay(Input.mousePosition);
  182.  
  183.         //    if (Physics.Raycast(ray, out RaycastHit hit))
  184.         //    {
  185.         //        ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), true, hit.collider.gameObject);
  186.         //    }
  187.         //}
  188.  
  189.         //if (Input.GetMouseButton(0))
  190.         //{
  191.         //    Ray ray = cam.ScreenPointToRay(Input.mousePosition);
  192.  
  193.         //    if (Physics.Raycast(ray, out RaycastHit hit))
  194.         //    {
  195.         //        ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), false, hit.collider.gameObject);
  196.         //    }
  197.         //}
  198.     }
  199.  
  200.     void Initialize()
  201.     {
  202.         caseToNumpolys = Tables.caseToNumPolys;
  203.         triTable = Tables.triTable;
  204.  
  205.         cam = Camera.main;
  206.        
  207.         cornerOffsets = new NativeArray<int3>(8, Allocator.Persistent);
  208.  
  209.         cornerOffsets[0] = new int3(0, 0, 0);
  210.         cornerOffsets[1] = new int3(0, 1, 0);
  211.         cornerOffsets[2] = new int3(1, 1, 0);
  212.         cornerOffsets[3] = new int3(1, 0, 0);
  213.         cornerOffsets[4] = new int3(0, 0, 1);
  214.         cornerOffsets[5] = new int3(0, 1, 1);
  215.         cornerOffsets[6] = new int3(1, 1, 1);
  216.         cornerOffsets[7] = new int3(1, 0, 1);
  217.  
  218.         noise = new Noise(frequency, persistance, lacunarity, warpingStrength, warpingFrequency, mountainHeightOffset, octaves, voxelGridShader);
  219.     }
  220.  
  221.     void AddVertices(int index, Vector3Int pos, MeshData md)
  222.     {
  223.         float[] voxelData = new float[8];
  224.  
  225.         for (int i = 0; i < 8; i++)
  226.         {
  227.             voxelData[i] = md.voxelGrid[(index * 8) + i];
  228.         }
  229.  
  230.         int triCase = Utils.CalculateCase(voxelData);
  231.         int[] edges = triTable[triCase];
  232.  
  233.         for (int j = 0, i = 0; j < caseToNumpolys[triCase]; j++, i += 3)
  234.         {
  235.             for (int h = 0; h < 3; h++)
  236.             {
  237.                 Vector3 vertex = GetEdgePosition(edges[i + (2 - h)], voxelData, md.lod, pos);
  238.  
  239.                 if (md.vertDictionary.ContainsKey(vertex))
  240.                 {
  241.                     md.indices.Add(md.vertDictionary[vertex]);
  242.                 }
  243.  
  244.                 else
  245.                 {
  246.                     md.vertices.Add(vertex);
  247.                     md.indices.Add(md.vertices.Count - 1);
  248.  
  249.                     md.vertDictionary.Add(vertex, md.vertices.Count - 1);
  250.                 }
  251.             }
  252.         }
  253.     }
  254.  
  255.     Vector3 GetEdgePosition(int edge, float[] voxelData, int lod, Vector3Int pos)
  256.     {
  257.         int x = pos.x;
  258.         int y = pos.y;
  259.         int z = pos.z;
  260.  
  261.         switch (edge)
  262.         {
  263.             case 0: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[1], 0, 1, 0);
  264.             case 1: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z, voxelData[1], voxelData[2], 1, 0, 0);
  265.             case 2: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z, voxelData[3], voxelData[2], 0, 1, 0);
  266.             case 3: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[3], 1, 0, 0);
  267.  
  268.             case 4: return Utils.GetInterpolatedEdgePosition(x, y, z + (1 * lod), voxelData[4], voxelData[5], 0, 1, 0);
  269.             case 5: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z + (1 * lod), voxelData[5], voxelData[6], 1, 0, 0);
  270.             case 6: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z + (1 * lod), voxelData[7], voxelData[6], 0, 1, 0);
  271.             case 7: return Utils.GetInterpolatedEdgePosition(x, y, z + (1 * lod), voxelData[4], voxelData[7], 1, 0, 0);
  272.  
  273.             case 8: return Utils.GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[4], 0, 0, 1);
  274.             case 9: return Utils.GetInterpolatedEdgePosition(x, y + (1 * lod), z, voxelData[1], voxelData[5], 0, 0, 1);
  275.             case 10: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y + (1 * lod), z, voxelData[2], voxelData[6], 0, 0, 1);
  276.             case 11: return Utils.GetInterpolatedEdgePosition(x + (1 * lod), y, z, voxelData[3], voxelData[7], 0, 0, 1);
  277.  
  278.             default: throw new ArgumentOutOfRangeException(nameof(edge), "Invalid edge index: " + edge);
  279.         }
  280.     }
  281.  
  282.     //private void ModifyTerrain(Vector3Int vertex, bool addTerrain, GameObject chunk)
  283.     //{
  284.     //    for (int zOffset = -brushSize; zOffset <= brushSize; zOffset++)
  285.     //    {
  286.     //        for (int yOffset = -brushSize; yOffset <= brushSize; yOffset++)
  287.     //        {
  288.     //            for (int xOffset = -brushSize; xOffset <= brushSize; xOffset++)
  289.     //            {
  290.     //                bool xOutOfRange = vertex.x + xOffset < 0 || vertex.x + xOffset > chunkDimensions.x - 1;
  291.     //                bool yOutOfRange = vertex.y + yOffset < 0 || vertex.y + yOffset > chunkDimensions.y - 1;
  292.     //                bool zOutOfRange = vertex.z + zOffset < 0 || vertex.z + zOffset > chunkDimensions.z - 1;
  293.  
  294.     //                if (xOutOfRange || yOutOfRange || zOutOfRange)
  295.     //                {
  296.     //                    continue;
  297.     //                }
  298.  
  299.     //                float[] voxel = voxelGrid[Utils.VoxelIndex(vertex.x + xOffset, vertex.y + yOffset, vertex.z + zOffset)];
  300.  
  301.     //                for (int i = 0; i < 8; i++)
  302.     //                {
  303.     //                    int x = vertex.x + xOffset + cornerOffsets[i].x;
  304.     //                    int y = vertex.y + yOffset + cornerOffsets[i].y;
  305.     //                    int z = vertex.z + zOffset + cornerOffsets[i].z;
  306.  
  307.     //                    float dist = Vector3.Distance(vertex, new Vector3(x, y, z));
  308.  
  309.     //                    if (dist < brushSize)
  310.     //                    {
  311.     //                        voxel[i] = addTerrain ? voxel[i] + brushStrength : voxel[i] - brushStrength;
  312.     //                    }
  313.     //                }
  314.     //            }
  315.     //        }
  316.     //    }
  317.  
  318.     //    chunk.GetComponent<MeshFilter>().mesh = ChunkMesh(new Vector2Int((int)chunk.transform.position.x, (int)chunk.transform.position.z));
  319.     //}
  320.  
  321.     private void OnDestroy()
  322.     {
  323.         cornerOffsets.Dispose();
  324.     }
  325.  
  326.     struct MeshData
  327.     {
  328.         public List<Vector3> vertices;
  329.         public List<int> indices;
  330.         public Dictionary<Vector3, int> vertDictionary;
  331.         public NativeArray<float> voxelGrid;
  332.         public int lod;
  333.     }
  334.  
  335.     [BurstCompile]
  336.     struct VoxelGridJob : IJobParallelFor
  337.     {
  338.         [NativeDisableParallelForRestriction]
  339.         [WriteOnly] public NativeArray<float> voxelGrid;
  340.  
  341.         [NativeDisableParallelForRestriction]
  342.         [ReadOnly] public NativeArray<float> noiseMap2D;
  343.  
  344.         [NativeDisableParallelForRestriction]
  345.         [ReadOnly] public NativeArray<float> noiseMap3D;
  346.  
  347.         [NativeDisableParallelForRestriction]
  348.         [ReadOnly] public NativeArray<int3> cornerOffsets;
  349.  
  350.         //[ReadOnly] public NativeArray<float> heightCurve;
  351.  
  352.         [ReadOnly] public int3 chunkDimensions;
  353.         [ReadOnly] public int lod;    
  354.         [ReadOnly] public float surfaceLevel;
  355.         [ReadOnly] public float heightMultiplier;
  356.         [ReadOnly] public float density;
  357.  
  358.         public void Execute(int i)
  359.         {
  360.             int z = i / (chunkDimensions.x / lod * chunkDimensions.y / lod) * lod;
  361.             int y = (i / (chunkDimensions.x / lod) * lod) - z / lod * chunkDimensions.y;
  362.             int x = i % (chunkDimensions.x / lod) * lod;
  363.  
  364.             CreateVoxel(new int3(x, y, z), i);
  365.         }
  366.  
  367.         void CreateVoxel(int3 pos, int index)
  368.         {
  369.             int noise2DIndex = ((pos.x / lod) + ((pos.z / lod) * chunkDimensions.x)) * 8;
  370.  
  371.             for (int i = 0; i < 8; i++)
  372.             {
  373.                 int3 cornerPos = pos + cornerOffsets[i] * lod;
  374.  
  375.                 float noise2D = noiseMap2D[noise2DIndex + i];
  376.  
  377.                 voxelGrid[(index * 8) + i] = noiseMap3D[(index * 8) + i]; //(-cornerPos.y + surfaceLevel + noise2D * heightMultiplier) * density + noiseMap3D[(index * 8) + i];
  378.             }
  379.         }
  380.     }
  381.  
  382. }
  383.  
  384.  
  385.  
  386.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement