├── .gitattributes ├── Assets ├── Heightmaps │ ├── circle.png │ ├── terrainheightmap.png │ ├── Heightmap Terrain Presets.meta │ ├── Heightmap Terrain Presets │ │ ├── DefaultHeightmapTerrain.asset.meta │ │ └── DefaultHeightmapTerrain.asset │ ├── circle.png.meta │ └── terrainheightmap.png.meta ├── Prefabs │ ├── Chunk.prefab.meta │ └── Chunk.prefab ├── Prefabs.meta ├── Scenes.meta ├── Scripts.meta ├── Shaders.meta ├── Heightmaps.meta ├── Materials.meta ├── VoxelTerrain.meta ├── Scenes │ ├── Heightmap World Example.unity.meta │ └── Procedural World Example.unity.meta ├── Scripts │ ├── Player.meta │ └── Player │ │ ├── PlayerCamera.cs.meta │ │ ├── TerrainDeformer.cs.meta │ │ └── PlayerCamera.cs ├── VoxelTerrain │ ├── Core.meta │ ├── Modules.meta │ ├── Core │ │ ├── Chunk.meta │ │ ├── Meshing.meta │ │ ├── Settings.meta │ │ ├── Utilities.meta │ │ ├── VoxelData.meta │ │ ├── World.meta │ │ ├── Meshing │ │ │ ├── Data.meta │ │ │ ├── MesherJob.cs.meta │ │ │ ├── NativeCounter.cs.meta │ │ │ ├── VoxelMesher.cs.meta │ │ │ ├── Data │ │ │ │ ├── VoxelCorners.cs.meta │ │ │ │ ├── MeshingVertexData.cs.meta │ │ │ │ ├── MeshingVertexData.cs │ │ │ │ └── VoxelCorners.cs │ │ │ ├── VoxelMesher.cs │ │ │ ├── MesherJob.cs │ │ │ └── NativeCounter.cs │ │ ├── VoxelTerrain.Core.asmdef.meta │ │ ├── Utilities │ │ │ ├── Intersection.meta │ │ │ ├── BoundsUtilities.cs.meta │ │ │ ├── IndexUtilities.cs.meta │ │ │ ├── LookupTables.cs.meta │ │ │ ├── VectorUtilities.cs.meta │ │ │ ├── CoordinateUtilities.cs.meta │ │ │ ├── DistanceUtilities.cs.meta │ │ │ ├── JobHandleWithData.cs.meta │ │ │ ├── Intersection │ │ │ │ ├── IntersectionUtilities.cs.meta │ │ │ │ ├── PlaneLineIntersectionResult.cs.meta │ │ │ │ ├── PlaneLineIntersectionResult.cs │ │ │ │ └── IntersectionUtilities.cs │ │ │ ├── JobHandleWithData.cs │ │ │ ├── LookupTables.cs │ │ │ ├── BoundsUtilities.cs │ │ │ ├── DistanceUtilities.cs │ │ │ ├── IndexUtilities.cs │ │ │ └── VectorUtilities.cs │ │ ├── Chunk │ │ │ ├── ChunkStore.cs.meta │ │ │ ├── ChunkProperties.cs.meta │ │ │ ├── ChunkProvider.cs.meta │ │ │ ├── ChunkUpdater.cs.meta │ │ │ ├── ChunkStore.cs │ │ │ ├── ChunkProperties.cs │ │ │ ├── ChunkProvider.cs │ │ │ └── ChunkUpdater.cs │ │ ├── World │ │ │ ├── VoxelWorld.cs.meta │ │ │ └── VoxelWorld.cs │ │ ├── Settings │ │ │ ├── WorldSettings.cs.meta │ │ │ └── WorldSettings.cs │ │ ├── VoxelData │ │ │ ├── PerChunkStore.cs.meta │ │ │ ├── PerVoxelStore.cs.meta │ │ │ ├── VoxelColorStore.cs.meta │ │ │ ├── VoxelDataStore.cs.meta │ │ │ ├── VoxelDataVolume.cs.meta │ │ │ ├── VoxelDataGenerator.cs.meta │ │ │ ├── IVoxelDataGenerationJob.cs.meta │ │ │ ├── IVoxelDataGenerationJob.cs │ │ │ ├── VoxelColorStore.cs │ │ │ └── VoxelDataGenerator.cs │ │ └── VoxelTerrain.Core.asmdef │ └── Modules │ │ ├── Chunk.meta │ │ ├── World.meta │ │ ├── Meshing.meta │ │ ├── VoxelData.meta │ │ ├── TerrainSettings.meta │ │ ├── Meshing │ │ ├── MarchingCubes.meta │ │ └── MarchingCubes │ │ │ ├── VertexList.cs.meta │ │ │ ├── MarchingCubesJob.cs.meta │ │ │ ├── MarchingCubesMesher.cs.meta │ │ │ ├── MarchingCubesFunctions.cs.meta │ │ │ ├── MarchingCubesLookupTables.cs.meta │ │ │ ├── MarchingCubesMesher.cs │ │ │ ├── VertexList.cs │ │ │ ├── MarchingCubesJob.cs │ │ │ └── MarchingCubesFunctions.cs │ │ ├── VoxelTerrain.Modules.asmdef.meta │ │ ├── Chunk │ │ ├── ProceduralChunkProvider.cs.meta │ │ └── ProceduralChunkProvider.cs │ │ ├── World │ │ ├── HeightmapWorldGenerator.cs.meta │ │ ├── ProceduralWorldGenerator.cs.meta │ │ ├── HeightmapWorldGenerator.cs │ │ └── ProceduralWorldGenerator.cs │ │ ├── VoxelData │ │ ├── HeightmapVoxelDataGenerator.cs.meta │ │ ├── ProceduralVoxelDataGenerator.cs.meta │ │ ├── HeightmapTerrainVoxelDataCalculationJob.cs.meta │ │ ├── ProceduralTerrainVoxelDataCalculationJob.cs.meta │ │ ├── ProceduralVoxelDataGenerator.cs │ │ ├── HeightmapVoxelDataGenerator.cs │ │ ├── ProceduralTerrainVoxelDataCalculationJob.cs │ │ └── HeightmapTerrainVoxelDataCalculationJob.cs │ │ ├── TerrainSettings │ │ ├── HeightmapTerrainSettings.cs.meta │ │ ├── ProceduralTerrainSettings.cs.meta │ │ ├── ProceduralTerrainSettings.cs │ │ └── HeightmapTerrainSettings.cs │ │ └── VoxelTerrain.Modules.asmdef ├── VoxelTerrain.Tests.meta ├── VoxelTerrain.Tests │ ├── Core.meta │ ├── Modules.meta │ ├── Core │ │ ├── MeshingTests.meta │ │ ├── UtilitiesTests.meta │ │ ├── ChunkUtilitiesTests.meta │ │ ├── VoxelDataVolumeTests.meta │ │ ├── VoxelTerrain.Core.Tests.asmdef.meta │ │ ├── UtilitiesTests │ │ │ ├── ModTests.cs.meta │ │ │ ├── IndexToXyzTests.cs.meta │ │ │ ├── ToInt3Tests.cs.meta │ │ │ ├── XyzToIndexTests.cs.meta │ │ │ ├── ToVectorIntTests.cs.meta │ │ │ ├── FloorToMultipleOfXTests.cs.meta │ │ │ ├── GetIntersectionAreaTests.cs.meta │ │ │ ├── PlaneLineIntersectionTests.cs.meta │ │ │ ├── ModTests.cs │ │ │ ├── FloorToMultipleOfXTests.cs │ │ │ ├── ToVectorIntTests.cs │ │ │ ├── ToInt3Tests.cs │ │ │ ├── IndexToXyzTests.cs │ │ │ ├── XyzToIndexTests.cs │ │ │ ├── GetIntersectionAreaTests.cs │ │ │ └── PlaneLineIntersectionTests.cs │ │ ├── MeshingTests │ │ │ ├── NativeCounterTests.cs.meta │ │ │ └── NativeCounterTests.cs │ │ ├── ChunkUtilitiesTests │ │ │ ├── CoordinateUtilitiesTests.cs.meta │ │ │ └── CoordinateUtilitiesTests.cs │ │ ├── VoxelDataVolumeTests │ │ │ ├── VoxelDataVolumeTests.cs.meta │ │ │ └── VoxelDataVolumeTests.cs │ │ └── VoxelTerrain.Core.Tests.asmdef │ └── Modules │ │ ├── WorldTests.meta │ │ ├── MeshingTests.meta │ │ ├── VoxelTerrain.Modules.Tests.asmdef.meta │ │ ├── MeshingTests │ │ ├── MarchingCubesTests.meta │ │ └── MarchingCubesTests │ │ │ └── MarchingCubesFunctionsTests.cs.meta │ │ └── VoxelTerrain.Modules.Tests.asmdef ├── VertexColorMaterial.mat.meta ├── Materials │ ├── Triplanar Shading.mat.meta │ └── Triplanar Shading.mat ├── Shaders │ ├── Triplanar Shader.shader.meta │ └── Triplanar Shader.shader └── VertexColorMaterial.mat ├── ProjectSettings ├── ProjectVersion.txt ├── ClusterInputManager.asset ├── NetworkManager.asset ├── XRSettings.asset ├── TimeManager.asset ├── VFXManager.asset ├── EditorBuildSettings.asset ├── BurstAotSettings_StandaloneWindows.json ├── AudioManager.asset ├── TagManager.asset ├── EditorSettings.asset ├── PresetManager.asset ├── UnityConnectSettings.asset ├── DynamicsManager.asset ├── Physics2DSettings.asset ├── NavMeshAreas.asset ├── GraphicsSettings.asset └── InputManager.asset ├── Packages └── manifest.json ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Assets/Heightmaps/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eldemarkki/Marching-Cubes-Terrain/HEAD/Assets/Heightmaps/circle.png -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2019.3.15f1 2 | m_EditorVersionWithRevision: 2019.3.15f1 (59ff3e03856d) 3 | -------------------------------------------------------------------------------- /Assets/Heightmaps/terrainheightmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Eldemarkki/Marching-Cubes-Terrain/HEAD/Assets/Heightmaps/terrainheightmap.png -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /Assets/Prefabs/Chunk.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d3008c1365ac1cb49b849d43fffdc19e 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2b4aaaac306311499459e651ffa8c58 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 716fc49c0a0c0614791a670768976209 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca90e8ce0d35b044cbbc5fa04e45a622 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8decea629e652246ac5135df54c1a98 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /Assets/Heightmaps.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c3c6f4417d1093469fdcfa8b90fde28 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a869d5378e598f4c9b821ece5cf852d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 90b8ebac1963a364f847499726d66989 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scenes/Heightmap World Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d5a5b0b410836b45ad7e6bf30ec1e9c 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scenes/Procedural World Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2c5cddc6c031b8b489bfc1264e60bb24 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scripts/Player.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9087dfe2cc3e10a4c9e1951a62a5f107 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aad75f62a17578a4faf116b0d13a541b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff96f12ef0cf9ab4084f4ed63a3455f1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 816df23405de2334399f4889b92487e1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe69be840f3b22c45878a41155fc8a43 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dfde9d0260a3dc54f82f5345d46f95d6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ca93dd062277114498cf2f1922b1f12 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5b169ebe28a0634f8b211235935b9d2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Settings.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbdf8c6d681549b4ab2c6ab88fa42d42 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e2ca2b9bda48fc24fb3de22e9f74e9b9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e93627528ea18344a25b6fb86c4994a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/World.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e02ddd589e98ad64381fed09240298d7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Chunk.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a21125a24156c1d4fad75d66f42b8c59 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/World.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73ec69dfe74011140b940d61b01537c4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 167840751702d0f4d94734947b59be72 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelTerrain.Core.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ff95134247574242a0f8bcdbf3bdc70 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: addc2312dd40c7e42b50f1020651e89f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d358380057200764a99e6d19564272cb 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Heightmaps/Heightmap Terrain Presets.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad883cb9ab34e7a4e96eaef2addcc11f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VertexColorMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f4ec41ce043e2940a19224905527b38 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/MeshingTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0c50375e9baf0648b8f65f5384088fd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/WorldTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9fedb4671decadb43b62b05edc55ff36 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/TerrainSettings.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a997d4f10c9521b47a010d6ed189552d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b386bf31d498954884a1f3543e76a51 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/MeshingTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3ef0b6170112ca94786f616bbbb9553b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/Intersection.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 774c2310663fdc0468488052050420e0 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac2bd5e8fecf63944b1b99df1b9474fd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelTerrain.Modules.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec6dc5c40c3d1164fa192bfa6f5db865 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Materials/Triplanar Shading.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c10a75e53f4f277418f0e3a03569e6ce 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/ChunkUtilitiesTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb6f507884caa944b86f549365bc7eef 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/VoxelDataVolumeTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac4e9403346d9584caafde4fc071f24e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/VoxelTerrain.Core.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 83835746ea3fcba4e819c4e703967f86 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/VoxelTerrain.Modules.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb8da5dee15273b4792b76e71ac760e4 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/MeshingTests/MarchingCubesTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dbd2f188f539ed84e89f8331cc86a5a1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.1 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.burst": "1.3.3", 4 | "com.unity.jobs": "0.2.9-preview.15", 5 | "com.unity.ugui": "1.0.0", 6 | "com.unity.modules.physics": "1.0.0", 7 | "com.unity.modules.ui": "1.0.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Assets/Heightmaps/Heightmap Terrain Presets/DefaultHeightmapTerrain.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b09c379fa88978d4d83dcf65edad60bf 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Shaders/Triplanar Shader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db8c18db5cb480d4c8523e1b745f5af5 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Scripts/Player/PlayerCamera.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fceb88e3d7c83554b9539a0da91feda1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Player/TerrainDeformer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b25c4f659e9d0f84d9897b9f38efef04 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 100 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkStore.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35a265702d5a74545892631579dfcbd8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/World/VoxelWorld.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4ea9986f028d4e04b91a350741140621 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkProperties.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 00de47b60a9ba744da3bbdc17cd942fd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e72216e47af7e58408454b827e439157 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkUpdater.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7f754d5f5e2253a409594cb8cd7a4278 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/MesherJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d61cdfeda8139ac43b47639051b8055a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/NativeCounter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2505c9fe53002c644b50fbb09d80ae1e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/VoxelMesher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc122460c884a7744aa5b708cfc99771 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/Data/VoxelCorners.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 604a276c9361e0b48bac99b9446cff8c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Settings/WorldSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2e0cd28018556c40811d70f1621df66 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/BoundsUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48439e638aa2cb140b4b3b6f17204f0c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/IndexUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b979723edb3aefa48b4e069eaf2e546e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/LookupTables.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 679090026106fa84398558c6f071420a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/VectorUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73e6a8cc3e246194d90a1ccd6c923cf1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/PerChunkStore.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6e9379ca73a25741a49fcb6d292c477 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/PerVoxelStore.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 702596fe13400164cb93d8ea72e39725 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelColorStore.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e66f3dd9a72a0f2449b26a410bde7d38 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelDataStore.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c3117ed0cc55e1846874b46688138374 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelDataVolume.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 42b915ef1200c3844bed576d3a837b6c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ModTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d145f5c2b18ed842a4ff0b40cfd4c2e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/Data/MeshingVertexData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe34939e1b76afe45a211c759f9de425 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/CoordinateUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7cb35d6a1b2ed44c8ba74df4220f65f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/DistanceUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac4b697b7ff3073458a055ea76817d29 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/JobHandleWithData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b98fb069e8c9f5942bd60fdf274a2118 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelDataGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d73a1710889a074f8244fb35cb2b8ab 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/IndexToXyzTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a89f89788505aab4391174e602da3105 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ToInt3Tests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 081907ffde2bcd049b6ad55b63553ea9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/XyzToIndexTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb8674bc8d15c5a4b9607fb1aedaa841 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/IVoxelDataGenerationJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1cea74814d0d0ed4ab5b130a9a377873 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Chunk/ProceduralChunkProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cf2139c3087ce95439212cb2d0c8091a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/VertexList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef1904457e6a9b1429b338df0710fbd2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/World/HeightmapWorldGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b126af6880531864c942905cea6158c9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/World/ProceduralWorldGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0f97e4ff6bf8c0541aca7cfae307087f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/MeshingTests/NativeCounterTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b77183f52692984eaf1d44a691b3ee5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ToVectorIntTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 031c8469554469942a6484a382c33f3a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2a1d711be887de4891ba2e4a76a7028 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/HeightmapVoxelDataGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af9d5b8307eaa9f499db7bcc0a15c223 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/ProceduralVoxelDataGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4cc09cb714c6b8345896680d67a9b421 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/FloorToMultipleOfXTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0ba00df0479f64c4da49ef7927d23dce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/GetIntersectionAreaTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cf434a8b1706ec438fbb3d0ae2c0f9f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/Intersection/IntersectionUtilities.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72934639dbdd3b646aef5f60c9429493 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesMesher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8ef462ca49da6db4d89a0aaa43a026c4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/TerrainSettings/HeightmapTerrainSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 440bc03213899e148bed19eec6e99127 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/TerrainSettings/ProceduralTerrainSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 389b1d0824494f84cb1b877da681e3aa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: 8 | - enabled: 1 9 | path: Assets/Examples/Scenes/Procedural World Example.unity 10 | guid: 2c5cddc6c031b8b489bfc1264e60bb24 11 | m_configObjects: {} 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/ChunkUtilitiesTests/CoordinateUtilitiesTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2efd6c6ac28a03545b02723346305385 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/PlaneLineIntersectionTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 650fe6ec44610bb46b2bc3e67be3194c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/VoxelDataVolumeTests/VoxelDataVolumeTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e032e88065fc040408f92a50b4b1c7fc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/Intersection/PlaneLineIntersectionResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef3d64bef79f4e7ca703ce2c15e8f337 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesFunctions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79957911854a43d458793b9bc537dea6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesLookupTables.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8390fa0bd304238458d03fba06ec8ff6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/HeightmapTerrainVoxelDataCalculationJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5373d320718af2240a2fff3a7fd2f8a1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/ProceduralTerrainVoxelDataCalculationJob.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 544bf4c1b0890a047ae74b642cff373a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/MeshingTests/MarchingCubesTests/MarchingCubesFunctionsTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3464cc25b0a0394ab02b2bff7d824c8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /ProjectSettings/BurstAotSettings_StandaloneWindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "MonoBehaviour": { 3 | "m_Enabled": true, 4 | "m_EditorHideFlags": 0, 5 | "m_Name": "", 6 | "m_EditorClassIdentifier": "Unity.Burst.Editor:Unity.Burst.Editor:BurstPlatformAotSettings", 7 | "DisableOptimisations": false, 8 | "DisableSafetyChecks": true, 9 | "DisableBurstCompilation": false 10 | } 11 | } -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 1024 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_AmbisonicDecoderPlugin: 16 | m_DisableAudio: 0 17 | m_VirtualizeEffects: 1 18 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - PostProcessing 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelTerrain.Core.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoxelTerrain.Core", 3 | "references": [ 4 | "GUID:2665a8d13d1b3f18800f46e256720795", 5 | "GUID:e0cd26848372d4e5c891c569017e11f1", 6 | "GUID:8a2eafa29b15f444eb6d74f94a930e1d", 7 | "GUID:d8b63aba1907145bea998dd612889d6b" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": true, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/JobHandleWithData.cs: -------------------------------------------------------------------------------- 1 | using Unity.Jobs; 2 | 3 | namespace Eldemarkki.VoxelTerrain.Utilities 4 | { 5 | /// 6 | /// A class that associates a JobHandle to some data 7 | /// 8 | /// The type of the data 9 | public class JobHandleWithData 10 | { 11 | /// 12 | /// The job handle 13 | /// 14 | public JobHandle JobHandle { get; set; } 15 | 16 | /// 17 | /// The associated data 18 | /// 19 | public T JobData { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /Assets/Heightmaps/Heightmap Terrain Presets/DefaultHeightmapTerrain.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 440bc03213899e148bed19eec6e99127, type: 3} 13 | m_Name: DefaultHeightmapTerrain 14 | m_EditorClassIdentifier: 15 | heightmap: {fileID: 2800000, guid: c592a59b98b6d2149bd5cdf21483ecd0, type: 3} 16 | amplitude: 35 17 | heightOffset: 0 18 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/IVoxelDataGenerationJob.cs: -------------------------------------------------------------------------------- 1 | using Unity.Jobs; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.VoxelData 5 | { 6 | /// 7 | /// An interface for voxel data generation jobs 8 | /// 9 | public interface IVoxelDataGenerationJob : IJob 10 | { 11 | /// 12 | /// The sampling point's world position offset 13 | /// 14 | int3 WorldPositionOffset { get; set; } 15 | 16 | /// 17 | /// The generated voxel data 18 | /// 19 | VoxelDataVolume OutputVoxelData { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ModTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 5 | { 6 | public class ModTests 7 | { 8 | [TestCase(10, 16, 74, 5, 0, 1, 4)] 9 | [TestCase(84, -24, 0, 8, 4, 0, 0)] 10 | [TestCase(-85, -8, 14, 3, 2, 1, 2 )] 11 | [TestCase(20, 35, 71, 35, 20, 0, 1)] 12 | public void TestMod(int nx, int ny, int nz, int x, int expectedX, int expectedY, int expectedZ) 13 | { 14 | Assert.AreEqual(new int3(expectedX, expectedY, expectedZ), VectorUtilities.Mod(new int3(nx, ny, nz), x)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelTerrain.Modules.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoxelTerrain.Modules", 3 | "references": [ 4 | "GUID:6ff95134247574242a0f8bcdbf3bdc70", 5 | "GUID:2665a8d13d1b3f18800f46e256720795", 6 | "GUID:e0cd26848372d4e5c891c569017e11f1", 7 | "GUID:d8b63aba1907145bea998dd612889d6b", 8 | "GUID:8a2eafa29b15f444eb6d74f94a930e1d" 9 | ], 10 | "includePlatforms": [], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": true, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. What were you doing when the bug happened? Did something not work, or did it throw an error? What error (include stacktrace) 12 | 13 | **Branch** 14 | Which branch did this bug happen on? 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 19 | **Expected behavior** 20 | This should have happened instead: 21 | 22 | **Screenshots** 23 | Include screenshots if applicable 24 | 25 | **Other** 26 | Some other information that may be relevant 27 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/Intersection/PlaneLineIntersectionResult.cs: -------------------------------------------------------------------------------- 1 | namespace Eldemarkki.VoxelTerrain.Utilities.Intersection 2 | { 3 | /// 4 | /// A plane-line intersection result 5 | /// 6 | public enum PlaneLineIntersectionResult 7 | { 8 | /// 9 | /// The plane and the line don't intersect 10 | /// 11 | NoHit, 12 | 13 | /// 14 | /// The plane and the line intersected once 15 | /// 16 | OneHit, 17 | 18 | /// 19 | /// The line is inside the plane parallel to it 20 | /// 21 | ParallelInsidePlane 22 | } 23 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/LookupTables.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | 3 | namespace Eldemarkki.VoxelTerrain.Utilities 4 | { 5 | /// 6 | /// A class to hold miscellaneous lookup tables 7 | /// 8 | public static class LookupTables 9 | { 10 | /// 11 | /// The corners of a voxel 12 | /// 13 | public static readonly int3[] CubeCorners = 14 | { 15 | new int3(0, 0, 0), 16 | new int3(1, 0, 0), 17 | new int3(1, 0, 1), 18 | new int3(0, 0, 1), 19 | new int3(0, 1, 0), 20 | new int3(1, 1, 0), 21 | new int3(1, 1, 1), 22 | new int3(0, 1, 1) 23 | }; 24 | } 25 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/VoxelTerrain.Core.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoxelTerrain.Core.Tests", 3 | "references": [ 4 | "UnityEngine.TestRunner", 5 | "UnityEditor.TestRunner", 6 | "Unity.Mathematics", 7 | "Unity.Collections", 8 | "Unity.Burst", 9 | "Unity.Jobs", 10 | "VoxelTerrain.Core" 11 | ], 12 | "includePlatforms": [ 13 | "Editor" 14 | ], 15 | "excludePlatforms": [], 16 | "allowUnsafeCode": true, 17 | "overrideReferences": true, 18 | "precompiledReferences": [ 19 | "nunit.framework.dll" 20 | ], 21 | "autoReferenced": false, 22 | "defineConstraints": [ 23 | "UNITY_INCLUDE_TESTS" 24 | ], 25 | "versionDefines": [], 26 | "noEngineReferences": false 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### 2 | # Unity folders and files 3 | ### 4 | [Aa]ssets/AssetStoreTools* 5 | [Bb]uild/ 6 | [Ll]ibrary/ 7 | [Ll]ocal[Cc]ache/ 8 | [Ll]ogs/ 9 | [Oo]bj/ 10 | [Tt]emp/ 11 | [Uu]nityGenerated/ 12 | 13 | # file on crash reports 14 | sysinfo.txt 15 | # Unity3D generated meta files 16 | *.pidb.meta 17 | 18 | 19 | db.lock 20 | storage.ide 21 | storage.ide-shm 22 | storage.ide-wal 23 | 24 | .collabignore 25 | 26 | ### 27 | # VS/MD solution and project files 28 | ### 29 | [Ee]xportedObj/ 30 | *.booproj 31 | *.csproj 32 | *.sln 33 | *.suo 34 | *.svd 35 | *.unityproj 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | .DS_Store 40 | .vscode/ 41 | .vs/ 42 | 43 | ### 44 | # OS generated 45 | ### 46 | .DS_Store 47 | .DS_Store? 48 | ._* 49 | .Spotlight-V100 50 | .Trashes 51 | Icon? 52 | ehthumbs.db 53 | Thumbs.db 54 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/FloorToMultipleOfXTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 5 | { 6 | public class FloorToMultipleOfXTests 7 | { 8 | [TestCase(16f , 16f , 16f , 4, 16, 16 , 16)] 9 | [TestCase(16.5f , 16.5f , 16.5f , 4, 16, 16 , 16)] 10 | [TestCase(16f , 16f , 16f , 3, 15, 15 , 15)] 11 | [TestCase(15.9f , 6.1f , 129.3f , 2, 14, 6 , 128)] 12 | public void Test_Floor_To_Multiple_Of_X(float nx, float ny, float nz, int x, int expectedX, int expectedY, int expectedZ) 13 | { 14 | Assert.AreEqual(new int3(expectedX, expectedY, expectedZ), VectorUtilities.FloorToMultipleOfX(new float3(nx, ny, nz), x)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Modules/VoxelTerrain.Modules.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoxelTerrain.Modules.Tests", 3 | "references": [ 4 | "UnityEngine.TestRunner", 5 | "UnityEditor.TestRunner", 6 | "Unity.Mathematics", 7 | "Unity.Collections", 8 | "Unity.Burst", 9 | "Unity.Jobs", 10 | "VoxelTerrain.Core", 11 | "VoxelTerrain.Modules" 12 | ], 13 | "includePlatforms": [ 14 | "Editor" 15 | ], 16 | "excludePlatforms": [], 17 | "allowUnsafeCode": true, 18 | "overrideReferences": true, 19 | "precompiledReferences": [ 20 | "nunit.framework.dll" 21 | ], 22 | "autoReferenced": false, 23 | "defineConstraints": [ 24 | "UNITY_INCLUDE_TESTS" 25 | ], 26 | "versionDefines": [], 27 | "noEngineReferences": false 28 | } 29 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 7 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 2 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: 7 | - type: 8 | m_NativeTypeID: 108 9 | m_ManagedTypePPtr: {fileID: 0} 10 | m_ManagedTypeFallback: 11 | defaultPresets: 12 | - m_Preset: {fileID: 2655988077585873504, guid: c1cf8506f04ef2c4a88b64b6c4202eea, 13 | type: 2} 14 | - type: 15 | m_NativeTypeID: 1020 16 | m_ManagedTypePPtr: {fileID: 0} 17 | m_ManagedTypeFallback: 18 | defaultPresets: 19 | - m_Preset: {fileID: 2655988077585873504, guid: 0cd792cc87e492d43b4e95b205fc5cc6, 20 | type: 2} 21 | - type: 22 | m_NativeTypeID: 1006 23 | m_ManagedTypePPtr: {fileID: 0} 24 | m_ManagedTypeFallback: 25 | defaultPresets: 26 | - m_Preset: {fileID: 2655988077585873504, guid: 7a99f8aa944efe94cb9bd74562b7d5f9, 27 | type: 2} 28 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Settings/WorldSettings.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | using UnityEngine; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Settings 5 | { 6 | /// 7 | /// Parameters that specify how the world will be generated 8 | /// 9 | [System.Serializable] 10 | public class WorldSettings 11 | { 12 | /// 13 | /// The chunk's size. This represents the width, height and depth in Unity units. 14 | /// 15 | [SerializeField] private int3 chunkSize = new int3(16, 16, 16); 16 | 17 | /// 18 | /// The chunk's prefab that will be instantiated 19 | /// 20 | [SerializeField] private GameObject chunkPrefab; 21 | 22 | /// 23 | /// The chunk's size. This represents the width, height and depth in Unity units. 24 | /// 25 | public int3 ChunkSize => chunkSize; 26 | 27 | /// 28 | /// The chunk's prefab that will be instantiated 29 | /// 30 | public GameObject ChunkPrefab => chunkPrefab; 31 | } 32 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Eldemarkki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/VoxelMesher.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using Eldemarkki.VoxelTerrain.VoxelData; 3 | using Eldemarkki.VoxelTerrain.World; 4 | using Unity.Mathematics; 5 | using UnityEngine; 6 | 7 | namespace Eldemarkki.VoxelTerrain.Meshing 8 | { 9 | public abstract class VoxelMesher : MonoBehaviour 10 | { 11 | /// 12 | /// The voxel world the owns this voxel mesher 13 | /// 14 | public VoxelWorld VoxelWorld { get; set; } 15 | 16 | /// 17 | /// Starts a mesh generation job 18 | /// 19 | /// The store where to retrieve the voxel data from 20 | /// The store where to retrieve the voxels' color data from 21 | /// The coordinate of the chunk that will be generated 22 | /// The job handle and the actual mesh generation job 23 | public abstract JobHandleWithData CreateMesh(VoxelDataStore voxelDataStore, VoxelColorStore voxelColorStore, int3 chunkCoordinate); 24 | } 25 | } -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 8 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Marching-Cubes-Terrain 2 | This is my implementation of the Marching Cubes algorithm using Unity. 3 | 4 | Demo video: https://www.youtube.com/watch?v=7GrKaSCoyvs 5 | 6 | Discord Server: https://discord.gg/tKhNq7sCYu 7 | 8 | ## Features 9 | - Unity Job System with the Burst Compiler 10 | - Realtime terrain editing 11 | - Smooth the terrain by holding the left ctrl key and left click 12 | - Two world types: 13 | - Procedurally-generated infinite world 14 | - Import from black-and-white heightmap texture 15 | 16 | ## System Requirements 17 | - Unity3D (I'm developing this project with version **2019.3.0f6**, but any newer version should also work) 18 | 19 | ## Setup 20 | 1. Clone the repository with `git clone https://github.com/Eldemarkki/Marching-Cubes-Terrain.git` 21 | 2. Open the project with Unity 22 | 23 | ## Contributing 24 | All contributions are welcome. 25 | 26 | When creating a new issue, please describe the bug in as much detail as possible, and include the branch and commit id where the bug happened. If applicable, also include screenshots. 27 | 28 | ## Acknowledgements: 29 | - Paul Bourke for an example implementation of the Marching Cubes algorithm (http://paulbourke.net/geometry/polygonise/) 30 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/MeshingTests/NativeCounterTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Collections; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Meshing.Tests 5 | { 6 | public class NativeCounterTests 7 | { 8 | private NativeCounter counter; 9 | 10 | [SetUp] 11 | public void SetupNativeCounterTest() 12 | { 13 | counter = new NativeCounter(Allocator.Temp); 14 | } 15 | 16 | [TearDown] 17 | public void TeardownNativeCounterTest() 18 | { 19 | counter.Dispose(); 20 | } 21 | 22 | [Test] 23 | public void NativeCounter_Count_Initialized_As_0() 24 | { 25 | Assert.AreEqual(0, counter.Count); 26 | } 27 | 28 | [Test] 29 | public void NativeCounter_Increment_Increases_Count_By_1() 30 | { 31 | counter.Increment(); 32 | Assert.AreEqual(1, counter.Count); 33 | } 34 | 35 | [Test] 36 | public void NativeCounter_Random_Increment_Sets_Count_To_N([Random(5, 100, 3)] int value) 37 | { 38 | for (int i = 0; i < value; i++) 39 | { 40 | counter.Increment(); 41 | } 42 | 43 | Assert.AreEqual(value, counter.Count); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/MesherJob.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Meshing.Data; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using UnityEngine; 5 | using Eldemarkki.VoxelTerrain.VoxelData; 6 | 7 | namespace Eldemarkki.VoxelTerrain.Meshing 8 | { 9 | /// 10 | /// An interface for all the jobs that can extract a surface from voxel data 11 | /// 12 | public interface IMesherJob : IJob 13 | { 14 | /// 15 | /// A counter that keeps track of how many vertices there are 16 | /// 17 | NativeCounter VertexCountCounter { get; set; } 18 | 19 | /// 20 | /// The voxel data to generate the mesh from 21 | /// 22 | VoxelDataVolume VoxelData { get; set; } 23 | 24 | /// 25 | /// The voxel colors used to color the triangles 26 | /// 27 | VoxelDataVolume VoxelColors { get; set; } 28 | 29 | /// 30 | /// The generated vertices 31 | /// 32 | NativeArray OutputVertices { get; set; } 33 | 34 | /// 35 | /// The generated triangles 36 | /// 37 | NativeArray OutputTriangles { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /Assets/Shaders/Triplanar Shader.shader: -------------------------------------------------------------------------------- 1 | Shader "Marching Cubes/Triplanar Shader" 2 | { 3 | Properties 4 | { 5 | XColor("X Color", Color) = (0,0,0,0) 6 | YColor("Y Color", Color) = (0,0,0,0) 7 | NegativeYColor("Negative Y Color", Color) = (0,0,0,0) 8 | ZColor("Z Color", Color) = (0,0,0,0) 9 | YColorAmount("Y Color Amount", float) = 0.4 10 | } 11 | 12 | SubShader 13 | { 14 | Tags { "RenderType" = "Opaque"} 15 | 16 | CGPROGRAM 17 | #pragma surface surf Standard fullforwardshadows 18 | #pragma target 3.0 19 | 20 | fixed4 XColor; 21 | fixed4 YColor; 22 | fixed4 NegativeYColor; 23 | fixed4 ZColor; 24 | fixed YColorAmount; 25 | 26 | 27 | struct Input 28 | { 29 | float3 worldNormal; 30 | }; 31 | 32 | void surf (Input IN, inout SurfaceOutputStandard o) 33 | { 34 | fixed x = abs(IN.worldNormal.x); 35 | fixed yNormal = IN.worldNormal.y; 36 | fixed y = abs(yNormal) * YColorAmount; 37 | fixed z = abs(IN.worldNormal.z); 38 | 39 | fixed total = (x + y + z); 40 | x /= total; 41 | y /= total; 42 | z /= total; 43 | 44 | // X 45 | fixed3 col = (XColor * x); 46 | 47 | // Y 48 | if (yNormal < 0) 49 | col += NegativeYColor * y; 50 | else 51 | col += YColor * y; 52 | 53 | // Z 54 | col += (ZColor * z); 55 | 56 | o.Albedo = col; 57 | } 58 | ENDCG 59 | } 60 | FallBack "Diffuse" 61 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ToVectorIntTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 5 | { 6 | public class ToVectorIntTests 7 | { 8 | [Test] 9 | public void TestToVectorIntValueX([Random(0, 100, 4)] int x) 10 | { 11 | // Just some arbitrary values for y and z 12 | int y = 61; 13 | int z = 42; 14 | 15 | int3 vector = new int3(x, y, z); 16 | Assert.AreEqual(vector.x, VectorUtilities.ToVectorInt(vector).x); 17 | } 18 | 19 | [Test] 20 | public void TestToVectorIntValueY([Random(0, 100, 4)] int y) 21 | { 22 | // Just some arbitrary values for x and z 23 | int x = 33; 24 | int z = 98; 25 | 26 | int3 vector = new int3(x, y, z); 27 | Assert.AreEqual(vector.y, VectorUtilities.ToVectorInt(vector).y); 28 | } 29 | 30 | [Test] 31 | public void TestToVectorIntValueZ([Random(0, 100, 4)] int z) 32 | { 33 | // Just some arbitrary values for x and y 34 | int x = 48; 35 | int y = 86; 36 | 37 | int3 vector = new int3(x, y, z); 38 | Assert.AreEqual(vector.z, VectorUtilities.ToVectorInt(vector).z); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/ToInt3Tests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 6 | { 7 | public class ToInt3Tests 8 | { 9 | [Test] 10 | public void TestToInt3ValueX([Random(0, 100, 4)] int x) 11 | { 12 | // Just some arbitrary values for y and z 13 | int y = 61; 14 | int z = 42; 15 | 16 | Vector3Int vector = new Vector3Int(x, y, z); 17 | Assert.AreEqual(vector.x, VectorUtilities.ToInt3(vector).x); 18 | } 19 | 20 | [Test] 21 | public void TestToInt3ValueY([Random(0, 100, 4)] int y) 22 | { 23 | // Just some arbitrary values for x and z 24 | int x = 33; 25 | int z = 98; 26 | 27 | Vector3Int vector = new Vector3Int(x, y, z); 28 | Assert.AreEqual(vector.y, VectorUtilities.ToInt3(vector).y); 29 | } 30 | 31 | [Test] 32 | public void TestToInt3ValueZ([Random(0, 100, 4)] int z) 33 | { 34 | // Just some arbitrary values for x and y 35 | int x = 48; 36 | int y = 86; 37 | 38 | Vector3Int vector = new Vector3Int(x, y, z); 39 | Assert.AreEqual(vector.z, VectorUtilities.ToInt3(vector).z); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/BoundsUtilities.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | using UnityEngine; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities 5 | { 6 | public static class BoundsUtilities 7 | { 8 | /// 9 | /// Calculates the world space bounds of a chunk 10 | /// 11 | /// The coordinate of the chunk 12 | /// The size of the chunk 13 | /// That chunk's world space bounds 14 | public static BoundsInt GetChunkBounds(int3 chunkCoordinate, int3 chunkSize) 15 | { 16 | int3 min = chunkCoordinate * chunkSize; 17 | int3 size = new int3(1, 1, 1) * (chunkSize + new int3(1, 1, 1)); 18 | 19 | return new BoundsInt(min.ToVectorInt(), size.ToVectorInt()); 20 | } 21 | 22 | /// 23 | /// Calculates the volume of ; how many points are inside of 24 | /// 25 | /// The bounds whose volume is calculated 26 | /// The amount of points inside of 27 | public static int CalculateVolume(this BoundsInt bounds) 28 | { 29 | Vector3Int size = bounds.size; 30 | return size.x * size.y * size.z; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_AutoSimulation: 1 23 | m_QueriesHitTriggers: 1 24 | m_QueriesStartInColliders: 1 25 | m_ChangeStopsCallbacks: 0 26 | m_CallbacksOnDisable: 1 27 | m_ReuseCollisionCallbacks: 1 28 | m_AutoSyncTransforms: 0 29 | m_AlwaysShowColliders: 0 30 | m_ShowColliderSleep: 1 31 | m_ShowColliderContacts: 0 32 | m_ShowColliderAABB: 0 33 | m_ContactArrowScale: 0.2 34 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 35 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 36 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 37 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 38 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 39 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/ProceduralVoxelDataGenerator.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Settings; 2 | using Eldemarkki.VoxelTerrain.Utilities; 3 | using Unity.Collections; 4 | using Unity.Jobs; 5 | using Unity.Mathematics; 6 | using UnityEngine; 7 | 8 | namespace Eldemarkki.VoxelTerrain.VoxelData 9 | { 10 | /// 11 | /// A generator that creates voxel data procedurally 12 | /// 13 | public class ProceduralVoxelDataGenerator : VoxelDataGenerator 14 | { 15 | /// 16 | /// The settings for the procedural generation 17 | /// 18 | [SerializeField] private ProceduralTerrainSettings proceduralTerrainSettings = new ProceduralTerrainSettings(1, 9, 120, 0, 0); 19 | 20 | /// 21 | public override JobHandleWithData GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume outputVoxelDataArray) 22 | { 23 | ProceduralTerrainVoxelDataCalculationJob job = new ProceduralTerrainVoxelDataCalculationJob 24 | { 25 | WorldPositionOffset = worldSpaceOrigin, 26 | OutputVoxelData = outputVoxelDataArray, 27 | ProceduralTerrainSettings = proceduralTerrainSettings 28 | }; 29 | 30 | JobHandle jobHandle = job.Schedule(); 31 | 32 | JobHandleWithData jobHandleWithData = new JobHandleWithData 33 | { 34 | JobHandle = jobHandle, 35 | JobData = job 36 | }; 37 | 38 | return jobHandleWithData; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/DistanceUtilities.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | 3 | namespace Eldemarkki.VoxelTerrain.Utilities 4 | { 5 | public static class DistanceUtilities 6 | { 7 | /// 8 | /// Calculates the difference between and , and returns true if any of the xyz components of the difference is greater than . If all of the xyz components of the difference is less than or equal to it returns false. The formal name of this distance calculation is Chebyshev distance. This compares if the Chebyshev distance is greater than 9 | /// 10 | /// Point A 11 | /// Point B 12 | /// Maximum allowed component-wise difference of the difference between and 13 | /// True if any of the component-wise differences in the difference between and is greater than , false otherwise 14 | public static bool ChebyshevDistanceGreaterThan(int3 pointA, int3 pointB, int maximumAllowed) 15 | { 16 | int abx = pointA.x - pointB.x; 17 | int aby = pointA.y - pointB.y; 18 | int abz = pointA.z - pointB.z; 19 | 20 | return abx > maximumAllowed || -abx > maximumAllowed || aby > maximumAllowed || -aby > maximumAllowed || abz > maximumAllowed || -abz > maximumAllowed; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/Data/MeshingVertexData.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | namespace Eldemarkki.VoxelTerrain.Meshing.Data 7 | { 8 | /// 9 | /// A struct to hold the data every vertex should have 10 | /// 11 | [StructLayout(LayoutKind.Sequential)] 12 | public struct MeshingVertexData 13 | { 14 | /// 15 | /// The vertex's local position 16 | /// 17 | public float3 position; 18 | 19 | /// 20 | /// The vertex's normal 21 | /// 22 | public float3 normal; 23 | 24 | public Color32 color; 25 | 26 | /// 27 | /// The constructor to create a 28 | /// 29 | /// The vertex's local position 30 | /// The vertex's normal 31 | public MeshingVertexData(float3 position, float3 normal, Color32 color) 32 | { 33 | this.position = position; 34 | this.normal = normal; 35 | this.color = color; 36 | } 37 | 38 | /// 39 | /// The memory layout of a single vertex in memory 40 | /// 41 | public static readonly VertexAttributeDescriptor[] VertexBufferMemoryLayout = 42 | { 43 | new VertexAttributeDescriptor(VertexAttribute.Position), 44 | new VertexAttributeDescriptor(VertexAttribute.Normal), 45 | new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.UNorm8, 4) 46 | }; 47 | } 48 | } -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkStore.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | 3 | namespace Eldemarkki.VoxelTerrain.World.Chunks 4 | { 5 | /// 6 | /// A container for all of the chunks in the world 7 | /// 8 | public class ChunkStore : PerChunkStore 9 | { 10 | /// 11 | /// Generates the data for a chunk at coordinate , and adds it to the chunks dictionary in 12 | /// 13 | /// The coordinate to generate the data for 14 | public override void GenerateDataForChunkUnchecked(int3 chunkCoordinate) 15 | { 16 | ChunkProperties chunkProperties = new ChunkProperties(); 17 | chunkProperties.Initialize(chunkCoordinate, VoxelWorld.WorldSettings.ChunkSize); 18 | AddChunk(chunkCoordinate, chunkProperties); 19 | } 20 | 21 | /// 22 | /// Generates the data for a chunk at coordinate , and adds it to the chunks dictionary in . The new data is generated to . 23 | /// 24 | /// The coordinate to generate the data for 25 | /// The already existing data that will be used to generate the data into 26 | public override void GenerateDataForChunkUnchecked(int3 chunkCoordinate, ChunkProperties existingData) 27 | { 28 | existingData.MeshCollider.enabled = false; 29 | existingData.MeshRenderer.enabled = false; 30 | existingData.Initialize(chunkCoordinate, VoxelWorld.WorldSettings.ChunkSize); 31 | AddChunk(chunkCoordinate, existingData); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/NativeCounter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Unity.Collections; 4 | using Unity.Collections.LowLevel.Unsafe; 5 | 6 | namespace Eldemarkki.VoxelTerrain.Meshing 7 | { 8 | /// 9 | /// An incremental counter made for the Unity Job System 10 | /// 11 | public unsafe struct NativeCounter : IDisposable 12 | { 13 | /// 14 | /// The allocator for the counter 15 | /// 16 | private readonly Allocator _allocator; 17 | 18 | /// 19 | /// The pointer to the value 20 | /// 21 | [NativeDisableUnsafePtrRestriction] private readonly int* _counter; 22 | 23 | /// 24 | /// The counter's value 25 | /// 26 | public int Count 27 | { 28 | get => *_counter; 29 | set => (*_counter) = value; 30 | } 31 | 32 | /// 33 | /// The constructor 34 | /// 35 | /// What type of allocator to use 36 | public NativeCounter(Allocator allocator) 37 | { 38 | _allocator = allocator; 39 | _counter = (int*)UnsafeUtility.Malloc(sizeof(int), 4, allocator); 40 | Count = 0; 41 | } 42 | 43 | /// 44 | /// Increments the count by 1 45 | /// 46 | /// The original count 47 | public int Increment() 48 | { 49 | return Interlocked.Increment(ref *_counter) - 1; 50 | } 51 | 52 | /// 53 | /// Disposes the counter 54 | /// 55 | public void Dispose() 56 | { 57 | UnsafeUtility.Free(_counter, _allocator); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelColorStore.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.World; 2 | using Unity.Collections.LowLevel.Unsafe; 3 | using Unity.Mathematics; 4 | using UnityEngine; 5 | 6 | namespace Eldemarkki.VoxelTerrain.VoxelData 7 | { 8 | /// 9 | /// A store which handles getting and setting the voxel colors for the world 10 | /// 11 | public class VoxelColorStore : PerVoxelStore 12 | { 13 | /// 14 | /// The default color that the terrain will be colored with on load 15 | /// 16 | [SerializeField] private Color32 defaultTerrainColor = new Color32(11, 91, 33, 255); 17 | 18 | /// 19 | /// Generates the colors for a chunk at , where the output array is to save memory by not needing to allocate a new array. This does not check if a color array already exists at 20 | /// 21 | /// The coordinate of the chunk which to generate the colors for 22 | /// The array that should be filled with the new colors 23 | public override unsafe void GenerateDataForChunkUnchecked(int3 chunkCoordinate, VoxelDataVolume outputColors) 24 | { 25 | // Fill the array with the default terrain color 26 | Color32* defaultColorArray = stackalloc Color32[1] 27 | { 28 | defaultTerrainColor 29 | }; 30 | 31 | unsafe 32 | { 33 | UnsafeUtility.MemCpyReplicate(outputColors.GetUnsafePtr(), defaultColorArray, sizeof(Color32), outputColors.Length); 34 | } 35 | 36 | SetDataChunkUnchecked(chunkCoordinate, outputColors, false); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/World/VoxelWorld.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Meshing; 2 | using Eldemarkki.VoxelTerrain.Settings; 3 | using Eldemarkki.VoxelTerrain.VoxelData; 4 | using Eldemarkki.VoxelTerrain.World.Chunks; 5 | using UnityEngine; 6 | 7 | namespace Eldemarkki.VoxelTerrain.World 8 | { 9 | /// 10 | /// The main entry point for interacting with the voxel world 11 | /// 12 | public class VoxelWorld : MonoBehaviour 13 | { 14 | [SerializeField] private WorldSettings worldSettings; 15 | public WorldSettings WorldSettings => worldSettings; 16 | 17 | [SerializeField] private VoxelMesher voxelMesher; 18 | public VoxelMesher VoxelMesher => voxelMesher; 19 | 20 | [SerializeField] private VoxelDataStore voxelDataStore; 21 | public VoxelDataStore VoxelDataStore => voxelDataStore; 22 | 23 | [SerializeField] private VoxelColorStore voxelColorStore; 24 | public VoxelColorStore VoxelColorStore => voxelColorStore; 25 | 26 | [SerializeField] private VoxelDataGenerator voxelDataGenerator; 27 | public VoxelDataGenerator VoxelDataGenerator => voxelDataGenerator; 28 | 29 | [SerializeField] private ChunkProvider chunkProvider; 30 | public ChunkProvider ChunkProvider => chunkProvider; 31 | 32 | [SerializeField] private ChunkStore chunkStore; 33 | public ChunkStore ChunkStore => chunkStore; 34 | 35 | [SerializeField] private ChunkUpdater chunkUpdater; 36 | public ChunkUpdater ChunkUpdater => chunkUpdater; 37 | 38 | private void Awake() 39 | { 40 | voxelDataStore.VoxelWorld = this; 41 | voxelColorStore.VoxelWorld = this; 42 | chunkProvider.VoxelWorld = this; 43 | chunkUpdater.VoxelWorld = this; 44 | chunkStore.VoxelWorld = this; 45 | voxelMesher.VoxelWorld = this; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/IndexToXyzTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 5 | { 6 | public class IndexToXyzTests 7 | { 8 | private static void TestIndexToXyz(int index, int expectedX, int expectedY, int expectedZ, int width, int height) 9 | { 10 | Assert.AreEqual(new int3(expectedX, expectedY, expectedZ), IndexUtilities.IndexToXyz(index, width, height)); 11 | } 12 | 13 | [TestCaseSource(nameof(Width_1_Height_5_Cases))] 14 | public void Width_1_Height_5(int index, int expectedX, int expectedY, int expectedZ) 15 | { 16 | TestIndexToXyz(index, expectedX, expectedY, expectedZ, 1, 5); 17 | } 18 | 19 | [TestCaseSource(nameof(Width_2_Height_5_Cases))] 20 | public void Width_2_Height_5(int index, int expectedX, int expectedY, int expectedZ) 21 | { 22 | TestIndexToXyz(index, expectedX, expectedY, expectedZ, 2, 5); 23 | } 24 | 25 | private static object[] Width_1_Height_5_Cases = 26 | { 27 | new object[] { 1, 0, 1, 0}, 28 | new object[] { 2, 0, 2, 0}, 29 | new object[] { 2, 0, 2, 0}, 30 | new object[] { 3, 0, 3, 0}, 31 | new object[] { 4, 0, 4, 0}, 32 | new object[] { 5, 0, 0, 1} 33 | }; 34 | 35 | private static object[] Width_2_Height_5_Cases = 36 | { 37 | new object[] { 1 , 1, 0, 0}, 38 | new object[] { 2 , 0, 1, 0}, 39 | new object[] { 3 , 1, 1, 0}, 40 | new object[] { 4 , 0, 2, 0}, 41 | new object[] { 10, 0, 0, 1}, 42 | new object[] { 11, 1, 0, 1}, 43 | new object[] { 12, 0, 1, 1}, 44 | new object[] { 13, 1, 1, 1}, 45 | new object[] { 20, 0, 0, 2}, 46 | new object[] { 30, 0, 0, 3}, 47 | new object[] { 33, 1, 1, 3} 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/HeightmapVoxelDataGenerator.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using Eldemarkki.VoxelTerrain.World; 3 | using Unity.Collections; 4 | using Unity.Jobs; 5 | using Unity.Mathematics; 6 | using UnityEngine; 7 | 8 | namespace Eldemarkki.VoxelTerrain.VoxelData 9 | { 10 | /// 11 | /// A generator that creates voxel data from a heightmap 12 | /// 13 | public class HeightmapVoxelDataGenerator : VoxelDataGenerator 14 | { 15 | /// 16 | /// The heightmap world generator which gives this class the HeightmapTerrainSettings 17 | /// 18 | [SerializeField] private HeightmapWorldGenerator heightmapWorldGenerator; 19 | 20 | /// 21 | public override JobHandleWithData GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume outputVoxelDataArray) 22 | { 23 | HeightmapTerrainVoxelDataCalculationJob job = new HeightmapTerrainVoxelDataCalculationJob 24 | { 25 | WorldPositionOffset = worldSpaceOrigin, 26 | OutputVoxelData = outputVoxelDataArray, 27 | HeightmapData = heightmapWorldGenerator.HeightmapTerrainSettings.HeightmapData, 28 | HeightmapWidth = heightmapWorldGenerator.HeightmapTerrainSettings.Width, 29 | HeightmapHeight = heightmapWorldGenerator.HeightmapTerrainSettings.Height, 30 | Amplitude = heightmapWorldGenerator.HeightmapTerrainSettings.Amplitude, 31 | HeightOffset = heightmapWorldGenerator.HeightmapTerrainSettings.HeightOffset 32 | }; 33 | 34 | JobHandle jobHandle = job.Schedule(); 35 | 36 | JobHandleWithData jobHandleWithData = new JobHandleWithData 37 | { 38 | JobHandle = jobHandle, 39 | JobData = job 40 | }; 41 | 42 | return jobHandleWithData; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkProperties.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.World.Chunks 6 | { 7 | /// 8 | /// A class that contains properties for a chunk 9 | /// 10 | public class ChunkProperties 11 | { 12 | /// 13 | /// The game object that corresponds to these properties 14 | /// 15 | public GameObject ChunkGameObject { get; set; } 16 | public MeshFilter MeshFilter { get; set; } 17 | public MeshCollider MeshCollider { get; set; } 18 | public MeshRenderer MeshRenderer { get; set; } 19 | 20 | public int3 ChunkCoordinate { get; set; } 21 | 22 | /// 23 | /// Has the voxel data of this chunk been changed during the last frame 24 | /// 25 | public bool HasChanges { get; set; } 26 | public bool IsMeshGenerated { get; set; } 27 | 28 | /// 29 | /// Initializes the chunk's properties. 30 | /// 31 | /// The coordinate of this chunk 32 | /// The size of this chunk 33 | public void Initialize(int3 chunkCoordinate, int3 chunkSize) 34 | { 35 | #if UNITY_EDITOR 36 | ChunkGameObject.name = GetName(chunkCoordinate); 37 | #endif 38 | ChunkGameObject.transform.position = (chunkCoordinate * chunkSize).ToVectorInt(); 39 | ChunkCoordinate = chunkCoordinate; 40 | 41 | IsMeshGenerated = false; 42 | HasChanges = false; 43 | } 44 | 45 | /// 46 | /// Generates a chunk name from a chunk coordinate 47 | /// 48 | /// The coordinate of the chunk 49 | /// The name of the chunk 50 | public static string GetName(int3 chunkCoordinate) 51 | { 52 | return $"Chunk_{chunkCoordinate.x}_{chunkCoordinate.y}_{chunkCoordinate.z}"; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/VoxelData/VoxelDataGenerator.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using Unity.Collections; 3 | using Unity.Mathematics; 4 | using UnityEngine; 5 | 6 | namespace Eldemarkki.VoxelTerrain.VoxelData 7 | { 8 | /// 9 | /// A base class for all voxel data generators 10 | /// 11 | public abstract class VoxelDataGenerator : MonoBehaviour 12 | { 13 | /// 14 | /// Starts generating the voxel data for a specified volume with a persistent allocator 15 | /// 16 | /// The world-space volume to generate the voxel data for 17 | /// The job handle and the voxel data generation job 18 | public JobHandleWithData GenerateVoxelData(BoundsInt bounds) 19 | { 20 | return GenerateVoxelData(bounds, Allocator.Persistent); 21 | } 22 | 23 | /// 24 | /// Starts generating the voxel data for a specified volume 25 | /// 26 | /// The world-space volume to generate the voxel data for 27 | /// The allocator for the new voxel data array 28 | /// The job handle and the voxel data generation job 29 | public JobHandleWithData GenerateVoxelData(BoundsInt bounds, Allocator allocator) 30 | { 31 | VoxelDataVolume voxelDataArray = new VoxelDataVolume(bounds.size, allocator); 32 | int3 worldSpaceOrigin = bounds.min.ToInt3(); 33 | return GenerateVoxelData(worldSpaceOrigin, voxelDataArray); 34 | } 35 | 36 | /// 37 | /// Starts generating the voxel data for the given volume, where the origin of the volume is at 38 | /// 39 | /// The world space origin of 40 | /// The volume where the new voxel data should be generated to 41 | /// The job handle and the voxel data generation job 42 | public abstract JobHandleWithData GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume outputVoxelDataArray); 43 | } 44 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/World/HeightmapWorldGenerator.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Settings; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.World 6 | { 7 | /// 8 | /// A world generated from a heightmap 9 | /// 10 | public class HeightmapWorldGenerator : MonoBehaviour 11 | { 12 | /// 13 | /// The voxel world the "owns" this world generator 14 | /// 15 | [SerializeField] private VoxelWorld voxelWorld; 16 | 17 | /// 18 | /// The settings for generating the heightmap terrain 19 | /// 20 | [SerializeField] private HeightmapTerrainSettings heightmapTerrainSettings; 21 | 22 | /// 23 | /// The settings for generating the heightmap terrain 24 | /// 25 | public HeightmapTerrainSettings HeightmapTerrainSettings => heightmapTerrainSettings; 26 | 27 | private void Awake() 28 | { 29 | heightmapTerrainSettings.Initialize(heightmapTerrainSettings.Heightmap, heightmapTerrainSettings.Amplitude, heightmapTerrainSettings.HeightOffset); 30 | } 31 | 32 | private void Start() 33 | { 34 | CreateHeightmapTerrainImmediate(); 35 | } 36 | 37 | private void OnDestroy() 38 | { 39 | heightmapTerrainSettings.Dispose(); 40 | } 41 | 42 | /// 43 | /// Creates the heightmap terrain and loads the chunks. 44 | /// 45 | private void CreateHeightmapTerrainImmediate() 46 | { 47 | int chunkCountX = (int)math.ceil((float)(heightmapTerrainSettings.Width - 1) / voxelWorld.WorldSettings.ChunkSize.x); 48 | int chunkCountZ = (int)math.ceil((float)(heightmapTerrainSettings.Height - 1) / voxelWorld.WorldSettings.ChunkSize.z); 49 | int chunkCountY = (int)math.ceil(heightmapTerrainSettings.Amplitude / voxelWorld.WorldSettings.ChunkSize.y); 50 | 51 | for (int x = 0; x < chunkCountX; x++) 52 | { 53 | for (int y = 0; y < chunkCountY; y++) 54 | { 55 | for (int z = 0; z < chunkCountZ; z++) 56 | { 57 | voxelWorld.ChunkProvider.CreateLoadedChunkToCoordinateImmediate(new int3(x, y, z)); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkProvider.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.World.Chunks 6 | { 7 | /// 8 | /// A class for providing chunks to the world 9 | /// 10 | public class ChunkProvider : MonoBehaviour 11 | { 12 | /// 13 | /// The world for which to provide chunks for 14 | /// 15 | public VoxelWorld VoxelWorld { get; set; } 16 | 17 | /// 18 | /// Instantiates a chunk to and initializes it, but does not generate its mesh 19 | /// 20 | /// The chunk's coordinate 21 | /// The new chunk 22 | protected ChunkProperties CreateUnloadedChunkToCoordinate(int3 chunkCoordinate) 23 | { 24 | int3 worldPosition = chunkCoordinate * VoxelWorld.WorldSettings.ChunkSize; 25 | GameObject chunkGameObject = Instantiate(VoxelWorld.WorldSettings.ChunkPrefab, worldPosition.ToVectorInt(), Quaternion.identity); 26 | 27 | ChunkProperties chunkProperties = new ChunkProperties 28 | { 29 | ChunkGameObject = chunkGameObject, 30 | MeshCollider = chunkGameObject.GetComponent(), 31 | MeshFilter = chunkGameObject.GetComponent(), 32 | MeshRenderer = chunkGameObject.GetComponent() 33 | }; 34 | 35 | chunkProperties.Initialize(chunkCoordinate, VoxelWorld.WorldSettings.ChunkSize); 36 | 37 | VoxelWorld.ChunkStore.AddChunk(chunkCoordinate, chunkProperties); 38 | 39 | return chunkProperties; 40 | } 41 | 42 | /// 43 | /// Instantiates a chunk to , initializes it and generates its mesh 44 | /// 45 | /// The coordinate of the chunk to create 46 | /// The new chunk 47 | public ChunkProperties CreateLoadedChunkToCoordinateImmediate(int3 chunkCoordinate) 48 | { 49 | ChunkProperties chunkProperties = CreateUnloadedChunkToCoordinate(chunkCoordinate); 50 | VoxelWorld.ChunkUpdater.GenerateVoxelDataAndMeshImmediate(chunkProperties); 51 | return chunkProperties; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/IndexUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities 5 | { 6 | public static class IndexUtilities 7 | { 8 | /// 9 | /// Converts a 3D location to a 1D index 10 | /// 11 | /// The position of the point 12 | /// The size of the "container" in the x-direction 13 | /// The size of the "container" in the y-direction 14 | /// The 1D representation of the specified location in the "container" 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static int XyzToIndex(int3 xyz, int width, int height) 17 | { 18 | return XyzToIndex(xyz.x, xyz.y, xyz.z, width, height); 19 | } 20 | 21 | /// 22 | /// Converts a 3D location to a 1D index 23 | /// 24 | /// The x value of the location 25 | /// The y value of the location 26 | /// The z value of the location 27 | /// The size of the "container" in the x-direction 28 | /// The size of the "container" in the y-direction 29 | /// The 1D representation of the specified location in the "container" 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public static int XyzToIndex(int x, int y, int z, int width, int height) 32 | { 33 | return z * width * height + y * width + x; 34 | } 35 | 36 | 37 | /// 38 | /// Converts a 1D index to a 3D location 39 | /// 40 | /// The 1D index in the "container" 41 | /// The size of the "container" in the x-direction 42 | /// The size of the "container" in the y-direction 43 | /// The 3D representation of the specified index in the "container" 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | public static int3 IndexToXyz(int index, int width, int height) 46 | { 47 | int3 position = new int3( 48 | index % width, 49 | index / width % height, 50 | index / (width * height)); 51 | return position; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/Intersection/IntersectionUtilities.cs: -------------------------------------------------------------------------------- 1 | using Unity.Mathematics; 2 | using UnityEngine; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Intersection 5 | { 6 | /// 7 | /// A utilities class for different kinds of geometric intersections 8 | /// 9 | public static class IntersectionUtilities 10 | { 11 | /// 12 | /// Intersects a plane with a line 13 | /// 14 | /// The origin of the plane 15 | /// The normal of the plane 16 | /// The origin of the line 17 | /// The direction of the line 18 | /// The point where the line hit the plane (if any) 19 | /// The collision result 20 | public static PlaneLineIntersectionResult PlaneLineIntersection(float3 planeOrigin, float3 planeNormal, float3 lineOrigin, 21 | float3 lineDirection, out float3 intersectionPoint) 22 | { 23 | planeNormal = math.normalize(planeNormal); 24 | lineDirection = math.normalize(lineDirection); 25 | 26 | if (math.dot(planeNormal, lineDirection) == 0) 27 | { 28 | intersectionPoint = float3.zero; 29 | return (planeOrigin - lineOrigin).Equals(float3.zero) ? PlaneLineIntersectionResult.ParallelInsidePlane : PlaneLineIntersectionResult.NoHit; 30 | } 31 | 32 | float d = math.dot(planeOrigin, -planeNormal); 33 | float t = -(d + lineOrigin.z * planeNormal.z + lineOrigin.y * planeNormal.y + lineOrigin.x * planeNormal.x) / (lineDirection.z * planeNormal.z + lineDirection.y * planeNormal.y + lineDirection.x * planeNormal.x); 34 | intersectionPoint = lineOrigin + t * lineDirection; 35 | return PlaneLineIntersectionResult.OneHit; 36 | } 37 | 38 | /// 39 | /// Gets the volume where the bounds intersect 40 | /// 41 | /// The first bounds 42 | /// The second bounds 43 | /// The volume that is contained in both bounds 44 | public static BoundsInt GetIntersectionVolume(BoundsInt a, BoundsInt b) 45 | { 46 | int3 min = math.max(a.min.ToInt3(), b.min.ToInt3()); 47 | int3 max = math.min(a.max.ToInt3(), b.max.ToInt3()); 48 | 49 | int3 size = max - min; 50 | return new BoundsInt(min.ToVectorInt(), size.ToVectorInt()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} 39 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 40 | - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} 41 | - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} 42 | m_PreloadedShaders: [] 43 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 44 | type: 0} 45 | m_CustomRenderPipeline: {fileID: 0} 46 | m_TransparencySortMode: 0 47 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 48 | m_DefaultRenderingPath: 1 49 | m_DefaultMobileRenderingPath: 1 50 | m_TierSettings: [] 51 | m_LightmapStripping: 0 52 | m_FogStripping: 0 53 | m_InstancingStripping: 0 54 | m_LightmapKeepPlain: 1 55 | m_LightmapKeepDirCombined: 1 56 | m_LightmapKeepDynamicPlain: 1 57 | m_LightmapKeepDynamicDirCombined: 1 58 | m_LightmapKeepShadowMask: 1 59 | m_LightmapKeepSubtractive: 1 60 | m_FogKeepLinear: 1 61 | m_FogKeepExp: 1 62 | m_FogKeepExp2: 1 63 | m_AlbedoSwatchInfos: [] 64 | m_LightsUseLinearIntensity: 0 65 | m_LightsUseColorTemperature: 0 66 | -------------------------------------------------------------------------------- /Assets/Materials/Triplanar Shading.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Triplanar Shading 11 | m_Shader: {fileID: 4800000, guid: db8c18db5cb480d4c8523e1b745f5af5, type: 3} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - Tex1: 23 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 24 | m_Scale: {x: 0.1, y: 0.1} 25 | m_Offset: {x: 0, y: 0} 26 | - Tex2: 27 | m_Texture: {fileID: 2800000, guid: c6bd348a701e4904097c86dc74e1ea0d, type: 3} 28 | m_Scale: {x: 0.1, y: 0.1} 29 | m_Offset: {x: 0, y: 0} 30 | - Tex3: 31 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 32 | m_Scale: {x: 0.1, y: 0.1} 33 | m_Offset: {x: 0, y: 0} 34 | - Texture2D_1B8FCD66: 35 | m_Texture: {fileID: 2800000, guid: c6bd348a701e4904097c86dc74e1ea0d, type: 3} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - Texture2D_2C986A40: 39 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - Texture2D_35130819: 43 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _XTexture: 47 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _YTexture: 51 | m_Texture: {fileID: 2800000, guid: c6bd348a701e4904097c86dc74e1ea0d, type: 3} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _ZTexture: 55 | m_Texture: {fileID: 2800000, guid: 2fdf9aa38a68a274cbfa7b62d7a8841b, type: 3} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | m_Floats: 59 | - YColorAmount: 1 60 | - _Glossiness: 0 61 | - _Metallic: 0 62 | m_Colors: 63 | - NegativeYColor: {r: 0.3490566, g: 0.22091156, b: 0.09055714, a: 1} 64 | - XColor: {r: 0.5849056, g: 0.35697895, b: 0.124154516, a: 1} 65 | - YColor: {r: 0.21813813, g: 0.8113208, b: 0.3686471, a: 1} 66 | - ZColor: {r: 0.5849056, g: 0.35697892, b: 0.124154486, a: 1} 67 | - _TintColor: {r: 1, g: 1, b: 1, a: 1} 68 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Chunk/ProceduralChunkProvider.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.World.Chunks; 2 | using System.Collections.Generic; 3 | using Unity.Mathematics; 4 | using UnityEngine; 5 | 6 | namespace Eldemarkki.VoxelTerrain.Chunks 7 | { 8 | /// 9 | /// Provider for procedurally generated chunks 10 | /// 11 | public class ProceduralChunkProvider : ChunkProvider 12 | { 13 | /// 14 | /// The maximum amount of chunks that can be generated in one frame 15 | /// 16 | [SerializeField] private int chunkGenerationRate = 10; 17 | 18 | /// 19 | /// A queue that contains all the coordinates where a chunk will eventually have to be generated 20 | /// 21 | private Queue _generationQueue; 22 | 23 | private void Awake() 24 | { 25 | _generationQueue = new Queue(); 26 | } 27 | 28 | private void Update() 29 | { 30 | int chunksGenerated = 0; 31 | while (_generationQueue.Count > 0 && chunksGenerated < chunkGenerationRate) 32 | { 33 | int3 chunkCoordinate = _generationQueue.Dequeue(); 34 | 35 | if (VoxelWorld.ChunkStore.TryGetDataChunk(chunkCoordinate, out ChunkProperties chunkProperties)) 36 | { 37 | if (!chunkProperties.IsMeshGenerated) 38 | { 39 | VoxelWorld.ChunkUpdater.GenerateVoxelDataAndMeshImmediate(chunkProperties); 40 | chunksGenerated++; 41 | } 42 | } 43 | } 44 | } 45 | 46 | /// 47 | /// Ensures that a chunk exists at a coordinate, if there is not, a new chunk is instantiated there, and its will eventually be generated 48 | /// 49 | /// The chunk's coordinate 50 | public void EnsureChunkExistsAtCoordinate(int3 chunkCoordinate) 51 | { 52 | if (!VoxelWorld.ChunkStore.DoesChunkExistAtCoordinate(chunkCoordinate)) 53 | { 54 | CreateUnloadedChunkToCoordinate(chunkCoordinate); 55 | AddChunkToGenerationQueue(chunkCoordinate); 56 | } 57 | } 58 | 59 | /// 60 | /// Adds the coordinate to the list of chunks that will eventually have to be generated 61 | /// 62 | /// 63 | public void AddChunkToGenerationQueue(int3 chunkCoordinate) 64 | { 65 | _generationQueue.Enqueue(chunkCoordinate); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/XyzToIndexTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 5 | { 6 | public class XyzToIndexTests 7 | { 8 | private static void TestXyzToIndex_Using_int3(int3 xyz, int expectedIndex, int width, int height) 9 | { 10 | int actualIndex = IndexUtilities.XyzToIndex(xyz, width, height); 11 | Assert.AreEqual(expectedIndex, actualIndex); 12 | } 13 | 14 | private static void TestXyzToIndex_Using_int_xyz(int x, int y, int z, int expectedIndex, int width, int height) 15 | { 16 | int actualIndex = IndexUtilities.XyzToIndex(x, y, z, width, height); 17 | Assert.AreEqual(expectedIndex, actualIndex); 18 | } 19 | 20 | [TestCaseSource(nameof(Width_1_Height_5_Cases))] 21 | public void Width_1_Height_5_Using_int3(int x, int y, int z, int expectedIndex) 22 | { 23 | TestXyzToIndex_Using_int3(new int3(x, y, z), expectedIndex, 1, 5); 24 | } 25 | 26 | [TestCaseSource(nameof(Width_2_Height_5_Cases))] 27 | public void Width_2_Height_5_Using_int3(int x, int y, int z, int expectedIndex) 28 | { 29 | TestXyzToIndex_Using_int3(new int3(x, y, z), expectedIndex, 2, 5); 30 | } 31 | 32 | [TestCaseSource(nameof(Width_1_Height_5_Cases))] 33 | public void Width_1_Height_5_Using_int_xyz(int x, int y, int z, int expectedIndex) 34 | { 35 | TestXyzToIndex_Using_int_xyz(x, y, z, expectedIndex, 1, 5); 36 | } 37 | 38 | [TestCaseSource(nameof(Width_2_Height_5_Cases))] 39 | public void Width_2_Height_5_Using_int_xyz(int x, int y, int z, int expectedIndex) 40 | { 41 | TestXyzToIndex_Using_int_xyz(x, y, z, expectedIndex, 2, 5); 42 | } 43 | 44 | static object[] Width_1_Height_5_Cases = 45 | { 46 | new object[] { 0, 1, 0, 1 }, 47 | new object[] { 0, 2, 0, 2 }, 48 | new object[] { 0, 2, 0, 2 }, 49 | new object[] { 0, 3, 0, 3 }, 50 | new object[] { 0, 4, 0, 4 }, 51 | new object[] { 0, 0, 1, 5 } 52 | }; 53 | 54 | static object[] Width_2_Height_5_Cases = 55 | { 56 | new object[] { 1, 0, 0, 1 }, 57 | new object[] { 0, 1, 0, 2 }, 58 | new object[] { 1, 1, 0, 3 }, 59 | new object[] { 0, 2, 0, 4 }, 60 | new object[] { 0, 0, 1, 10 }, 61 | new object[] { 1, 0, 1, 11 }, 62 | new object[] { 0, 1, 1, 12 }, 63 | new object[] { 1, 1, 1, 13 }, 64 | new object[] { 0, 0, 2, 20 }, 65 | new object[] { 0, 0, 3, 30 }, 66 | new object[] { 1, 1, 3, 33 } 67 | }; 68 | } 69 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/TerrainSettings/ProceduralTerrainSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Settings 5 | { 6 | /// 7 | /// The procedural terrain generation settings 8 | /// 9 | [Serializable] 10 | public struct ProceduralTerrainSettings 11 | { 12 | /// 13 | [SerializeField] private float noiseFrequency; 14 | 15 | /// 16 | [SerializeField] private int noiseOctaveCount; 17 | 18 | /// 19 | [SerializeField] private float amplitude; 20 | 21 | /// 22 | [SerializeField] private float heightOffset; 23 | 24 | /// 25 | [SerializeField] private int noiseSeed; 26 | 27 | /// 28 | /// The frequency of the noise 29 | /// 30 | public float NoiseFrequency { get => noiseFrequency; set => noiseFrequency = value; } 31 | 32 | /// 33 | /// How many octaves the noise will have 34 | /// 35 | public int NoiseOctaveCount { get => noiseOctaveCount; set => noiseOctaveCount = value; } 36 | 37 | /// 38 | /// The height multiplier 39 | /// 40 | public float Amplitude { get => amplitude; set => amplitude = value; } 41 | 42 | /// 43 | /// Moves the height up and down 44 | /// 45 | public float HeightOffset { get => heightOffset; set => heightOffset = value; } 46 | 47 | /// 48 | /// The seed that the noise function will be initialized with 49 | /// 50 | public int NoiseSeed { get => noiseSeed; set => noiseSeed = value; } 51 | 52 | /// 53 | /// Constructor 54 | /// 55 | /// The frequency of the noise 56 | /// How many octaves the noise will have 57 | /// The height multiplier 58 | /// Moves the height up and down 59 | /// The seed that the noise function will be initialized with 60 | public ProceduralTerrainSettings(float noiseFrequency, int noiseOctaveCount, float amplitude, float heightOffset, int noiseSeed) 61 | { 62 | this.noiseFrequency = noiseFrequency; 63 | this.noiseOctaveCount = noiseOctaveCount; 64 | this.amplitude = amplitude; 65 | this.heightOffset = heightOffset; 66 | this.noiseSeed = noiseSeed; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesMesher.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Meshing.Data; 2 | using Eldemarkki.VoxelTerrain.VoxelData; 3 | using Eldemarkki.VoxelTerrain.Utilities; 4 | using Unity.Collections; 5 | using Unity.Jobs; 6 | using Unity.Mathematics; 7 | using UnityEngine; 8 | 9 | namespace Eldemarkki.VoxelTerrain.Meshing.MarchingCubes 10 | { 11 | /// 12 | /// A mesher for the marching cubes algorithm 13 | /// 14 | public class MarchingCubesMesher : VoxelMesher 15 | { 16 | /// 17 | [SerializeField, Range(0, 1)] private float isolevel = 0.5f; 18 | 19 | /// 20 | /// The density level where a surface will be created. Densities below this will be inside the surface (solid), 21 | /// and densities above this will be outside the surface (air) 22 | /// 23 | public float Isolevel => isolevel; 24 | 25 | /// 26 | public override JobHandleWithData CreateMesh(VoxelDataStore voxelDataStore, VoxelColorStore voxelColorStore, int3 chunkCoordinate) 27 | { 28 | if (!voxelDataStore.TryGetDataChunk(chunkCoordinate, out VoxelDataVolume boundsVoxelData)) 29 | { 30 | return null; 31 | } 32 | 33 | if (!voxelColorStore.TryGetDataChunk(chunkCoordinate, out VoxelDataVolume boundsVoxelColors)) 34 | { 35 | return null; 36 | } 37 | 38 | NativeCounter vertexCountCounter = new NativeCounter(Allocator.TempJob); 39 | 40 | int voxelCount = VoxelWorld.WorldSettings.ChunkSize.x * VoxelWorld.WorldSettings.ChunkSize.y * VoxelWorld.WorldSettings.ChunkSize.z; 41 | int maxLength = 15 * voxelCount; 42 | 43 | NativeArray outputVertices = new NativeArray(maxLength, Allocator.TempJob); 44 | NativeArray outputTriangles = new NativeArray(maxLength, Allocator.TempJob); 45 | 46 | MarchingCubesJob marchingCubesJob = new MarchingCubesJob 47 | { 48 | VoxelData = boundsVoxelData, 49 | VoxelColors = boundsVoxelColors, 50 | Isolevel = Isolevel, 51 | VertexCountCounter = vertexCountCounter, 52 | 53 | OutputVertices = outputVertices, 54 | OutputTriangles = outputTriangles 55 | }; 56 | 57 | JobHandle jobHandle = marchingCubesJob.Schedule(); 58 | 59 | JobHandleWithData jobHandleWithData = new JobHandleWithData 60 | { 61 | JobHandle = jobHandle, 62 | JobData = marchingCubesJob 63 | }; 64 | 65 | return jobHandleWithData; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/GetIntersectionAreaTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnityEngine; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Intersection.Tests 5 | { 6 | public class GetIntersectionVolumeTests 7 | { 8 | private static void TestIntersection(Vector3Int aPosition, Vector3Int aSize, Vector3Int bPosition, Vector3Int bSize, Vector3Int expectedPosition, Vector3Int expectedSize) 9 | { 10 | BoundsInt a = new BoundsInt(aPosition, aSize); 11 | BoundsInt b = new BoundsInt(bPosition, bSize); 12 | BoundsInt expected = new BoundsInt(expectedPosition, expectedSize); 13 | 14 | string message = $"Test failed with objects {a} and {b}. Expected {expected}"; 15 | 16 | BoundsInt intersection = IntersectionUtilities.GetIntersectionVolume(a, b); 17 | Assert.AreEqual(expected, intersection, "Regular: " + message); 18 | 19 | BoundsInt intersectionSwapped = IntersectionUtilities.GetIntersectionVolume(b, a); 20 | Assert.AreEqual(expected, intersectionSwapped, "Swapped: " + message); 21 | } 22 | 23 | [Test] 24 | public void Bounds_Are_Same_Should_Return_Same() 25 | { 26 | Vector3Int position = new Vector3Int(41, 24, 85); 27 | Vector3Int size = new Vector3Int(48, 26, 23); 28 | 29 | TestIntersection(position, size, 30 | position, size, 31 | position, size); 32 | } 33 | 34 | [Test] 35 | public void Test1() 36 | { 37 | TestIntersection(new Vector3Int(-2, -2, -2), new Vector3Int(4, 4, 4), 38 | new Vector3Int(0, 0, 0), new Vector3Int(4, 4, 4), 39 | new Vector3Int(0, 0, 0), new Vector3Int(2, 2, 2)); 40 | } 41 | 42 | [Test] 43 | public void Test2() 44 | { 45 | TestIntersection(new Vector3Int(-3, -1, -1), new Vector3Int(5, 8, 4), 46 | new Vector3Int(0, 4, 2), new Vector3Int(1, 5, 3), 47 | new Vector3Int(0, 4, 2), new Vector3Int(1, 3, 1)); 48 | } 49 | 50 | [Test] 51 | public void Test3() 52 | { 53 | TestIntersection(new Vector3Int(-12, -12, -12), new Vector3Int(4, 4, 4), 54 | new Vector3Int(-8, -8, -8), new Vector3Int(16, 16, 16), 55 | new Vector3Int(-8, -8, -8), new Vector3Int(0, 0, 0)); 56 | } 57 | 58 | [Test] 59 | public void Test4() 60 | { 61 | TestIntersection(new Vector3Int(-12, -12, -12), new Vector3Int(4, 4, 4), 62 | new Vector3Int(-9, -9, -9), new Vector3Int(16, 16, 16), 63 | new Vector3Int(-9, -9, -9), new Vector3Int(1, 1, 1)); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Assets/Prefabs/Chunk.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1042568357287805991 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 8302165401843338731} 12 | - component: {fileID: 773550656402152373} 13 | - component: {fileID: 8131520927842024086} 14 | - component: {fileID: 7519686632171402987} 15 | m_Layer: 0 16 | m_Name: Chunk 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &8302165401843338731 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 1042568357287805991} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0, y: 0, z: 0} 31 | m_LocalScale: {x: 1, y: 1, z: 1} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!23 &773550656402152373 37 | MeshRenderer: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 1042568357287805991} 43 | m_Enabled: 1 44 | m_CastShadows: 1 45 | m_ReceiveShadows: 1 46 | m_DynamicOccludee: 1 47 | m_MotionVectors: 1 48 | m_LightProbeUsage: 1 49 | m_ReflectionProbeUsage: 1 50 | m_RayTracingMode: 2 51 | m_RenderingLayerMask: 1 52 | m_RendererPriority: 0 53 | m_Materials: 54 | - {fileID: 2100000, guid: 6f4ec41ce043e2940a19224905527b38, type: 2} 55 | m_StaticBatchInfo: 56 | firstSubMesh: 0 57 | subMeshCount: 0 58 | m_StaticBatchRoot: {fileID: 0} 59 | m_ProbeAnchor: {fileID: 0} 60 | m_LightProbeVolumeOverride: {fileID: 0} 61 | m_ScaleInLightmap: 1 62 | m_ReceiveGI: 1 63 | m_PreserveUVs: 0 64 | m_IgnoreNormalsForChartDetection: 0 65 | m_ImportantGI: 0 66 | m_StitchLightmapSeams: 1 67 | m_SelectedEditorRenderState: 3 68 | m_MinimumChartSize: 4 69 | m_AutoUVMaxDistance: 0.5 70 | m_AutoUVMaxAngle: 89 71 | m_LightmapParameters: {fileID: 0} 72 | m_SortingLayerID: 0 73 | m_SortingLayer: 0 74 | m_SortingOrder: 0 75 | --- !u!33 &8131520927842024086 76 | MeshFilter: 77 | m_ObjectHideFlags: 0 78 | m_CorrespondingSourceObject: {fileID: 0} 79 | m_PrefabInstance: {fileID: 0} 80 | m_PrefabAsset: {fileID: 0} 81 | m_GameObject: {fileID: 1042568357287805991} 82 | m_Mesh: {fileID: 0} 83 | --- !u!64 &7519686632171402987 84 | MeshCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 1042568357287805991} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 4 94 | m_Convex: 0 95 | m_CookingOptions: 30 96 | m_Mesh: {fileID: 0} 97 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Chunk/ChunkUpdater.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Meshing; 2 | using Eldemarkki.VoxelTerrain.Meshing.Data; 3 | using Eldemarkki.VoxelTerrain.Utilities; 4 | using UnityEngine; 5 | using UnityEngine.Rendering; 6 | 7 | namespace Eldemarkki.VoxelTerrain.World.Chunks 8 | { 9 | public class ChunkUpdater : MonoBehaviour 10 | { 11 | /// 12 | /// The world for which to provide chunks for 13 | /// 14 | public VoxelWorld VoxelWorld { get; set; } 15 | 16 | private void Update() 17 | { 18 | foreach (ChunkProperties chunkProperties in VoxelWorld.ChunkStore.Chunks) 19 | { 20 | if (chunkProperties.HasChanges) 21 | { 22 | GenerateMeshImmediate(chunkProperties); 23 | } 24 | } 25 | } 26 | 27 | /// 28 | /// Generates the voxel data and colors for this chunk and generates the mesh 29 | /// 30 | public void GenerateVoxelDataAndMeshImmediate(ChunkProperties chunkProperties) 31 | { 32 | VoxelWorld.VoxelDataStore.GenerateDataForChunk(chunkProperties.ChunkCoordinate); 33 | VoxelWorld.VoxelColorStore.GenerateDataForChunk(chunkProperties.ChunkCoordinate); 34 | GenerateMeshImmediate(chunkProperties); 35 | } 36 | 37 | /// 38 | /// Forces the regeneration of the mesh 39 | /// 40 | public void GenerateMeshImmediate(ChunkProperties chunkProperties) 41 | { 42 | JobHandleWithData jobHandleWithData = VoxelWorld.VoxelMesher.CreateMesh(VoxelWorld.VoxelDataStore, VoxelWorld.VoxelColorStore, chunkProperties.ChunkCoordinate); 43 | if (jobHandleWithData == null) { return; } 44 | 45 | IMesherJob job = jobHandleWithData.JobData; 46 | 47 | Mesh mesh = new Mesh(); 48 | SubMeshDescriptor subMesh = new SubMeshDescriptor(0, 0); 49 | 50 | jobHandleWithData.JobHandle.Complete(); 51 | 52 | int vertexCount = job.VertexCountCounter.Count * 3; 53 | job.VertexCountCounter.Dispose(); 54 | 55 | mesh.SetVertexBufferParams(vertexCount, MeshingVertexData.VertexBufferMemoryLayout); 56 | mesh.SetIndexBufferParams(vertexCount, IndexFormat.UInt16); 57 | 58 | mesh.SetVertexBufferData(job.OutputVertices, 0, 0, vertexCount, 0, MeshUpdateFlags.DontValidateIndices); 59 | mesh.SetIndexBufferData(job.OutputTriangles, 0, 0, vertexCount, MeshUpdateFlags.DontValidateIndices); 60 | 61 | job.OutputVertices.Dispose(); 62 | job.OutputTriangles.Dispose(); 63 | 64 | mesh.subMeshCount = 1; 65 | subMesh.indexCount = vertexCount; 66 | mesh.SetSubMesh(0, subMesh); 67 | 68 | mesh.RecalculateBounds(); 69 | 70 | chunkProperties.MeshFilter.sharedMesh = mesh; 71 | chunkProperties.MeshCollider.sharedMesh = mesh; 72 | 73 | chunkProperties.MeshCollider.enabled = true; 74 | chunkProperties.MeshRenderer.enabled = true; 75 | 76 | chunkProperties.HasChanges = false; 77 | 78 | chunkProperties.IsMeshGenerated = true; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Assets/VertexColorMaterial.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: VertexColorMaterial 11 | m_Shader: {fileID: 210, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 0 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: 19 | - ALWAYS 20 | m_SavedProperties: 21 | serializedVersion: 3 22 | m_TexEnvs: 23 | - _BumpMap: 24 | m_Texture: {fileID: 0} 25 | m_Scale: {x: 1, y: 1} 26 | m_Offset: {x: 0, y: 0} 27 | - _DetailAlbedoMap: 28 | m_Texture: {fileID: 0} 29 | m_Scale: {x: 1, y: 1} 30 | m_Offset: {x: 0, y: 0} 31 | - _DetailMask: 32 | m_Texture: {fileID: 0} 33 | m_Scale: {x: 1, y: 1} 34 | m_Offset: {x: 0, y: 0} 35 | - _DetailNormalMap: 36 | m_Texture: {fileID: 0} 37 | m_Scale: {x: 1, y: 1} 38 | m_Offset: {x: 0, y: 0} 39 | - _EmissionMap: 40 | m_Texture: {fileID: 0} 41 | m_Scale: {x: 1, y: 1} 42 | m_Offset: {x: 0, y: 0} 43 | - _MainTex: 44 | m_Texture: {fileID: 0} 45 | m_Scale: {x: 1, y: 1} 46 | m_Offset: {x: 0, y: 0} 47 | - _MetallicGlossMap: 48 | m_Texture: {fileID: 0} 49 | m_Scale: {x: 1, y: 1} 50 | m_Offset: {x: 0, y: 0} 51 | - _OcclusionMap: 52 | m_Texture: {fileID: 0} 53 | m_Scale: {x: 1, y: 1} 54 | m_Offset: {x: 0, y: 0} 55 | - _ParallaxMap: 56 | m_Texture: {fileID: 0} 57 | m_Scale: {x: 1, y: 1} 58 | m_Offset: {x: 0, y: 0} 59 | - _SpecGlossMap: 60 | m_Texture: {fileID: 0} 61 | m_Scale: {x: 1, y: 1} 62 | m_Offset: {x: 0, y: 0} 63 | m_Floats: 64 | - _BlendOp: 0 65 | - _BumpScale: 1 66 | - _CameraFadingEnabled: 0 67 | - _CameraFarFadeDistance: 2 68 | - _CameraNearFadeDistance: 1 69 | - _Cull: 2 70 | - _Cutoff: 0.5 71 | - _DetailNormalMapScale: 1 72 | - _DistortionBlend: 0.5 73 | - _DistortionEnabled: 0 74 | - _DistortionStrength: 1 75 | - _DistortionStrengthScaled: 0 76 | - _DstBlend: 0 77 | - _EmissionEnabled: 0 78 | - _FlipbookMode: 0 79 | - _GlossMapScale: 1 80 | - _Glossiness: 0.215 81 | - _GlossyReflections: 1 82 | - _LightingEnabled: 1 83 | - _Metallic: 0 84 | - _Mode: 0 85 | - _OcclusionStrength: 1 86 | - _Parallax: 0.02 87 | - _SmoothnessTextureChannel: 0 88 | - _SoftParticlesEnabled: 0 89 | - _SoftParticlesFarFadeDistance: 1 90 | - _SoftParticlesNearFadeDistance: 0 91 | - _SpecularHighlights: 1 92 | - _SrcBlend: 1 93 | - _UVSec: 0 94 | - _ZWrite: 1 95 | m_Colors: 96 | - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0} 97 | - _Color: {r: 1, g: 1, b: 1, a: 1} 98 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 99 | - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} 100 | - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} 101 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/ProceduralTerrainVoxelDataCalculationJob.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Eldemarkki.VoxelTerrain.Settings; 3 | using Unity.Burst; 4 | using Unity.Mathematics; 5 | 6 | namespace Eldemarkki.VoxelTerrain.VoxelData 7 | { 8 | /// 9 | /// A procedural terrain voxel data calculation job 10 | /// 11 | [BurstCompile] 12 | public struct ProceduralTerrainVoxelDataCalculationJob : IVoxelDataGenerationJob 13 | { 14 | /// 15 | /// The procedural terrain generation settings 16 | /// 17 | public ProceduralTerrainSettings ProceduralTerrainSettings { get; set; } 18 | 19 | /// 20 | public int3 WorldPositionOffset { get; set; } 21 | 22 | /// 23 | public VoxelDataVolume OutputVoxelData { get; set; } 24 | 25 | /// 26 | /// The execute method required for Unity's IJobParallelFor job type 27 | /// 28 | public void Execute() 29 | { 30 | for (int x = 0; x < OutputVoxelData.Width; x++) 31 | { 32 | for (int z = 0; z < OutputVoxelData.Depth; z++) 33 | { 34 | int2 terrainPosition = new int2(x + WorldPositionOffset.x, z + WorldPositionOffset.z); 35 | float terrainNoise = OctaveNoise(terrainPosition.x, terrainPosition.y, ProceduralTerrainSettings.NoiseFrequency * 0.001f, ProceduralTerrainSettings.NoiseOctaveCount, ProceduralTerrainSettings.NoiseSeed) * ProceduralTerrainSettings.Amplitude; 36 | 37 | for (int y = 0; y < OutputVoxelData.Height; y++) 38 | { 39 | int3 worldPosition = new int3(terrainPosition.x, y + WorldPositionOffset.y, terrainPosition.y); 40 | 41 | float voxelData = (worldPosition.y - ProceduralTerrainSettings.HeightOffset - terrainNoise) * 0.5f; 42 | OutputVoxelData.SetVoxelData((byte)math.clamp(voxelData * 255, 0, 255), new int3(x, y, z)); 43 | } 44 | } 45 | } 46 | } 47 | 48 | /// 49 | /// Calculates octave noise 50 | /// 51 | /// Sampling point's x position 52 | /// Sampling point's y position 53 | /// The frequency of the noise 54 | /// How many layers of noise to combine 55 | /// The sampled noise value 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | private static float OctaveNoise(float x, float y, float frequency, int octaveCount, int seed) 58 | { 59 | float value = 0; 60 | 61 | for (int i = 0; i < octaveCount; i++) 62 | { 63 | int octaveModifier = (int)math.pow(2, i); 64 | 65 | // (x+1)/2 because noise.snoise returns a value from -1 to 1 so it needs to be scaled to go from 0 to 1. 66 | float pureNoise = (noise.snoise(new float3(octaveModifier * x * frequency, octaveModifier * y * frequency, seed)) + 1) / 2f; 67 | value += pureNoise / octaveModifier; 68 | } 69 | 70 | return value; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/UtilitiesTests/PlaneLineIntersectionTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Unity.Mathematics; 3 | 4 | namespace Eldemarkki.VoxelTerrain.Utilities.Intersection.Tests 5 | { 6 | public class PlaneLineIntersectionTests 7 | { 8 | private static void TestPlaneLineIntersectionResult(float3 planeOrigin, float3 planeNormal, float3 lineOrigin, float3 lineDirection, PlaneLineIntersectionResult expected) 9 | { 10 | PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, math.normalize(planeNormal), lineOrigin, lineDirection, out _); 11 | Assert.AreEqual(expected, result); 12 | } 13 | 14 | private static void TestPlaneLineIntersectionPoint(float3 planeOrigin, float3 planeNormal, float3 lineOrigin, float3 lineDirection, float3 expected) 15 | { 16 | _ = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint); 17 | Assert.AreEqual(expected, intersectionPoint); 18 | } 19 | 20 | [Test] 21 | public void Line_Above_Directly_Down_Result_Should_Be_OneHit() 22 | { 23 | TestPlaneLineIntersectionResult(new float3(0, 0, 0), new float3(0, 1, 0), new float3(0, 10, 0), new float3(0, -1, 0), PlaneLineIntersectionResult.OneHit); 24 | } 25 | 26 | [Test] 27 | public void Line_Above_Directly_Down_Should_Hit_0_0_0() 28 | { 29 | TestPlaneLineIntersectionPoint(new float3(0, 0, 0), new float3(0, 1, 0), new float3(0, 10, 0), new float3(0, -1, 0), new float3(0, 0, 0)); 30 | } 31 | 32 | [Test] 33 | public void Line_At_10_4_5_Directly_Down_Should_Hit_10_0_5() 34 | { 35 | TestPlaneLineIntersectionPoint(new float3(0, 0, 0), new float3(0, 1, 0), new float3(10, 4, 5), new float3(0, -1, 0), new float3(10, 0, 5)); 36 | } 37 | 38 | [Test] 39 | public void Line_Parallel_To_Plane_Not_Inside_Result_Should_Be_NoHit() 40 | { 41 | TestPlaneLineIntersectionResult(new float3(0, 4, 0), new float3(0, 1, 0), new float3(0, 10, 0), new float3(1, 0, 0), PlaneLineIntersectionResult.NoHit); 42 | } 43 | 44 | [Test] 45 | public void Line_Parallel_To_Plane_Inside_Result_Should_Be_ParallelInsidePlane() 46 | { 47 | TestPlaneLineIntersectionResult(new float3(0, 4, 0), new float3(0, 1, 0), new float3(0, 4, 0), new float3(1, 0, 0), PlaneLineIntersectionResult.ParallelInsidePlane); 48 | } 49 | 50 | [Test] 51 | public void Line_At_1_0_0_Plane_At_0_0_0_45_Degree_Angle_Should_Be_1_Negative1_0() 52 | { 53 | TestPlaneLineIntersectionPoint(new float3(0, 0, 0), new float3(1, 1, 0), new float3(1, 0, 0), new float3(0, -1, 0), new float3(1, -1, 0)); 54 | } 55 | 56 | [Test] 57 | public void Line_At_1_0_0_Plane_At_Negative1_0_0_45_Degree_Angle_Should_Be_1_Negative2_0() 58 | { 59 | TestPlaneLineIntersectionPoint(new float3(-1, 0, 0), new float3(1, 1, 0), new float3(1, 0, 0), new float3(0, -1, 0), new float3(1, -2, 0)); 60 | } 61 | 62 | [Test] 63 | public void Line_At_1_0_0_Plane_At_0_0_0_Custom_Angle_Should_Be_1_Negative2_0() 64 | { 65 | TestPlaneLineIntersectionPoint(new float3(0, 0, 0), new float3(1, 0.5f, 0), new float3(1, 0, 0), new float3(0, -1, 0), new float3(1, -2, 0)); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Assets/Heightmaps/circle.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c592a59b98b6d2149bd5cdf21483ecd0 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 1 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 0 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 2048 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 0 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 2048 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 0 97 | - serializedVersion: 3 98 | buildTarget: WebGL 99 | maxTextureSize: 2048 100 | resizeAlgorithm: 0 101 | textureFormat: -1 102 | textureCompression: 1 103 | compressionQuality: 50 104 | crunchedCompression: 0 105 | allowsAlphaSplitting: 0 106 | overridden: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | spriteSheet: 110 | serializedVersion: 2 111 | sprites: [] 112 | outline: [] 113 | physicsShape: [] 114 | bones: [] 115 | spriteID: 116 | internalID: 0 117 | vertices: [] 118 | indices: 119 | edges: [] 120 | weights: [] 121 | secondaryTextures: [] 122 | spritePackingTag: 123 | pSDRemoveMatte: 0 124 | pSDShowRemoveMatteOption: 0 125 | userData: 126 | assetBundleName: 127 | assetBundleVariant: 128 | -------------------------------------------------------------------------------- /Assets/Heightmaps/terrainheightmap.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cb1cd891623f1643b57dd752a2e2c45 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 1 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 0 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 512 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 0 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 0 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 512 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 0 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 0 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 512 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 0 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 0 97 | - serializedVersion: 3 98 | buildTarget: WebGL 99 | maxTextureSize: 512 100 | resizeAlgorithm: 0 101 | textureFormat: -1 102 | textureCompression: 0 103 | compressionQuality: 50 104 | crunchedCompression: 0 105 | allowsAlphaSplitting: 0 106 | overridden: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | spriteSheet: 110 | serializedVersion: 2 111 | sprites: [] 112 | outline: [] 113 | physicsShape: [] 114 | bones: [] 115 | spriteID: 116 | internalID: 0 117 | vertices: [] 118 | indices: 119 | edges: [] 120 | weights: [] 121 | secondaryTextures: [] 122 | spritePackingTag: 123 | pSDRemoveMatte: 0 124 | pSDShowRemoveMatteOption: 0 125 | userData: 126 | assetBundleName: 127 | assetBundleVariant: 128 | -------------------------------------------------------------------------------- /Assets/Scripts/Player/PlayerCamera.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Eldemarkki.VoxelTerrain.Player 4 | { 5 | /// 6 | /// A class to allow moving, rotating and zooming the camera 7 | /// 8 | [RequireComponent(typeof(Camera))] 9 | public class PlayerCamera : MonoBehaviour 10 | { 11 | /// 12 | /// The movement speed of the camera 13 | /// 14 | [Header("Movement")] 15 | [SerializeField] private float movementSpeed = 30f; 16 | 17 | /// 18 | /// How fast the camera rotates when the player moves the mouse 19 | /// 20 | [Header("Rotation")] 21 | [SerializeField] private float sensitivity = 3f; 22 | 23 | /// 24 | /// The minimum field of view the player can go to 25 | /// 26 | [Header("Zoom")] 27 | [SerializeField] private float minimumFieldOfView = 2; 28 | 29 | /// 30 | /// The maximum field of view the player can go to 31 | /// 32 | [SerializeField] private float maximumFieldOfView = 170; 33 | 34 | /// 35 | /// How fast the player can zoom (change the FOV) their camera 36 | /// 37 | [SerializeField] private float zoomSpeed = 3f; 38 | 39 | /// 40 | /// The target camera component cached 41 | /// 42 | private Camera _cam; 43 | 44 | /// 45 | /// The camera's current rotation in the x-axis 46 | /// 47 | private float _rotationX; 48 | 49 | /// 50 | /// The camera's current rotation in the y-axis 51 | /// 52 | private float _rotationY; 53 | 54 | private void Awake() 55 | { 56 | _cam = GetComponent(); 57 | _rotationX = -transform.eulerAngles.x; 58 | _rotationY = transform.eulerAngles.y; 59 | } 60 | 61 | private void Update() 62 | { 63 | Move(); 64 | LookAround(); 65 | Zoom(); 66 | } 67 | 68 | /// 69 | /// Gets the user input from the keyboard and uses that to move the camera 70 | /// 71 | private void Move() 72 | { 73 | Vector3 movement = Vector3.zero; 74 | movement.x += Input.GetAxisRaw("Horizontal"); 75 | if (Input.GetKey(KeyCode.Space)) 76 | { 77 | movement.y++; 78 | } 79 | else if (Input.GetKey(KeyCode.LeftShift)) 80 | { 81 | movement.y--; 82 | } 83 | 84 | movement.z += Input.GetAxisRaw("Vertical"); 85 | 86 | _cam.transform.Translate(movementSpeed * Time.deltaTime * movement.normalized, Space.Self); 87 | } 88 | 89 | /// 90 | /// Gets the user input from the mouse and uses that to rotate the camera 91 | /// 92 | private void LookAround() 93 | { 94 | // Dividing by 60 makes the sensitivity scale based on the FOV because the default FOV is 60. 95 | float rotationSpeed = sensitivity * _cam.fieldOfView / 60f; 96 | _rotationX += Input.GetAxis("Mouse Y") * rotationSpeed; 97 | _rotationY += Input.GetAxis("Mouse X") * rotationSpeed; 98 | 99 | _rotationX = Mathf.Clamp(_rotationX, -90, 90); 100 | 101 | transform.eulerAngles = new Vector3(-_rotationX, _rotationY, 0); 102 | } 103 | 104 | /// 105 | /// Gets the user input from the mouse scroll and uses that to zoom (change the FOV) 106 | /// 107 | private void Zoom() 108 | { 109 | _cam.fieldOfView = Mathf.Clamp(_cam.fieldOfView - Input.mouseScrollDelta.y * zoomSpeed, minimumFieldOfView, maximumFieldOfView); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/VoxelData/HeightmapTerrainVoxelDataCalculationJob.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using System.Runtime.CompilerServices; 3 | using Unity.Burst; 4 | using Unity.Collections; 5 | using Unity.Mathematics; 6 | 7 | namespace Eldemarkki.VoxelTerrain.VoxelData 8 | { 9 | /// 10 | /// A heightmap terrain voxel data calculation job 11 | /// 12 | [BurstCompile] 13 | public struct HeightmapTerrainVoxelDataCalculationJob : IVoxelDataGenerationJob 14 | { 15 | /// 16 | /// The height data from the heightmap 17 | /// 18 | [ReadOnly] private NativeArray _heightmapData; 19 | 20 | /// 21 | /// How wide the heightmap is (in pixels). 1 pixel = 1 Unity unit 22 | /// 23 | public int HeightmapWidth { get; set; } 24 | 25 | /// 26 | /// How high the heightmap is (in pixels). 1 pixel = 1 Unity unit 27 | /// 28 | public int HeightmapHeight { get; set; } 29 | 30 | /// 31 | /// The value to multiply the height with 32 | /// 33 | public float Amplitude { get; set; } 34 | 35 | /// 36 | /// The offset to move the sampling point up and down 37 | /// 38 | public float HeightOffset { get; set; } 39 | 40 | /// 41 | public int3 WorldPositionOffset { get; set; } 42 | 43 | /// 44 | public VoxelDataVolume OutputVoxelData { get; set; } 45 | 46 | /// 47 | /// The height data from the heightmap 48 | /// 49 | public NativeArray HeightmapData { get => _heightmapData; set => _heightmapData = value; } 50 | 51 | /// 52 | /// The execute method required for Unity's IJobParallelFor job type 53 | /// 54 | public void Execute() 55 | { 56 | int index = 0; 57 | for (int z = 0; z < OutputVoxelData.Depth; z++) 58 | { 59 | for (int y = 0; y < OutputVoxelData.Height; y++) 60 | { 61 | for (int x = 0; x < OutputVoxelData.Width; x++) 62 | { 63 | int3 worldPosition = new int3(x, y, z) + WorldPositionOffset; 64 | int worldPositionX = worldPosition.x; 65 | int worldPositionY = worldPosition.y; 66 | int worldPositionZ = worldPosition.z; 67 | 68 | float voxelData = 1; // 1, because the default voxel data should be air 69 | if (worldPositionX < HeightmapWidth && worldPositionZ < HeightmapHeight) 70 | { 71 | voxelData = CalculateVoxelData(worldPositionX, worldPositionY, worldPositionZ); 72 | } 73 | 74 | OutputVoxelData.SetVoxelData((byte)math.clamp(voxelData * 255, 0, 255), index); 75 | index++; 76 | } 77 | } 78 | } 79 | } 80 | 81 | /// 82 | /// Calculates the voxel data at the world-space position 83 | /// 84 | /// Sampling point's world-space x position 85 | /// Sampling point's world-space y position 86 | /// Sampling point's world-space z position 87 | /// The voxel data sampled from the world-space position 88 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 89 | public float CalculateVoxelData(int worldPositionX, int worldPositionY, int worldPositionZ) 90 | { 91 | float heightmapValue = _heightmapData[worldPositionX + worldPositionZ * HeightmapWidth]; 92 | float h = Amplitude * heightmapValue; 93 | return worldPositionY - h - HeightOffset; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Meshing/Data/VoxelCorners.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace Eldemarkki.VoxelTerrain.Meshing.Data 6 | { 7 | /// 8 | /// A container for the corners of a voxel 9 | /// 10 | /// The element's type to hold in the corners 11 | public struct VoxelCorners : IEnumerable 12 | { 13 | /// 14 | /// The first corner 15 | /// 16 | public T Corner1 { get; set; } 17 | 18 | /// 19 | /// The second corner 20 | /// 21 | public T Corner2 { get; set; } 22 | 23 | /// 24 | /// The third corner 25 | /// 26 | public T Corner3 { get; set; } 27 | 28 | /// 29 | /// The fourth corner 30 | /// 31 | public T Corner4 { get; set; } 32 | 33 | /// 34 | /// The fifth corner 35 | /// 36 | public T Corner5 { get; set; } 37 | 38 | /// 39 | /// The sixth corner 40 | /// 41 | public T Corner6 { get; set; } 42 | 43 | /// 44 | /// The seventh corner 45 | /// 46 | public T Corner7 { get; set; } 47 | 48 | /// 49 | /// The eighth corner 50 | /// 51 | public T Corner8 { get; set; } 52 | 53 | /// 54 | /// The indexer for the voxel corners 55 | /// 56 | /// The corner's index 57 | /// Thrown when index is larger than 7. 58 | public T this[int index] 59 | { 60 | get 61 | { 62 | switch (index) 63 | { 64 | case 0: return Corner1; 65 | case 1: return Corner2; 66 | case 2: return Corner3; 67 | case 3: return Corner4; 68 | case 4: return Corner5; 69 | case 5: return Corner6; 70 | case 6: return Corner7; 71 | case 7: return Corner8; 72 | default: throw new ArgumentOutOfRangeException($"There are only 8 corners! You tried to access the corner at index {index}"); 73 | } 74 | } 75 | set 76 | { 77 | switch (index) 78 | { 79 | case 0: 80 | Corner1 = value; 81 | break; 82 | case 1: 83 | Corner2 = value; 84 | break; 85 | case 2: 86 | Corner3 = value; 87 | break; 88 | case 3: 89 | Corner4 = value; 90 | break; 91 | case 4: 92 | Corner5 = value; 93 | break; 94 | case 5: 95 | Corner6 = value; 96 | break; 97 | case 6: 98 | Corner7 = value; 99 | break; 100 | case 7: 101 | Corner8 = value; 102 | break; 103 | default: throw new ArgumentOutOfRangeException($"There are only 8 corners! You tried to access the corner at index {index}"); 104 | } 105 | } 106 | } 107 | 108 | public IEnumerator GetEnumerator() 109 | { 110 | for (int i = 0; i < 8; i++) 111 | { 112 | yield return this[i]; 113 | } 114 | } 115 | 116 | IEnumerator IEnumerable.GetEnumerator() 117 | { 118 | return GetEnumerator(); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/TerrainSettings/HeightmapTerrainSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Collections; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.Settings 6 | { 7 | /// 8 | /// A class that contains information about how the heightmap world should be generated 9 | /// 10 | [CreateAssetMenu(fileName = "New Heightmap Terrain Settings", menuName = "Marching Cubes Terrain/Heightmap Terrain Settings")] 11 | public class HeightmapTerrainSettings : ScriptableObject, IDisposable 12 | { 13 | /// 14 | /// The black and white heightmap texture 15 | /// 16 | [SerializeField] private Texture2D heightmap; 17 | 18 | /// 19 | /// The generated height data from the the heightmap 20 | /// 21 | [SerializeField] private NativeArray heightmapData; 22 | 23 | /// 24 | /// Height multiplier 25 | /// 26 | [SerializeField] private float amplitude; 27 | 28 | /// 29 | /// Moves the sampling point up and down 30 | /// 31 | [SerializeField] private float heightOffset; 32 | 33 | /// 34 | /// The width of the heightmap in pixels 35 | /// 36 | public int Width { get; private set; } 37 | 38 | /// 39 | /// The height of the heightmap in pixels 40 | /// 41 | public int Height { get; private set; } 42 | 43 | /// 44 | /// The black and white heightmap texture 45 | /// 46 | public Texture2D Heightmap 47 | { 48 | get => heightmap; 49 | set => heightmap = value; 50 | } 51 | 52 | /// 53 | /// The generated height data from the the heightmap 54 | /// 55 | public NativeArray HeightmapData 56 | { 57 | get => heightmapData; 58 | set => heightmapData = value; 59 | } 60 | 61 | /// 62 | /// Height multiplier 63 | /// 64 | public float Amplitude 65 | { 66 | get => amplitude; 67 | set => amplitude = value; 68 | } 69 | 70 | /// 71 | /// Moves the sampling point up and down 72 | /// 73 | public float HeightOffset 74 | { 75 | get => heightOffset; 76 | set => heightOffset = value; 77 | } 78 | 79 | /// 80 | /// Converts the parameters to a format the can be used by the Job System 81 | /// 82 | /// The black and white heightmap 83 | /// Height multiplier 84 | /// Moves the sampling point up and down 85 | public void Initialize(Texture2D heightmap, float amplitude, float heightOffset) 86 | { 87 | this.amplitude = amplitude; 88 | this.heightOffset = heightOffset; 89 | 90 | this.heightmap = heightmap; 91 | Width = heightmap.width; 92 | Height = heightmap.height; 93 | 94 | heightmapData = new NativeArray(Width * Height, Allocator.Persistent); 95 | SetHeightmap(heightmap); 96 | } 97 | 98 | /// 99 | /// Generates the HeightmapData from the heightmap 100 | /// 101 | /// The black and white heightmap 102 | private void SetHeightmap(Texture2D heightmap) 103 | { 104 | for (int x = 0; x < Width; x++) 105 | { 106 | for (int y = 0; y < Height; y++) 107 | { 108 | heightmapData[x + Width * y] = heightmap.GetPixel(x, y).grayscale; 109 | } 110 | } 111 | } 112 | 113 | /// 114 | /// Disposes HeightmapData 115 | /// 116 | public void Dispose() 117 | { 118 | heightmapData.Dispose(); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Core/Utilities/VectorUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | 5 | namespace Eldemarkki.VoxelTerrain.Utilities 6 | { 7 | /// 8 | /// A collection of utilities that operate on vectors (int3/float3) 9 | /// 10 | public static class VectorUtilities 11 | { 12 | /// 13 | /// Floors the value to a multiple of x 14 | /// 15 | /// The value to floor 16 | /// The multiple to floor to 17 | /// The floored value 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public static int3 FloorToMultipleOfX(this float3 n, int3 x) 20 | { 21 | return (int3)(math.floor(n / x) * x); 22 | } 23 | 24 | /// 25 | /// Floors the value to a multiple of x 26 | /// 27 | /// The value to floor 28 | /// The multiple to floor to 29 | /// The floored value 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public static int3 FloorToMultipleOfX(this Vector3 n, int3 x) 32 | { 33 | return (int3)(math.floor(new float3(n.x / x.x, n.y / x.y, n.z / x.z)) * x); 34 | } 35 | 36 | /// 37 | /// Converts an int3 value to Vector3Int 38 | /// 39 | /// The int3 value to convert 40 | /// The converted value 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public static Vector3Int ToVectorInt(this int3 n) 43 | { 44 | return new Vector3Int(n.x, n.y, n.z); 45 | } 46 | 47 | /// 48 | /// Converts a Vector3 to a int3 by casting the xyz values to ints 49 | /// 50 | /// The Vector3 to be converted 51 | /// The converted int3 52 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 | public static int3 ToInt3(this Vector3 n) 54 | { 55 | return new int3((int)n.x, (int)n.y, (int)n.z); 56 | } 57 | 58 | /// 59 | /// Converts a Vector3 to a int3 by casting the xyz values to ints 60 | /// 61 | /// The Vector3 to be converted 62 | /// The converted int3 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | public static int3 ToInt3(this Vector3Int n) 65 | { 66 | return new int3(n.x, n.y, n.z); 67 | } 68 | 69 | /// 70 | /// Calculates the remainder of a division operation for int3. Ensures that the returned value is positive 71 | /// 72 | /// The dividend 73 | /// The divisor 74 | /// The remainder of n/x 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | public static int3 Mod(this int3 n, int3 x) 77 | { 78 | return (n % x + x) % x; 79 | } 80 | 81 | /// 82 | /// Converts a world position to a chunk coordinate 83 | /// 84 | /// The world-position that should be converted 85 | /// The size of a chunk in the world 86 | /// The chunk coordinate 87 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 88 | public static int3 WorldPositionToCoordinate(float3 worldPosition, int3 chunkSize) 89 | { 90 | return worldPosition.FloorToMultipleOfX(chunkSize) / chunkSize; 91 | } 92 | 93 | /// 94 | /// Converts a world position to a chunk coordinate 95 | /// 96 | /// The world-position that should be converted 97 | /// The size of a chunk in the world 98 | /// The chunk coordinate 99 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 100 | public static int3 WorldPositionToCoordinate(Vector3 worldPosition, int3 chunkSize) 101 | { 102 | return worldPosition.FloorToMultipleOfX(chunkSize) / chunkSize; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/VertexList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Unity.Mathematics; 5 | 6 | namespace Eldemarkki.VoxelTerrain.Meshing.MarchingCubes 7 | { 8 | /// 9 | /// A container for a vertex list with 12 vertices 10 | /// 11 | public struct VertexList : IEnumerable 12 | { 13 | /// 14 | /// The first vertex 15 | /// 16 | private float3 _c1; 17 | 18 | /// 19 | /// The second vertex 20 | /// 21 | private float3 _c2; 22 | 23 | /// 24 | /// The third vertex 25 | /// 26 | private float3 _c3; 27 | 28 | /// 29 | /// The fourth vertex 30 | /// 31 | private float3 _c4; 32 | 33 | /// 34 | /// The fifth vertex 35 | /// 36 | private float3 _c5; 37 | 38 | /// 39 | /// The sixth vertex 40 | /// 41 | private float3 _c6; 42 | 43 | /// 44 | /// The seventh vertex 45 | /// 46 | private float3 _c7; 47 | 48 | /// 49 | /// The eighth vertex 50 | /// 51 | private float3 _c8; 52 | 53 | /// 54 | /// The ninth vertex 55 | /// 56 | private float3 _c9; 57 | 58 | /// 59 | /// The tenth vertex 60 | /// 61 | private float3 _c10; 62 | 63 | /// 64 | /// The eleventh vertex 65 | /// 66 | private float3 _c11; 67 | 68 | /// 69 | /// The twelfth vertex 70 | /// 71 | private float3 _c12; 72 | 73 | /// 74 | /// The indexer for the vertex list 75 | /// 76 | /// The vertex's index 77 | /// Thrown when the index is more than 11. 78 | public float3 this[int index] 79 | { 80 | get 81 | { 82 | switch (index) 83 | { 84 | case 0: return _c1; 85 | case 1: return _c2; 86 | case 2: return _c3; 87 | case 3: return _c4; 88 | case 4: return _c5; 89 | case 5: return _c6; 90 | case 6: return _c7; 91 | case 7: return _c8; 92 | case 8: return _c9; 93 | case 9: return _c10; 94 | case 10: return _c11; 95 | case 11: return _c12; 96 | default: throw new ArgumentOutOfRangeException($"There are only 12 vertices! You tried to access the vertex at index {index}"); 97 | } 98 | } 99 | set 100 | { 101 | switch (index) 102 | { 103 | case 0: 104 | _c1 = value; 105 | break; 106 | case 1: 107 | _c2 = value; 108 | break; 109 | case 2: 110 | _c3 = value; 111 | break; 112 | case 3: 113 | _c4 = value; 114 | break; 115 | case 4: 116 | _c5 = value; 117 | break; 118 | case 5: 119 | _c6 = value; 120 | break; 121 | case 6: 122 | _c7 = value; 123 | break; 124 | case 7: 125 | _c8 = value; 126 | break; 127 | case 8: 128 | _c9 = value; 129 | break; 130 | case 9: 131 | _c10 = value; 132 | break; 133 | case 10: 134 | _c11 = value; 135 | break; 136 | case 11: 137 | _c12 = value; 138 | break; 139 | default: throw new ArgumentOutOfRangeException($"There are only 12 vertices! You tried to access the vertex at index {index}"); 140 | } 141 | } 142 | } 143 | 144 | public IEnumerator GetEnumerator() 145 | { 146 | for (int i = 0; i < 12; i++) 147 | { 148 | yield return this[i]; 149 | } 150 | } 151 | 152 | IEnumerator IEnumerable.GetEnumerator() 153 | { 154 | return GetEnumerator(); 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesJob.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Meshing.Data; 2 | using Eldemarkki.VoxelTerrain.VoxelData; 3 | using Unity.Burst; 4 | using Unity.Collections; 5 | using Unity.Mathematics; 6 | using UnityEngine; 7 | 8 | namespace Eldemarkki.VoxelTerrain.Meshing.MarchingCubes 9 | { 10 | /// 11 | /// A marching cubes mesh generation job 12 | /// 13 | [BurstCompile] 14 | public struct MarchingCubesJob : IMesherJob 15 | { 16 | /// 17 | [ReadOnly] private VoxelDataVolume _voxelData; 18 | 19 | /// 20 | [ReadOnly] private VoxelDataVolume _voxelColors; 21 | 22 | /// 23 | /// The density level where a surface will be created. Densities below this will be inside the surface (solid), 24 | /// and densities above this will be outside the surface (air) 25 | /// 26 | public float Isolevel { get; set; } 27 | 28 | /// 29 | public NativeCounter VertexCountCounter { get; set; } 30 | 31 | /// 32 | [NativeDisableParallelForRestriction, WriteOnly] private NativeArray _vertices; 33 | 34 | /// 35 | [NativeDisableParallelForRestriction, WriteOnly] private NativeArray _triangles; 36 | 37 | /// 38 | public VoxelDataVolume VoxelData { get => _voxelData; set => _voxelData = value; } 39 | 40 | /// 41 | public VoxelDataVolume VoxelColors { get => _voxelColors; set => _voxelColors = value; } 42 | 43 | /// 44 | public NativeArray OutputVertices { get => _vertices; set => _vertices = value; } 45 | 46 | /// 47 | public NativeArray OutputTriangles { get => _triangles; set => _triangles = value; } 48 | 49 | /// 50 | /// The execute method required by the Unity Job System's IJob 51 | /// 52 | public void Execute() 53 | { 54 | byte isolevelByte = (byte)math.clamp(Isolevel * 255, 0, 255); 55 | for (int x = 0; x < VoxelData.Width - 1; x++) 56 | { 57 | for (int y = 0; y < VoxelData.Height - 1; y++) 58 | { 59 | for (int z = 0; z < VoxelData.Depth - 1; z++) 60 | { 61 | int3 voxelLocalPosition = new int3(x, y, z); 62 | 63 | VoxelCorners densities = _voxelData.GetVoxelDataUnitCube(voxelLocalPosition); 64 | 65 | byte cubeIndex = MarchingCubesFunctions.CalculateCubeIndex(densities, isolevelByte); 66 | if (cubeIndex == 0 || cubeIndex == 255) 67 | { 68 | continue; 69 | } 70 | 71 | int edgeIndex = MarchingCubesLookupTables.EdgeTable[cubeIndex]; 72 | 73 | VertexList vertexList = MarchingCubesFunctions.GenerateVertexList(densities, voxelLocalPosition, edgeIndex, isolevelByte); 74 | 75 | // Index at the beginning of the row 76 | int rowIndex = 15 * cubeIndex; 77 | 78 | for (int i = 0; MarchingCubesLookupTables.TriangleTable[rowIndex + i] != -1 && i < 15; i += 3) 79 | { 80 | float3 vertex1 = vertexList[MarchingCubesLookupTables.TriangleTable[rowIndex + i + 0]]; 81 | float3 vertex2 = vertexList[MarchingCubesLookupTables.TriangleTable[rowIndex + i + 1]]; 82 | float3 vertex3 = vertexList[MarchingCubesLookupTables.TriangleTable[rowIndex + i + 2]]; 83 | 84 | if (!vertex1.Equals(vertex2) && !vertex1.Equals(vertex3) && !vertex2.Equals(vertex3)) 85 | { 86 | float3 normal = math.normalize(math.cross(vertex2 - vertex1, vertex3 - vertex1)); 87 | 88 | int triangleIndex = VertexCountCounter.Increment() * 3; 89 | 90 | float3 triangleMiddlePoint = (vertex1 + vertex2 + vertex3) / 3f; 91 | 92 | // Take the position of the closest corner of the current voxel 93 | int3 colorSamplePoint = (int3)math.round(triangleMiddlePoint); 94 | Color32 color = VoxelColors.GetVoxelData(colorSamplePoint); 95 | 96 | _vertices[triangleIndex + 0] = new MeshingVertexData(vertex1, normal, color); 97 | _triangles[triangleIndex + 0] = (ushort)(triangleIndex + 0); 98 | 99 | _vertices[triangleIndex + 1] = new MeshingVertexData(vertex2, normal, color); 100 | _triangles[triangleIndex + 1] = (ushort)(triangleIndex + 1); 101 | 102 | _vertices[triangleIndex + 2] = new MeshingVertexData(vertex3, normal, color); 103 | _triangles[triangleIndex + 2] = (ushort)(triangleIndex + 2); 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/Meshing/MarchingCubes/MarchingCubesFunctions.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Utilities; 2 | using System.Runtime.CompilerServices; 3 | using Eldemarkki.VoxelTerrain.Meshing.Data; 4 | using Unity.Mathematics; 5 | using Eldemarkki.VoxelTerrain.VoxelData; 6 | 7 | namespace Eldemarkki.VoxelTerrain.Meshing.MarchingCubes 8 | { 9 | /// 10 | /// A collection of Marching Cubes -related functions 11 | /// 12 | public static class MarchingCubesFunctions 13 | { 14 | /// 15 | /// Interpolates the vertex's position 16 | /// 17 | /// The first corner's position 18 | /// The second corner's position 19 | /// The first corner's density 20 | /// The second corner's density 21 | /// The density level where a surface will be created. Densities below this will be inside the surface (solid), 22 | /// and densities above this will be outside the surface (air) 23 | /// The interpolated vertex's position 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static float3 VertexInterpolate(float3 p1, float3 p2, float v1, float v2, float isolevel) 26 | { 27 | return p1 + (isolevel - v1) * (p2 - p1) / (v2 - v1); 28 | } 29 | 30 | /// 31 | /// Calculates the cube index of a single voxel 32 | /// 33 | /// The densities of the voxel 34 | /// The density level where a surface will be created. Densities below this will be inside the surface (solid), 35 | /// and densities above this will be outside the surface (air) 36 | /// The calculated cube index 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | public static byte CalculateCubeIndex(VoxelCorners voxelDensities, byte isolevel) 39 | { 40 | byte cubeIndex = (byte)math.select(0, 1, voxelDensities.Corner1 < isolevel); 41 | cubeIndex |= (byte)math.select(0, 2, voxelDensities.Corner2 < isolevel); 42 | cubeIndex |= (byte)math.select(0, 4, voxelDensities.Corner3 < isolevel); 43 | cubeIndex |= (byte)math.select(0, 8, voxelDensities.Corner4 < isolevel); 44 | cubeIndex |= (byte)math.select(0, 16, voxelDensities.Corner5 < isolevel); 45 | cubeIndex |= (byte)math.select(0, 32, voxelDensities.Corner6 < isolevel); 46 | cubeIndex |= (byte)math.select(0, 64, voxelDensities.Corner7 < isolevel); 47 | cubeIndex |= (byte)math.select(0, 128, voxelDensities.Corner8 < isolevel); 48 | 49 | return cubeIndex; 50 | } 51 | 52 | /// 53 | /// Generates the vertex list for a single voxel 54 | /// 55 | /// The densities of the voxel 56 | /// The local voxel position of the voxel whose vertex list should be generated 57 | /// The edge index 58 | /// The density level where a surface will be created. Densities below this will be inside the surface (solid), 59 | /// and densities above this will be outside the surface (air) 60 | /// The generated vertex list for the voxel 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public static VertexList GenerateVertexList(VoxelCorners voxelDensities, int3 voxelLocalPosition, 63 | int edgeIndex, byte isolevel) 64 | { 65 | VertexList vertexList = new VertexList(); 66 | 67 | for (int i = 0; i < 12; i++) 68 | { 69 | if ((edgeIndex & (1 << i)) == 0) { continue; } 70 | 71 | int edgeStartIndex = MarchingCubesLookupTables.EdgeIndexTable[2 * i + 0]; 72 | int edgeEndIndex = MarchingCubesLookupTables.EdgeIndexTable[2 * i + 1]; 73 | 74 | int3 corner1 = voxelLocalPosition + LookupTables.CubeCorners[edgeStartIndex]; 75 | int3 corner2 = voxelLocalPosition + LookupTables.CubeCorners[edgeEndIndex]; 76 | 77 | float density1 = voxelDensities[edgeStartIndex] / 255f; 78 | float density2 = voxelDensities[edgeEndIndex] / 255f; 79 | 80 | vertexList[i] = VertexInterpolate(corner1, corner2, density1, density2, isolevel / 255f); 81 | } 82 | 83 | return vertexList; 84 | } 85 | 86 | /// 87 | /// Gets a cube-shaped volume of voxel data from . The size of the cube is 1 unit. 88 | /// 89 | /// The voxel data array to get the voxel data from 90 | /// The origin of the cube 91 | /// A cube-shaped volume of voxel data. The size of the cube is 1 unit. 92 | public static VoxelCorners GetVoxelDataUnitCube(this VoxelDataVolume voxelDataArray, int3 localPosition) where T : struct 93 | { 94 | VoxelCorners voxelDataCorners = new VoxelCorners(); 95 | for (int i = 0; i < 8; i++) 96 | { 97 | int3 voxelCorner = localPosition + LookupTables.CubeCorners[i]; 98 | if (voxelDataArray.TryGetVoxelData(voxelCorner, out T voxelData)) 99 | { 100 | voxelDataCorners[i] = voxelData; 101 | } 102 | } 103 | 104 | return voxelDataCorners; 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/VoxelDataVolumeTests/VoxelDataVolumeTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using Unity.Collections; 4 | using Unity.Mathematics; 5 | 6 | namespace Eldemarkki.VoxelTerrain.VoxelData.Tests 7 | { 8 | public class VoxelDataVolumeTests 9 | { 10 | private VoxelDataVolume voxelDataVolume; 11 | 12 | [TestCase(0, 9, 3)] 13 | [TestCase(5, 2, 13)] 14 | [TestCase(16, 7, 4)] 15 | public void Test_Xyz_Constructor_Width(int width, int height, int depth) 16 | { 17 | voxelDataVolume = new VoxelDataVolume(width, height, depth, Allocator.Temp); 18 | Assert.AreEqual(width, voxelDataVolume.Width); 19 | } 20 | 21 | [TestCase(0, 9, 3)] 22 | [TestCase(5, 2, 13)] 23 | [TestCase(16, 7, 4)] 24 | public void Test_Xyz_Constructor_Height(int width, int height, int depth) 25 | { 26 | voxelDataVolume = new VoxelDataVolume(width, height, depth, Allocator.Temp); 27 | Assert.AreEqual(height, voxelDataVolume.Height); 28 | } 29 | 30 | [TestCase(0, 9, 3)] 31 | [TestCase(5, 2, 13)] 32 | [TestCase(16, 7, 4)] 33 | public void Test_Xyz_Constructor_Depth(int width, int height, int depth) 34 | { 35 | voxelDataVolume = new VoxelDataVolume(width, height, depth, Allocator.Temp); 36 | Assert.AreEqual(depth, voxelDataVolume.Depth); 37 | } 38 | 39 | [TestCase(0)] 40 | [TestCase(5)] 41 | [TestCase(16)] 42 | public void Test_Int_Size_Constructor_Size(int size) 43 | { 44 | voxelDataVolume = new VoxelDataVolume(size, Allocator.Temp); 45 | Assert.AreEqual(new int3(size, size, size), voxelDataVolume.Size); 46 | } 47 | 48 | [TestCase(0, 9, 3)] 49 | [TestCase(5, 2, 13)] 50 | [TestCase(16, 7, 4)] 51 | public void Test_Xyz_Constructor_Length(int width, int height, int depth) 52 | { 53 | voxelDataVolume = new VoxelDataVolume(width, height, depth, Allocator.Temp); 54 | Assert.AreEqual(width * height * depth, voxelDataVolume.Length); 55 | } 56 | 57 | [TestCase(0, 9, 3)] 58 | [TestCase(5, 2, 13)] 59 | [TestCase(16, 7, 4)] 60 | public void Test_Xyz_Constructor_IsCreated(int width, int height, int depth) 61 | { 62 | voxelDataVolume = new VoxelDataVolume(width, height, depth, Allocator.Temp); 63 | Assert.AreEqual(true, voxelDataVolume.IsCreated); 64 | } 65 | 66 | [TestCase(-10)] 67 | [TestCase(-5)] 68 | public void Test_Int_Size_Constructor_Negative_Throws(int size) 69 | { 70 | Assert.Throws(() => 71 | { 72 | voxelDataVolume = new VoxelDataVolume(size, Allocator.Temp); 73 | }); 74 | } 75 | 76 | [Test] 77 | public void Test_Default_Constructor_IsNotCreated() 78 | { 79 | voxelDataVolume = new VoxelDataVolume(); 80 | Assert.AreEqual(false, voxelDataVolume.IsCreated); 81 | } 82 | 83 | [Test] 84 | public void Test_Voxel_Datas_Are_Initialized_To_0() 85 | { 86 | voxelDataVolume = new VoxelDataVolume(5, Allocator.Temp); 87 | for (int i = 0; i < voxelDataVolume.Length; i++) 88 | { 89 | Assert.AreEqual(0, voxelDataVolume.GetVoxelData(i)); 90 | } 91 | } 92 | 93 | private void TestSetGetVoxelData(Func function, float newVoxelData) 94 | { 95 | voxelDataVolume = new VoxelDataVolume(5, Allocator.Temp); 96 | float actualVoxelData = function(); 97 | Assert.IsTrue(AreVoxelDatasSame(newVoxelData, actualVoxelData), $"Expected {newVoxelData}, actual was {actualVoxelData}"); 98 | } 99 | 100 | [Test] 101 | public void Test_SetGetVoxelData_Index([Random(0, 1f, 5)] float newVoxelData, [Random(0, 5 * 5 * 5 - 1, 5)] int index) 102 | { 103 | TestSetGetVoxelData(() => 104 | { 105 | voxelDataVolume.SetVoxelData(newVoxelData, index); 106 | return voxelDataVolume.GetVoxelData(index); 107 | }, newVoxelData); 108 | } 109 | 110 | [Test] 111 | public void Test_SetGetVoxelData_Xyz([Random(0, 1f, 5)] float newVoxelData, [Random(0, 4, 3)] int x, [Random(0, 4, 3)] int y, [Random(0, 4, 3)] int z) 112 | { 113 | TestSetGetVoxelData(() => 114 | { 115 | voxelDataVolume.SetVoxelData(newVoxelData, x, y, z); 116 | return voxelDataVolume.GetVoxelData(x, y, z); 117 | }, newVoxelData); 118 | } 119 | 120 | [Test] 121 | public void Test_SetGetVoxelData_Int3([Random(0, 1f, 5)] float newVoxelData, [Random(0, 4, 3)] int x, [Random(0, 4, 3)] int y, [Random(0, 4, 3)] int z) 122 | { 123 | TestSetGetVoxelData(() => 124 | { 125 | voxelDataVolume.SetVoxelData(newVoxelData, new int3(x, y, z)); 126 | return voxelDataVolume.GetVoxelData(new int3(x, y, z)); 127 | }, newVoxelData); 128 | } 129 | 130 | private static bool AreVoxelDatasSame(float a, float b) 131 | { 132 | byte aByte = (byte)RoundUpIfDecimal5(255f * a); 133 | byte bByte = (byte)RoundUpIfDecimal5(255f * b); 134 | 135 | return aByte == bByte; 136 | } 137 | 138 | // This function is an "improvement" (not really...) of math.round() 139 | // This rounds a number down if its decimal is less than 0.5, and otherwise up: 140 | // 0.5 => 1 141 | // 0.49999 => 0 142 | // 76.5 => 77 143 | // 76.49999 => 76 144 | // This was needed because math.round rounded 0.5 => 0, which was incorrect when comparing voxel datas. 145 | private static int RoundUpIfDecimal5(float x) 146 | { 147 | if (x < 0) 148 | { 149 | throw new System.ArgumentException("This function only works with positive numbers!"); 150 | } 151 | 152 | int result; 153 | float decimals = x % 1; 154 | if (decimals < 0.5f) 155 | { 156 | result = (int)math.floor(x); 157 | } 158 | else 159 | { 160 | result = (int)math.ceil(x); 161 | } 162 | 163 | return result; 164 | } 165 | 166 | [TearDown] 167 | public void Teardown() 168 | { 169 | if (voxelDataVolume.IsCreated) 170 | { 171 | voxelDataVolume.Dispose(); 172 | } 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain.Tests/Core/ChunkUtilitiesTests/CoordinateUtilitiesTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Collections.Generic; 3 | using Unity.Mathematics; 4 | 5 | namespace Eldemarkki.VoxelTerrain.Utilities.Tests 6 | { 7 | public class CoordinateUtilitiesTests 8 | { 9 | [Test] 10 | public void GetChunkCoordinatesContainingPoint_Test1() 11 | { 12 | int3 worldPosition = new int3(0, 0, 0); 13 | int chunkSize = 16; 14 | 15 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 16 | 17 | IEnumerable expectedCoordinates = new List 18 | { 19 | new int3( 0, 0, 0), 20 | new int3(-1, 0, 0), 21 | new int3( 0, -1, 0), 22 | new int3(-1, -1, 0), 23 | new int3( 0, 0, -1), 24 | new int3(-1, 0, -1), 25 | new int3( 0, -1, -1), 26 | new int3(-1, -1, -1), 27 | }; 28 | 29 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 30 | } 31 | 32 | [Test] 33 | public void GetChunkCoordinatesContainingPoint_Test2() 34 | { 35 | int3 worldPosition = new int3(16, 0, 16); 36 | int chunkSize = 16; 37 | 38 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 39 | 40 | IEnumerable expectedCoordinates = new List 41 | { 42 | new int3( 1, 0, 1), 43 | new int3( 0, 0, 1), 44 | new int3( 1, -1, 1), 45 | new int3( 0, -1, 1), 46 | new int3( 1, 0, 0), 47 | new int3( 0, 0, 0), 48 | new int3( 1, -1, 0), 49 | new int3( 0, -1, 0), 50 | }; 51 | 52 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 53 | } 54 | 55 | [Test] 56 | public void GetChunkCoordinatesContainingPoint_Test3() 57 | { 58 | int3 worldPosition = new int3(16, 1, 16); 59 | int chunkSize = 16; 60 | 61 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 62 | 63 | IEnumerable expectedCoordinates = new List 64 | { 65 | new int3( 1, 0, 1), 66 | new int3( 0, 0, 1), 67 | new int3( 1, 0, 0), 68 | new int3( 0, 0, 0), 69 | }; 70 | 71 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 72 | } 73 | 74 | [Test] 75 | public void GetChunkCoordinatesContainingPoint_Test4() 76 | { 77 | int3 worldPosition = new int3(5, 3, 16); 78 | int chunkSize = 16; 79 | 80 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 81 | 82 | IEnumerable expectedCoordinates = new List 83 | { 84 | new int3( 0, 0, 1), 85 | new int3( 0, 0, 0), 86 | }; 87 | 88 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 89 | } 90 | 91 | [Test] 92 | public void GetChunkCoordinatesContainingPoint_Test5() 93 | { 94 | int3 worldPosition = new int3(-48, -32, -16); 95 | int chunkSize = 16; 96 | 97 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 98 | 99 | IEnumerable expectedCoordinates = new List 100 | { 101 | new int3(-3, -2, -1), 102 | new int3(-4, -2, -1), 103 | new int3(-3, -3, -1), 104 | new int3(-4, -3, -1), 105 | new int3(-3, -2, -2), 106 | new int3(-4, -2, -2), 107 | new int3(-3, -3, -2), 108 | new int3(-4, -3, -2), 109 | }; 110 | 111 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 112 | } 113 | 114 | [Test] 115 | public void GetChunkCoordinatesContainingPoint_Test6() 116 | { 117 | int3 worldPosition = new int3(0, 5, 5); 118 | int chunkSize = 16; 119 | 120 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 121 | 122 | IEnumerable expectedCoordinates = new List 123 | { 124 | new int3( 0, 0, 0), 125 | new int3(-1, 0, 0), 126 | }; 127 | 128 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 129 | } 130 | 131 | 132 | [Test] 133 | public void GetChunkCoordinatesContainingPoint_Test7() 134 | { 135 | int3 worldPosition = new int3(5, 0, 5); 136 | int chunkSize = 16; 137 | 138 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 139 | 140 | IEnumerable expectedCoordinates = new List 141 | { 142 | new int3(0, 0, 0), 143 | new int3(0, -1, 0), 144 | }; 145 | 146 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 147 | } 148 | 149 | [Test] 150 | public void GetChunkCoordinatesContainingPoint_Test8() 151 | { 152 | int3 worldPosition = new int3(5, 5, 0); 153 | int chunkSize = 16; 154 | 155 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 156 | 157 | IEnumerable expectedCoordinates = new List 158 | { 159 | new int3(0, 0, 0), 160 | new int3(0, 0, -1), 161 | }; 162 | 163 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 164 | } 165 | 166 | 167 | [Test] 168 | public void GetChunkCoordinatesContainingPoint_Test9() 169 | { 170 | int3 worldPosition = new int3(7, 7, 7); 171 | int chunkSize = 7; 172 | 173 | IEnumerable coordinates = CoordinateUtilities.GetChunkCoordinatesContainingPoint(worldPosition, chunkSize); 174 | 175 | IEnumerable expectedCoordinates = new List 176 | { 177 | new int3(1, 1, 1), 178 | new int3(0, 1, 1), 179 | new int3(1, 0, 1), 180 | new int3(0, 0, 1), 181 | new int3(1, 1, 0), 182 | new int3(0, 1, 0), 183 | new int3(1, 0, 0), 184 | new int3(0, 0, 0), 185 | }; 186 | 187 | Assert.That(coordinates, Is.EquivalentTo(expectedCoordinates)); 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Assets/VoxelTerrain/Modules/World/ProceduralWorldGenerator.cs: -------------------------------------------------------------------------------- 1 | using Eldemarkki.VoxelTerrain.Chunks; 2 | using Eldemarkki.VoxelTerrain.Utilities; 3 | using Eldemarkki.VoxelTerrain.Utilities.Intersection; 4 | using Unity.Mathematics; 5 | using UnityEngine; 6 | 7 | namespace Eldemarkki.VoxelTerrain.World 8 | { 9 | /// 10 | /// A procedurally generated world 11 | /// 12 | public class ProceduralWorldGenerator : MonoBehaviour 13 | { 14 | /// 15 | /// The voxel world that "owns" this world generator 16 | /// 17 | [SerializeField] private VoxelWorld voxelWorld; 18 | 19 | /// 20 | /// A chunk provider which provides chunks with procedurally generated data 21 | /// 22 | [SerializeField] private ProceduralChunkProvider chunkProvider; 23 | 24 | /// 25 | /// The radius of the chunks the player sees 26 | /// 27 | [SerializeField] private int renderDistance = 5; 28 | 29 | /// 30 | /// The size of the buffer around the render distance where voxel data will start to generate, but the mesh will not be generated yet 31 | /// 32 | [SerializeField] private int loadingBufferSize = 2; 33 | 34 | /// 35 | /// The viewer which the terrain is generated around 36 | /// 37 | [SerializeField] private Transform player; 38 | 39 | /// 40 | /// The coordinate of the chunk where terrain was last generated around 41 | /// 42 | private int3 _lastGenerationCoordinate; 43 | 44 | private void Start() 45 | { 46 | int3 playerCoordinate = GetPlayerCoordinate(); 47 | GenerateTerrainAroundCoordinate(playerCoordinate); 48 | } 49 | 50 | private void Update() 51 | { 52 | int3 newPlayerCoordinate = GetPlayerCoordinate(); 53 | if (!newPlayerCoordinate.Equals(_lastGenerationCoordinate)) 54 | { 55 | MoveVoxelData(_lastGenerationCoordinate, newPlayerCoordinate); 56 | 57 | var newlyFreedCoordinates = voxelWorld.ChunkStore.GetChunkCoordinatesOutsideOfRange(newPlayerCoordinate, renderDistance); 58 | 59 | int3 renderSize = new int3(renderDistance * 2 + 1); 60 | 61 | int3 oldPos = _lastGenerationCoordinate - new int3(renderDistance); 62 | BoundsInt oldCoords = new BoundsInt(oldPos.ToVectorInt(), renderSize.ToVectorInt()); 63 | 64 | int3 newPos = newPlayerCoordinate - new int3(renderDistance); 65 | BoundsInt newCoords = new BoundsInt(newPos.ToVectorInt(), renderSize.ToVectorInt()); 66 | 67 | int3[] coordinatesThatNeedChunks = CoordinateUtilities.GetCoordinatesThatNeedChunks(oldCoords, newCoords); 68 | 69 | int i = 0; 70 | foreach (int3 source in newlyFreedCoordinates) 71 | { 72 | int3 target = coordinatesThatNeedChunks[i]; 73 | 74 | // Move chunk gameobjects 75 | voxelWorld.ChunkStore.MoveChunk(source, target); 76 | 77 | // Move colors and generate new 78 | voxelWorld.VoxelColorStore.MoveChunk(source, target); 79 | 80 | chunkProvider.AddChunkToGenerationQueue(target); 81 | 82 | i++; 83 | } 84 | 85 | _lastGenerationCoordinate = newPlayerCoordinate; 86 | } 87 | } 88 | 89 | /// 90 | /// Moves all of the voxel data that existed when the player was at the coordinate to the coordinates that don't yet have data but should have when the player is at coordinate 91 | /// 92 | /// The old coordinate of the player 93 | /// The new coordinate of the player 94 | private void MoveVoxelData(int3 playerFromCoordinate, int3 playerToCoordinate) 95 | { 96 | int range = renderDistance + loadingBufferSize; 97 | int3 renderSize = new int3(range * 2 + 1); 98 | 99 | int3 oldPos = playerFromCoordinate - new int3(range); 100 | BoundsInt oldCoords = new BoundsInt(oldPos.ToVectorInt(), renderSize.ToVectorInt()); 101 | 102 | int3 newPos = playerToCoordinate - new int3(range); 103 | BoundsInt newCoords = new BoundsInt(newPos.ToVectorInt(), renderSize.ToVectorInt()); 104 | 105 | int3[] coordinatesThatNeedData = CoordinateUtilities.GetCoordinatesThatNeedChunks(oldCoords, newCoords); 106 | 107 | var newlyFreedCoordinates = voxelWorld.VoxelDataStore.GetChunkCoordinatesOutsideOfRange(playerToCoordinate, range); 108 | 109 | int i = 0; 110 | foreach (int3 freeCoordinate in newlyFreedCoordinates) 111 | { 112 | var targetCoordinate = coordinatesThatNeedData[i]; 113 | voxelWorld.VoxelDataStore.MoveChunk(freeCoordinate, targetCoordinate); 114 | i++; 115 | } 116 | } 117 | 118 | /// 119 | /// Get's the current coordinate of 120 | /// 121 | /// The coordinate of 122 | private int3 GetPlayerCoordinate() 123 | { 124 | return VectorUtilities.WorldPositionToCoordinate(player.position, voxelWorld.WorldSettings.ChunkSize); 125 | } 126 | 127 | /// 128 | /// Generates terrain around with a radius of 129 | /// 130 | /// The coordinate to generate the terrain around 131 | private void GenerateTerrainAroundCoordinate(int3 coordinate) 132 | { 133 | // Start generating voxel data for chunks with radius 'renderDistance + loadingBufferSize' 134 | int3[] preloadCoordinates = CoordinateUtilities.GetPreloadCoordinates(coordinate, renderDistance, loadingBufferSize); 135 | for (int i = 0; i < preloadCoordinates.Length; i++) 136 | { 137 | int3 loadingCoordinate = preloadCoordinates[i]; 138 | voxelWorld.VoxelDataStore.GenerateDataForChunk(loadingCoordinate); 139 | } 140 | 141 | // Generate chunks with radius 'renderDistance' 142 | int3[] chunkGenerationCoordinates = CoordinateUtilities.GetChunkGenerationCoordinates(coordinate, renderDistance); 143 | for (int i = 0; i < chunkGenerationCoordinates.Length; i++) 144 | { 145 | int3 generationCoordinate = chunkGenerationCoordinates[i]; 146 | voxelWorld.VoxelColorStore.GenerateDataForChunk(generationCoordinate); 147 | chunkProvider.EnsureChunkExistsAtCoordinate(generationCoordinate); 148 | } 149 | 150 | _lastGenerationCoordinate = coordinate; 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | --------------------------------------------------------------------------------