Advertisement
JontePonte

Marching Cubes with Terraforming

Sep 11th, 2024
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.10 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Experimental.AI;
  5.  
  6. public class MeshGenerator : MonoBehaviour
  7. {
  8.     public Vector3Int chunkDimensions;
  9.  
  10.     public Material material;
  11.  
  12.     public int brushSize;
  13.  
  14.     [Header("Noise Settings")]
  15.     public float frequency;
  16.  
  17.     float[,,][] voxelGrid;
  18.  
  19.     List<Vector3> vertices;
  20.  
  21.     int[] caseToNumpolys;
  22.     int[][] triTable;
  23.  
  24.     Vector3[] voxelCornerOffsets;
  25.  
  26.     RaycastHit hit;
  27.     Camera cam;
  28.  
  29.     private void Start()
  30.     {
  31.         caseToNumpolys = Tables.caseToNumPolys;
  32.         triTable = Tables.triTable;
  33.  
  34.         cam = Camera.main;
  35.  
  36.         voxelCornerOffsets = new Vector3[]
  37.         {
  38.             new Vector3(0, 0, 0),
  39.             new Vector3(0, 1, 0),
  40.             new Vector3(1, 1, 0),
  41.             new Vector3(1, 0, 0),
  42.             new Vector3(0, 0, 1),
  43.             new Vector3(0, 1, 1),
  44.             new Vector3(1, 1, 1),
  45.             new Vector3(1, 0, 1),
  46.  
  47.         };
  48.  
  49.         CreateVoxelGrid();
  50.         GenerateMesh();
  51.     }
  52.  
  53.     private void Update()
  54.     {
  55.         if (Input.GetMouseButton(1))
  56.         {          
  57.             if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hit))
  58.             {
  59.                 ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), true);
  60.             }
  61.         }
  62.  
  63.         if (Input.GetMouseButton(0))
  64.         {
  65.             if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit))
  66.             {
  67.                 ModifyTerrain(new Vector3Int((int)hit.point.x, (int)hit.point.y, (int)hit.point.z), false);
  68.             }
  69.         }
  70.     }
  71.  
  72.     void GenerateMesh()
  73.     {
  74.         vertices = new();
  75.  
  76.         for (int z = 0; z < chunkDimensions.z; z++)
  77.         {
  78.             for (int y = 0; y < chunkDimensions.y; y++)
  79.             {
  80.                 for (int x = 0; x < chunkDimensions.x; x++)
  81.                 {
  82.                     AddVertices(x, y, z);
  83.                 }
  84.             }
  85.         }
  86.  
  87.         int[] indices = new int[vertices.Count];
  88.  
  89.         for (int i = 0; i < vertices.Count; i++)
  90.         {
  91.             indices[i] = i;
  92.         }
  93.  
  94.         Mesh mesh = new Mesh();
  95.  
  96.         mesh.vertices = vertices.ToArray();
  97.         mesh.triangles = indices;
  98.  
  99.         mesh.RecalculateNormals();
  100.  
  101.         if(GameObject.Find("Mesh") == null)
  102.         {
  103.             GameObject obj = new GameObject("Mesh");
  104.             obj.AddComponent<MeshFilter>().mesh = mesh;
  105.             obj.AddComponent<MeshRenderer>().material = material;
  106.             obj.AddComponent<MeshCollider>();
  107.         }
  108.  
  109.         else
  110.         {
  111.             var mf = GameObject.Find("Mesh").GetComponent<MeshFilter>();
  112.             var collider = GameObject.Find("Mesh").GetComponent<MeshCollider>();
  113.  
  114.             mf.mesh = mesh;
  115.             collider.sharedMesh = null;
  116.             collider.sharedMesh = mesh;
  117.         }
  118.      
  119.     }
  120.  
  121.     void AddVertices(int x, int y, int z)
  122.     {
  123.         int triCase = CalculateCase(voxelGrid[x, y, z]);
  124.         int[] edges = triTable[triCase];
  125.  
  126.         for (int j = 0, i = 0; j < caseToNumpolys[triCase]; j++, i += 3)
  127.         {
  128.             vertices.AddRange(new List<Vector3>
  129.             {
  130.                 GetEdgePosition(edges[i + 2], x, y, z),
  131.                 GetEdgePosition(edges[i + 1], x, y, z),
  132.                 GetEdgePosition(edges[i], x, y, z)
  133.             });
  134.         }
  135.     }
  136.  
  137.     Vector3 GetEdgePosition(int edge, int x, int y, int z)
  138.     {
  139.         float[] voxelData = voxelGrid[x, y, z];
  140.  
  141.         switch (edge)
  142.         {
  143.             case 0: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[1], 0, 1, 0);
  144.             case 1: return GetInterpolatedEdgePosition(x, y + 1, z, voxelData[1], voxelData[2], 1, 0, 0);
  145.             case 2: return GetInterpolatedEdgePosition(x + 1, y, z, voxelData[3], voxelData[2], 0, 1, 0);
  146.             case 3: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[3], 1, 0, 0);
  147.  
  148.             case 4: return GetInterpolatedEdgePosition(x, y, z + 1, voxelData[4], voxelData[5], 0, 1, 0);
  149.             case 5: return GetInterpolatedEdgePosition(x, y + 1, z + 1, voxelData[5], voxelData[6], 1, 0, 0);
  150.             case 6: return GetInterpolatedEdgePosition(x + 1, y, z + 1, voxelData[7], voxelData[6], 0, 1, 0);
  151.             case 7: return GetInterpolatedEdgePosition(x, y, z + 1, voxelData[4], voxelData[7], 1, 0, 0);
  152.  
  153.             case 8: return GetInterpolatedEdgePosition(x, y, z, voxelData[0], voxelData[4], 0, 0, 1);
  154.             case 9: return GetInterpolatedEdgePosition(x, y + 1, z, voxelData[1], voxelData[5], 0, 0, 1);
  155.             case 10: return GetInterpolatedEdgePosition(x + 1, y + 1, z, voxelData[2], voxelData[6], 0, 0, 1);
  156.             case 11: return GetInterpolatedEdgePosition(x + 1, y, z, voxelData[3], voxelData[7], 0, 0, 1);
  157.  
  158.             default: throw new ArgumentOutOfRangeException(nameof(edge), "Invalid edge index: " + edge);
  159.         }
  160.     }
  161.  
  162.     // Helper method to calculate interpolated edge positions
  163.     Vector3 GetInterpolatedEdgePosition(int x, int y, int z, float voxelA, float voxelB, int offsetX, int offsetY, int offsetZ)
  164.     {
  165.         float interpolation = Interpolate(voxelA, voxelB);
  166.  
  167.         return new Vector3(x + offsetX * interpolation, y + offsetY * interpolation, z + offsetZ * interpolation);
  168.     }
  169.  
  170.     float Interpolate(float a, float b)
  171.     {
  172.         return (0 - a) / (b - a);
  173.     }
  174.  
  175.     int CalculateCase(float[] voxelData)
  176.     {
  177.         int triCase = 0;
  178.  
  179.         for (int i = 0; i < 8; i++)
  180.         {
  181.             int bit = voxelData[i] < 0 ? 1 : 0;
  182.             triCase |= bit << i;
  183.         }
  184.  
  185.         return triCase;
  186.     }
  187.  
  188.     private void ModifyTerrain(Vector3Int vertex, bool addTerrain)
  189.     {
  190.         for (int zOffset = -brushSize; zOffset <= brushSize; zOffset++)
  191.         {
  192.             for (int yOffset = -brushSize; yOffset <= brushSize; yOffset++)
  193.             {
  194.                 for (int xOffset = -brushSize; xOffset <= brushSize; xOffset++)
  195.                 {
  196.                     bool xOutOfRange = vertex.x + xOffset <= 1 || vertex.x + xOffset >= chunkDimensions.x - 2;
  197.                     bool yOutOfRange = vertex.y + yOffset <= 1 || vertex.y + yOffset >= chunkDimensions.y - 2;
  198.                     bool zOutOfRange = vertex.z + zOffset <= 1 || vertex.z + zOffset >= chunkDimensions.z - 2;
  199.  
  200.                     if(xOutOfRange || yOutOfRange || zOutOfRange)
  201.                     {
  202.                         continue;
  203.                     }
  204.                    
  205.                     float[] voxel = voxelGrid[vertex.x + xOffset, vertex.y + yOffset, vertex.z + zOffset];
  206.  
  207.                     for (int i = 0; i < 8; i++)
  208.                     {
  209.                         int x = (int)(vertex.x + xOffset + voxelCornerOffsets[i].x);
  210.                         int y = (int)(vertex.y + yOffset + voxelCornerOffsets[i].y);
  211.                         int z = (int)(vertex.z + zOffset + voxelCornerOffsets[i].z);
  212.  
  213.                         float dist = Vector3.Distance(vertex, new Vector3(x, y, z));
  214.  
  215.                         if (dist < brushSize)
  216.                         {
  217.                             voxel[i] = addTerrain ? voxel[i] + .01f : voxel[i] - .01f;
  218.                         }
  219.                     }
  220.                 }
  221.             }
  222.         }
  223.  
  224.         GenerateMesh();
  225.        
  226.     }
  227.  
  228.     public void CreateVoxelGrid()
  229.     {
  230.         voxelGrid = new float[chunkDimensions.x, chunkDimensions.y, chunkDimensions.z][];
  231.  
  232.         for (int z = 0; z < chunkDimensions.z; z++)
  233.         {
  234.             for (int y = 0; y < chunkDimensions.y; y++)
  235.             {
  236.                 for (int x = 0; x < chunkDimensions.x; x++)
  237.                 {
  238.                     CreateVoxel(x, y, z);
  239.                 }
  240.             }
  241.         }
  242.     }
  243.  
  244.     public void CreateVoxel(int x, int y, int z)
  245.     {
  246.         voxelGrid[x, y, z] = new float[8];
  247.  
  248.         for (int i = 0; i < 8; i++)
  249.         {
  250.             voxelGrid[x, y, z][i] = Perlin.Noise((x + voxelCornerOffsets[i].x) * frequency, (y + voxelCornerOffsets[i].y) * frequency, (z + voxelCornerOffsets[i].z) * frequency);
  251.         }
  252.     }
  253. }
  254.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement