Skip to content

About

Voxel world engine built from scratch in Unity. Chunked terrain from fBm Perlin noise, cave carving with noise and worm algorithms, face-culled mesh generation, chunk streaming around the player, and block breaking and placing. ISEL coursework.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

55 Commits

Folders and files

Repository files navigation

Unity Voxel Engine

Unity C# URP

A Minecraft-style voxel world built from scratch in Unity. Features include procedurally generated terrain and caves, chunk streaming around the player, mesh generation and block breaking and placing in first person.

Academic project - Interaction in Virtual Environments (Interação em Ambientes Virtuais), BSc in Computer Science and Multimedia Engineering (LEIM), ISEL.


World Generation

Terrain. A surface height per column comes from fractal Brownian motion, consiting of $4$ octaves of Perlin noise summed with decreasing amplitude and increasing frequency, normalized to $[0, 1]$ (NoiseUtils.FBm). A second, volumetric pass samples a pseudo-3D Perlin field (NoiseUtils.Perlin3D) and compares it against a density threshold, which lets the surface produce overhangs rather than a pure heightmap.

Caves. Two mechanisms, applied after the terrain exists. GenerateCaves carves any block whose 3D noise value crosses a threshold, producing scattered pockets. GenerateWorms walks a path through the volume, hollowing a radius around each step, producing connected tunnels. Cave walls are then re-textured so exposed stone reads correctly, and dirt with air above it becomes grass.

Water. Fills to sea level, and is meshed separately from solid blocks.

Meshing

Each chunk constitutes a single mesh. Chunk.DrawChunk walks the $16×16×64$ block array and emits a face only when the neighbouring block is not solid. Water does a second pass, emitting faces only against air. Vertices, triangles and UVs accumulate into shared lists.

Face UVs are looked up per block type from a texture atlas (Block.GetUVs), so the whole chunk renders in a single draw call with one material.

Chunk Lifecycle

WorldManager keeps two dictionaries keyed by chunk coordinate: activeChunks and sleepingChunks.

Update compares the player's chunk coordinate against lastPlayerChunk and does nothing if they match.

On a boundary crossing it stops the running build coroutine, calls RemoveDistantChunks, and starts BuildChunks on the new set. Generation runs as a coroutine, so chunks are built across several frames instead of in one hitch; cancelling it stops a fast-moving player from queueing work for chunks already out of range.

RemoveDistantChunks applies two thresholds. Past render distance, a chunk has its MeshRenderer disabled and its mesh cleared, then moves to sleepingChunks — the GameObject and its collider remain, so terrain that is no longer drawn is still solid. Past renderDistance * 3, the object is destroyed.

UpdateChunkVisibility runs every frame: it builds an AABB per active chunk, tests it against the camera frustum with GeometryUtility.TestPlanesAABB, and sets MeshRenderer.enabled from the result. Chunks behind the camera stay loaded but are not submitted for rendering.

Interaction

A raycast from the camera highlights the targeted block. Breaking and placing modify the chunk's block array and trigger a remesh; when the edit sits on a chunk border, the neighbouring chunk is redrawn too, so the seam updates. A hotbar UI tracks the selected block type.

Configuration

Config.cs holds the world constants — chunk size 16, chunk height 64, render distance 3, world height 256, sea level 12. Per-chunk generation parameters (noise scale, octaves, density threshold, cave scale, worm count) are serialized fields on Chunk, tunable from the Inspector without recompiling.

Repository structure

Assets/
├── Scripts/
│   ├── Aula1/GenerateCubes.cs        # first experiments (1 GameObject per cube)
│   ├── Aula2/Block.cs                # block type, face vertices, atlas UVs<>
│   ├── Aula2/Chunk.cs                # generation, texturing, meshing, collision
│   ├── Aula3/NoiseUtils.cs           # fBm and pseudo-3D Perlin
│   ├── Aula3/WorldManager.cs         # chunk streaming, culling, lifecycle
│   ├── Aula4/CaveGenerator.cs        # noise carving and worm tunnels
│   ├── Aula5/BlockInteraction.cs     # raycast, break, place, neighbour redraw
│   ├── Config.cs                     # world constants
│   └── HotbarUI.cs, HotbarSlot.cs    # block selection UI
├── Materials/, Shaders/, Sprites/    # block atlas and rendering
├── Prefabs/, Scenes/, Settings/
└── StarterAssets/                    # Unity's first-person controller

The AulaN folders follow the course's lesson progression.

How to Play?

Open the project in Unity 6000.3 (URP) and play the main scene in Assets/Scenes. WASD to move, mouse to look, left click to break, right click to place, scroll to change the selected block.

Authors

Group project for Interaction in Virtual Environments (Interação em Ambientes Virtuais), BSc in Computer Science and Multimedia Engineering (LEIM), ISEL - DEI, 2025/26. Supervised by Prof. Arnaldo Abrantes.

About

Voxel world engine built from scratch in Unity. Chunked terrain from fBm Perlin noise, cave carving with noise and worm algorithms, face-culled mesh generation, chunk streaming around the player, and block breaking and placing. ISEL coursework.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages