Home

Awesome

Ways to Render 1 Million Cubes

All the ways to efficiently render 1 Million individually coloured cubes in Unity3d (I could think of). WIP: This repository will be filled with implementations over time

Index



Concepts

Positional Data Generation

Cached (Pre-generated)

On-The-Fly

Cube Representation

Explicit (Mesh-Based)

Implicit (SDF)

Impostors (Single Quad)

Cube Grid Rendering

Procedural Meshing

Instanced Rendering

Raymarched SDF



Implementations

1. Instanced Rendering

1.1 Using Plain Old Mesh Renderers (POMR) & MaterialPropertyBlock

Description

Each cube is Instantiated as a separate GameObject with Transform, MeshFilter & MeshRenderer components attached to it. The MeshFilters of all the cubes point to a single (shared) Mesh asset. The MeshRenderers of all the cubes point to a single (shared) Material asset, which supports GPU Instancing. Each cube is individually coloured via a MaterialPropertyBlock

Pros
Cons

1.2 Using DrawMeshInstanced & MaterialPropertyBlock

Description

Using a single Mesh Instance, a single Material Instance and a Matrix4x4 array containing the transformation of each instance. The instanced drawing is trigerred by calling the Graphics.DrawMeshInstanced on every frame.

Pros
Cons

1.3 Using DrawMeshInstancedIndirect & Custom Shaders

Description

Using a single Mesh Instance, a single Material Instance and a custom Shader accepting arbitrary Buffers (like positions, rotations, colors etc.) and triggering the instanced drawing by calling the Graphics.DrawMeshInstancedIndirect on every frame. The shader is written to take care of the translation/scale/rotation of each instance.

Pros
Cons

1.4 Using DrawMeshInstancedIndirect with Custom GPU Z-Sorting

Description

Using a single Mesh Instance, a single Material Instance, a custom Shader accepting arbitrary Buffers (like positions, rotations, colors etc.) and a Compute Shader that sorts the indices of the instances in parallel(Bitonic Merge Sort), based on their distance to the Camera. The instanced drawing is trigerred by calling the Graphics.DrawMeshInstancedIndirect on every frame, after the execution of the sorting. The shader is written to take care of the translation/scale/rotation of each instance, and draw the instances in the correct order, with the ones further away from the camera drawn first.

Pros
Cons

1.5 Clustering Individual Instances into 3D Tiles

Recipe

Instead of using 1 cube per instance, generate a Mesh that groups together multiple cubes, and use that as each instance's mesh. The more cubes each instance represents, the less instances need to be drawn. Conversely, the more cubes each instance represents, the larger the memory footprint. Edge case is when the mesh contains all of the cubes, therefore is rendered as one instance, storing all of its vertices in memory. See 2.1

Pros
Cons


2. Procedural Meshing

2.1 Generating the Cubes as a single Mesh

Description

A single mesh containing the Vertices, Indices, Normals and Colors of all the cubes is generated procedurally, and passed to the MeshFilter of a GameObject. The buffers (vertex,index,normal,color etc) of the Mesh are generated either in the CPU using the Job System or in the GPU using a ComputeShader.

Pros
Cons

2.2 Generating the Cubes using a Geometry Shader & DrawProcedural

Description
Pros
Cons

2.3 "Stamping" the Cubes into a single Mesh

Description
Pros
Cons


3. Raymarching

3.1 Using a repeating Cube Signed Distance Field

Description
Pros
Cons

3.2 Using a Volumetric RenderTexture

Description
Pros
Cons


4. Particles

4.1 Using the Shuriken (CPU) Particle System

Description
Pros
Cons

4.2 Using the Visual Effects Graph (GPU)

Recipe

1. Generate a signed floating-point (R32G32B32) Texture, which encoded the positions of the cubes' centers as colors. (XYZ => RGB).</br> 2. Spawn particles once, and use Set Position From Map at their birth using the Texture.</br> 3. Use a Mesh Output node, and choose the appropriate Cube Mesh.

Pros
Cons


5. ECS & Hybrid Renderer