From b8aba9e8417ffed37c1060d88ec9bc98281efb30 Mon Sep 17 00:00:00 2001 From: Mark Corbelli Date: Tue, 26 Apr 2022 18:23:48 -0700 Subject: [PATCH] Part 9, byte voxels and bug fixes! --- Assets/VoxelProjectSeries/Scenes/World.unity | 10 ++-- .../Scripts/Camera/TerrainInteractor.cs | 7 +-- .../ComputeShaders/HeightMapNoise.compute | 40 ++++++-------- .../Scripts/ComputeShaders/Voxel.compute | 22 ++++++++ .../Scripts/ComputeShaders/Voxel.compute.meta | 9 ++++ .../ComputeShaders/VoxelCompute.compute | 50 +++++++---------- .../VoxelProjectSeries/Scripts/Data/Voxel.cs | 54 +++++++++++++++++-- .../Scripts/Managers/ActiveVoxelManager.cs | 12 ++--- .../Scripts/Managers/ComputeManager.cs | 13 ++--- .../Scripts/Managers/WorldManager.cs | 14 ++++- 10 files changed, 152 insertions(+), 79 deletions(-) create mode 100644 Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute create mode 100644 Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute.meta diff --git a/Assets/VoxelProjectSeries/Scenes/World.unity b/Assets/VoxelProjectSeries/Scenes/World.unity index 57cdac1..fa69f1d 100644 --- a/Assets/VoxelProjectSeries/Scenes/World.unity +++ b/Assets/VoxelProjectSeries/Scenes/World.unity @@ -274,7 +274,7 @@ MonoBehaviour: ReplaceBlockInPlace: 0 toolMode: 1 toolType: 1 - radiusToAffect: 4 + radiusToAffect: 3 voxelIDToPlace: 0 --- !u!1 &1147823335 GameObject: @@ -500,7 +500,7 @@ MonoBehaviour: - texture: {fileID: 2800000, guid: 64b479ecc48ec9343aa615792b72a11d, type: 3} color: serializedVersion: 2 - rgba: 5091361 + rgba: 45584 metallic: 0.1 smoothness: 0.5 - texture: {fileID: 2800000, guid: cb06f60397b2585409fc1667d04de54a, type: 3} @@ -515,7 +515,7 @@ MonoBehaviour: rgba: 19058 metallic: 0.4 smoothness: 0.1 - - texture: {fileID: 0} + - texture: {fileID: 2800000, guid: 0dc0649bf1b30484099e1017ce7953bc, type: 3} color: serializedVersion: 2 rgba: 55618 @@ -532,9 +532,9 @@ MonoBehaviour: maxHeight: 256 renderDistance: 64 sharedVertices: 0 - useTextures: 0 + useTextures: 1 mainCamera: {fileID: 414495109} - maxChunksToProcessPerFrame: 8 + maxChunksToProcessPerFrame: 6 --- !u!114 &1755072227 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/VoxelProjectSeries/Scripts/Camera/TerrainInteractor.cs b/Assets/VoxelProjectSeries/Scripts/Camera/TerrainInteractor.cs index b6d28e4..92cc24b 100644 --- a/Assets/VoxelProjectSeries/Scripts/Camera/TerrainInteractor.cs +++ b/Assets/VoxelProjectSeries/Scripts/Camera/TerrainInteractor.cs @@ -9,7 +9,7 @@ public class TerrainInteractor : MonoBehaviour public ToolMode toolMode; public ToolType toolType; public int radiusToAffect = 2; - public int voxelIDToPlace = 4; + public byte voxelIDToPlace = 4; void Update() @@ -38,7 +38,7 @@ void Update() if (blockPos.y < 0) return; - float v = voxelIDToPlace == 240 ? 1 : 0; + byte v = (byte)(voxelIDToPlace == 240 ? 100 : 0); if (toolType == ToolType.SingleBlock) WorldManager.Instance.SetVoxelAtCoord(chunkPos, math.round(blockPos), new Voxel() { ID = voxelIDToPlace, ActiveValue = v }); else @@ -50,7 +50,8 @@ void Update() Vector3 modPos = math.round(blockPos + new Vector3(x, y, z)); if ((modPos.y < 0 && voxelIDToPlace != 0) || (modPos.y < 1 && voxelIDToPlace == 0)) continue; - WorldManager.Instance.SetVoxelAtCoord(chunkPos, blockPos + new Vector3(x, y, z), new Voxel() { ID = voxelIDToPlace, ActiveValue = v }); + + WorldManager.Instance.SetVoxelAtCoord(chunkPos, modPos, new Voxel() { ID = voxelIDToPlace, ActiveValue = v }); } } diff --git a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/HeightMapNoise.compute b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/HeightMapNoise.compute index 1e3a11b..99bd87b 100644 --- a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/HeightMapNoise.compute +++ b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/HeightMapNoise.compute @@ -4,12 +4,7 @@ #include "Noise/SimplexNoise.compute" #include "Noise/HashNoise.compute" - -struct Voxel { - int ID; - float ActiveValue; - int CantUpdateFurther; -}; +#include "Voxel.compute" struct NoiseLayer { float gain; @@ -112,8 +107,8 @@ void FillArray(uint3 id : SV_DispatchThreadID) float3 pos = id + chunkPosition + seedOffset; float2 posXZ = pos.xz; - - if (voxelArray[flattenCoord(id)].ID != 0) + + if (GetVoxelData(0, voxelArray[flattenCoord(id)].VoxelData) != 0) return; uint terrainHeight; @@ -122,41 +117,41 @@ void FillArray(uint3 id : SV_DispatchThreadID) NoiseLayer selectednoise = noiseArray[noiseIndex]; Voxel vox; - vox.ID = 0; - vox.ActiveValue = 0; - vox.CantUpdateFurther = 1; + vox.VoxelData = 0; + int voxelId = 0; if (id.y > terrainHeight) { - vox.ID = 0; + voxelId = 0; - if (vox.ID == 0 && id.y <= 2) + if (voxelId == 0 && id.y <= 2) { - vox.ID = 240; + voxelId = 240; InterlockedAdd(count[0], 1); } + UpdateVoxelData(0, voxelId, vox.VoxelData); voxelArray[flattenCoord(id)] = vox; return; } bool isSurfaceBlock = id.y >= terrainHeight - 3; - vox.ID = isSurfaceBlock ? selectednoise.surfaceVoxelId : selectednoise.subSurfaceVoxelId; + voxelId = isSurfaceBlock ? selectednoise.surfaceVoxelId : selectednoise.subSurfaceVoxelId; if (generateCaves && evaluateNoise(pos, terrainHeight) > selectednoise.caveThreshold) { - vox.ID = 0; + voxelId = 0; } if (id.y <= 1 && forceFloor) - vox.ID = selectednoise.surfaceVoxelId; + voxelId = selectednoise.surfaceVoxelId; - if (vox.ID != 0) + if (voxelId != 0) InterlockedAdd(count[0], 1); - if (id.y == terrainHeight && vox.ID != 0 && id.y < 240) + if (id.y == terrainHeight && voxelId != 0 && id.y < 240) { bool placeFoliage = noise(float3(posXZ * 2, seed)) > 0.999; @@ -191,7 +186,8 @@ void FillArray(uint3 id : SV_DispatchThreadID) } } } - + + UpdateVoxelData(0, voxelId, vox.VoxelData); voxelArray[flattenCoord(id)] = vox; } @@ -199,8 +195,6 @@ void FillArray(uint3 id : SV_DispatchThreadID) void ClearArray(uint3 id : SV_DispatchThreadID) { Voxel emptyVoxel; - emptyVoxel.ID = 0; - emptyVoxel.ActiveValue = 0; - emptyVoxel.CantUpdateFurther = 1; + emptyVoxel.VoxelData = 0; voxelArray[flattenCoord(id)] = emptyVoxel; } \ No newline at end of file diff --git a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute new file mode 100644 index 0000000..7e97a29 --- /dev/null +++ b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute @@ -0,0 +1,22 @@ +struct Voxel +{ + int VoxelData; +}; + +struct VoxelDetails +{ + float color; + float metallic; + float smoothness; +}; + +uint GetVoxelData(uint component, int voxelData) +{ + uint shift = (8 * component); + return ((voxelData & (0xff << shift)) >> shift); +} + +void UpdateVoxelData(int component, int value, inout uint voxelData) +{ + voxelData |= value << (8 * component); +} \ No newline at end of file diff --git a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute.meta b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute.meta new file mode 100644 index 0000000..0a5470f --- /dev/null +++ b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/Voxel.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: de199a1b93bac0d47a6f483a0ba14275 +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 4 + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/VoxelCompute.compute b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/VoxelCompute.compute index 958cab3..90866e2 100644 --- a/Assets/VoxelProjectSeries/Scripts/ComputeShaders/VoxelCompute.compute +++ b/Assets/VoxelProjectSeries/Scripts/ComputeShaders/VoxelCompute.compute @@ -1,19 +1,7 @@ // Each #kernel tells which function to compile; you can have many kernels #pragma kernel CSMain #include "VoxelValues.cginc" - -struct VoxelDetails -{ - float color; - float metallic; - float smoothness; -}; - -struct Voxel { - int ID; - float ActiveValue; - int CantUpdateFurther; -}; +#include "Voxel.compute" struct sharedVert { @@ -63,12 +51,12 @@ uint flattenCoord(uint3 idx) bool VoxelIsSolid(uint3 pos) { - return voxelArray[flattenCoord(pos)].ID != 0; + return GetVoxelData(0, voxelArray[flattenCoord(pos)].VoxelData) != 0; } bool VoxelIsTransparent(uint3 pos) { - return voxelArray[flattenCoord(pos)].ID == 240; + return GetVoxelData(0, voxelArray[flattenCoord(pos)].VoxelData) == 240; } static uint3 getCellCenterForIDX(int idx, int axis, int corner) @@ -98,6 +86,7 @@ void calculateContour(uint3 blockCoord, out float3 position, out float3 normal, uint3 vWorldPos = blockCoord + vertexPos; //take local block coord, add the cubed position int counter = 0; currentCell = voxelArray[flattenCoord(blockCoord)]; + int currentCellId = GetVoxelData(0, currentCell.VoxelData); for (int ax = 0; ax < 3; ax++) { @@ -110,17 +99,17 @@ void calculateContour(uint3 blockCoord, out float3 position, out float3 normal, adjacentRootCell = voxelArray[flattenCoord(adjacentCellRoot)]; adjacentCell = voxelArray[flattenCoord(adjacentCellPos)]; - adjacentRootCellId = adjacentRootCell.ID; - adjacentCellId = adjacentCell.ID; + adjacentRootCellId = GetVoxelData(0, adjacentRootCell.VoxelData); + adjacentCellId = GetVoxelData(0, adjacentCell.VoxelData); - if (adjacentRootCell.ID == 240 && currentCell.ID != 240) + if (adjacentRootCellId == 240 && currentCellId != 240) adjacentRootCellId = 0; - if (adjacentCell.ID == 240 && currentCell.ID != 240) + if (adjacentCellId == 240 && currentCellId != 240) adjacentCellId = 0; - if (currentCell.ID == 240 && adjacentRootCell.ID != 240) + if (currentCellId == 240 && adjacentRootCellId != 240) adjacentRootCellId = 0; - if (currentCell.ID == 240 && adjacentCell.ID != 240) + if (currentCellId == 240 && adjacentCellId != 240) adjacentCellId = 0; adjacentRootCellDensity = adjacentRootCellId != 0 ? 1 : 0; @@ -156,15 +145,16 @@ void CSMain(uint3 id : SV_DispatchThreadID) return; Voxel block = voxelArray[flattenCoord(id)]; + int blockID = GetVoxelData(0, block.VoxelData); - if (block.ID == 0) + if (blockID == 0) return; float3 faceVertices[4]; float3 faceNorms[4]; - float4 color = float4(block.ID == 240 ? 240 : - (useTextures && voxelColors[block.ID - 1].color == -1 ? ((float) block.ID - 1) : voxelColors[block.ID - 1].color), - packFloats(voxelColors[block.ID - 1].metallic, voxelColors[block.ID - 1].smoothness), 0, 0); + float4 color = float4(blockID == 240 ? 240 : + (useTextures && voxelColors[blockID - 1].color == -1 ? ((float) blockID - 1) : voxelColors[blockID - 1].color), + packFloats(voxelColors[blockID - 1].metallic, voxelColors[blockID - 1].smoothness), 0, 0); uint vertCount = 0; uint triCount = 0; @@ -181,7 +171,7 @@ void CSMain(uint3 id : SV_DispatchThreadID) if (VoxelIsSolid(id + voxelFaceChecks[i]) && !VoxelIsTransparent(id + voxelFaceChecks[i])) continue; - if (block.ID == 240 && VoxelIsTransparent(id + voxelFaceChecks[i])) + if (blockID == 240 && VoxelIsTransparent(id + voxelFaceChecks[i])) continue; //Draw this face @@ -189,7 +179,7 @@ void CSMain(uint3 id : SV_DispatchThreadID) if (!sharedVertices) { InterlockedAdd(counter[0], 6, vertCount); - if (block.ID != 240) + if (blockID != 240) InterlockedAdd(counter[1], 6, triCount); else InterlockedAdd(counter[2], 6, triCount); @@ -206,7 +196,7 @@ void CSMain(uint3 id : SV_DispatchThreadID) color.b = voxelUVs[voxelTris[i][k]].x; color.a = voxelUVs[voxelTris[i][k]].y; colorBuffer[vertCount + k] = color; - if (block.ID != 240) + if (blockID != 240) indexBuffer[triCount + k] = vertCount + k; else transparentIndexBuffer[triCount + k] = vertCount + k; @@ -214,7 +204,7 @@ void CSMain(uint3 id : SV_DispatchThreadID) } else { - if (block.ID != 240) + if (blockID != 240) InterlockedAdd(counter[1], 6, triCount); else InterlockedAdd(counter[2], 6, triCount); @@ -239,7 +229,7 @@ void CSMain(uint3 id : SV_DispatchThreadID) colorBuffer[vertCount] = color; } - if (block.ID != 240) + if (blockID != 240) indexBuffer[triCount + k] = sharedVerts[idx].index; else transparentIndexBuffer[triCount + k] = sharedVerts[idx].index; diff --git a/Assets/VoxelProjectSeries/Scripts/Data/Voxel.cs b/Assets/VoxelProjectSeries/Scripts/Data/Voxel.cs index 2384645..9e974dd 100644 --- a/Assets/VoxelProjectSeries/Scripts/Data/Voxel.cs +++ b/Assets/VoxelProjectSeries/Scripts/Data/Voxel.cs @@ -1,11 +1,59 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; + public struct Voxel { - public int ID; - public float ActiveValue; - public int CantUpdateFurther; + public int voxelData; + + public byte ID + { + get + { + return GetVoxelData(0); + } + set + { + UpdateVoxelData(0, value); + } + } + + public byte ActiveValue + { + get + { + return GetVoxelData(1); + } + set + { + UpdateVoxelData(1, value); + } + } + //From root coord up - technically a range of 0-100 + public byte terrainHeight + { + get + { + return GetVoxelData(2); + } + set + { + UpdateVoxelData(2, value); + } + } + + + + byte GetVoxelData(byte component) + { + byte shift = (byte)(8 * component); + return (byte)((voxelData & (0xff << shift)) >> shift); + } + + void UpdateVoxelData(int component, byte value) + { + voxelData |= value << (8 * component); + } public bool isSolid { diff --git a/Assets/VoxelProjectSeries/Scripts/Managers/ActiveVoxelManager.cs b/Assets/VoxelProjectSeries/Scripts/Managers/ActiveVoxelManager.cs index 27b076a..98cc4b4 100644 --- a/Assets/VoxelProjectSeries/Scripts/Managers/ActiveVoxelManager.cs +++ b/Assets/VoxelProjectSeries/Scripts/Managers/ActiveVoxelManager.cs @@ -19,16 +19,16 @@ static void UpdateWater(Vector3 chunkPos, Vector3 voxelPos, Voxel vox, ref Noise { Vector3 down = voxelPos + new Vector3(0, -1, 0); - if (vox.ActiveValue >= 0.15 && noiseBuffer.voxelArray[down].ID == 0 && !WorldManager.Instance.activeVoxels[chunkPos].ContainsKey(down) && down.y > 0) + if (vox.ActiveValue >= 15 && noiseBuffer.voxelArray[down].ID == 0 && !WorldManager.Instance.activeVoxels[chunkPos].ContainsKey(down) && down.y > 0) { //Air below, continue to traverse down - vox.CantUpdateFurther = 1; + vox.ActiveValue = 0; WorldManager.Instance.SetVoxelAtCoord(chunkPos, voxelPos, vox); - WorldManager.Instance.SetVoxelAtCoord(chunkPos, down, new Voxel() { ID = vox.ID, ActiveValue = 1, CantUpdateFurther = 0 }); + WorldManager.Instance.SetVoxelAtCoord(chunkPos, down, new Voxel() { ID = vox.ID, ActiveValue = 100}); return; } //If hitting solid and not water, first hit onto the floor as well, helps prevent rerunning updates - if (vox.ActiveValue >= 0.15 && noiseBuffer.voxelArray[down].ID != 0 && noiseBuffer.voxelArray[down].ID != 240) + if (vox.ActiveValue >= 15 && noiseBuffer.voxelArray[down].ID != 0 && noiseBuffer.voxelArray[down].ID != 240) { for (int i = -1; i <= 1; i++) { @@ -52,8 +52,7 @@ static void UpdateWater(Vector3 chunkPos, Vector3 voxelPos, Voxel vox, ref Noise if (v.ID == 0) { v.ID = vox.ID; - v.ActiveValue = vox.ActiveValue - 0.15f; - v.CantUpdateFurther = 0; + v.ActiveValue = (byte)(vox.ActiveValue - 15); WorldManager.Instance.SetVoxelAtCoord(chunkPos, modPos, v); } @@ -63,7 +62,6 @@ static void UpdateWater(Vector3 chunkPos, Vector3 voxelPos, Voxel vox, ref Noise } } - vox.CantUpdateFurther = 1; WorldManager.Instance.SetVoxelAtCoord(chunkPos, voxelPos, vox); } } \ No newline at end of file diff --git a/Assets/VoxelProjectSeries/Scripts/Managers/ComputeManager.cs b/Assets/VoxelProjectSeries/Scripts/Managers/ComputeManager.cs index 902f1c2..eae7ad2 100644 --- a/Assets/VoxelProjectSeries/Scripts/Managers/ComputeManager.cs +++ b/Assets/VoxelProjectSeries/Scripts/Managers/ComputeManager.cs @@ -216,13 +216,14 @@ public void DisposeAllBuffers() static float ColorfTo32(Color32 c) { if (c.r == 0) - c.r = 1; + c.r = 5; if (c.g == 0) - c.g = 1; + c.g = 5; if (c.b == 0) - c.b = 1; + c.b = 5; if (c.a == 0) - c.a = 1; + c.a = 5; + return (c.r << 24) | (c.g << 16) | (c.b << 8) | (c.a); } @@ -272,7 +273,7 @@ public void InitializeBuffer() countBuffer.SetData(new uint[] {0, 0}); voxelArray = new IndexedArray(); - noiseBuffer = new ComputeBuffer(WorldManager.WorldSettings.ChunkCount, 12); + noiseBuffer = new ComputeBuffer(WorldManager.WorldSettings.ChunkCount, 4); Initialized = true; } @@ -317,7 +318,7 @@ public void InitializeBuffer() colorBuffer ??= new ComputeBuffer(maxVertices*3, 16); normalBuffer ??= new ComputeBuffer(maxNormals, 12); indexBuffer ??= new ComputeBuffer(maxTris*3, 4); - modifiedNoiseBuffer = new ComputeBuffer(WorldManager.WorldSettings.ChunkCount, 12); + modifiedNoiseBuffer = new ComputeBuffer(WorldManager.WorldSettings.ChunkCount, 4); transparentIndexBuffer ??= new ComputeBuffer(maxTris*3, 4); Initialized = true; diff --git a/Assets/VoxelProjectSeries/Scripts/Managers/WorldManager.cs b/Assets/VoxelProjectSeries/Scripts/Managers/WorldManager.cs index 0fa19ca..9beca9d 100644 --- a/Assets/VoxelProjectSeries/Scripts/Managers/WorldManager.cs +++ b/Assets/VoxelProjectSeries/Scripts/Managers/WorldManager.cs @@ -196,7 +196,7 @@ void CheckActiveVoxelsLoop() List toRemove = new List(); foreach (var activeVoxelKVP in kvp.Value) { - if (activeVoxelKVP.Value.ActiveValue < 0.15f) + if (activeVoxelKVP.Value.ActiveValue < 15) { toRemove.Add(activeVoxelKVP.Key); continue; @@ -450,7 +450,7 @@ public void SetVoxelAtCoord(Vector3 chunkPosition, Vector3 index, Voxel value) canPlaceWithinChunk = false; } - bool isActive = value.ID == 240; + bool isActive = value.ID == 240 && value.ActiveValue > 15; if (neighbor > 0) { for (int i = 0; i < neighbor; i++) @@ -518,6 +518,16 @@ public void SetVoxelAtCoord(Vector3 chunkPosition, Vector3 index, Voxel value) else modifiedVoxels[chunkPosition][index] = value; } + + if (activeChunks.ContainsKey(chunkPosition)) + { + Chunk c = activeChunks[chunkPosition]; + if (c.chunkState != Chunk.ChunkState.WaitingToMesh) + { + c.chunkState = Chunk.ChunkState.WaitingToMesh; + chunksNeedRegenerated.Enqueue(c.chunkPosition); + } + } } }