← All work

IMPLEMENTATION NOTES / C++ / Vulkan

Vulkan Renderer (MoltenVK)

A macOS Vulkan/MoltenVK renderer for a 64×64 sine-wave terrain mesh. Implements indexed drawing, matrix transforms, depth testing, and swapchain recreation.

C++VulkanGLFWGLSLCMakeMoltenVK

IMPLEMENTATION / EQUATIONS & SOURCE

Follow the inputs through the code.

Read each section as purpose → equation → actual source. Snippets are excerpts of the working implementation, not standalone programs. Follow the source link for surrounding context.

01 / A 64×64 sine-wave height field

This renderer uses a product of sine waves, not Perlin noise. Grid spacing is 0.15, amplitude 0.6, and frequency 0.35. Heights determine vertex color. This predictable mesh makes the Vulkan rendering path easier to inspect.

Equation
xworld = 0.15x − 63·0.15/2
zworld = 0.15z − 63·0.15/2
y = 0.6 sin(0.35xworld) sin(0.35zworld)
src/main.cpp : 99COMMIT b0586c7
            float worldX = x * kGridScale - half;
            float worldZ = z * kGridScale - half;
            float height = std::sin(worldX * kHeightFrequency) *
                           std::sin(worldZ * kHeightFrequency) * kHeightScale;
Read this source on GitHub ↗

02 / Split each cell into two triangles

Use vertex index z·64+x and gather the four cell corners i0…i3. Emit triangles (i0,i2,i1) and (i1,i2,i3), sharing vertices through an index buffer.

Equation
V = n², T = 2(n−1)², I = 6(n−1)²
src/main.cpp : 123COMMIT b0586c7
            uint32_t i0 = static_cast<uint32_t>(z * kGridSize + x);
            uint32_t i1 = static_cast<uint32_t>(z * kGridSize + x + 1);
            uint32_t i2 = static_cast<uint32_t>((z + 1) * kGridSize + x);
            uint32_t i3 = static_cast<uint32_t>((z + 1) * kGridSize + x + 1);

            indices.push_back(i0);
            indices.push_back(i2);
            indices.push_back(i1);
            indices.push_back(i1);
            indices.push_back(i2);
            indices.push_back(i3);
Read this source on GitHub ↗

03 / Vertex shader and coordinate transforms

Pass a CPU-built transform through the uniform buffer at binding 0. Read position at location 0 and color at location 1, then pass color onward to the fragment shader. math_utils.cpp flips the perspective matrix’s Y sign for Vulkan.

Equation
pclip = transform · (x,y,z,1)ᵀ
pNDC = (pclip.x,pclip.y,pclip.z) / pclip.w

The second line is the perspective divide after gl_Position is written, not an explicit division in this shader.

shaders/triangle.vert : 1COMMIT b0586c7
#version 450

layout(binding = 0) uniform UniformBufferObject {
    mat4 transform;
} ubo;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;

layout(location = 0) out vec3 vColor;

void main() {
    gl_Position = ubo.transform * vec4(inPosition, 1.0);
    vColor = inColor;
}
Read this source on GitHub ↗

SOURCE / SCOPE

Scope of the notes.

Each source excerpt comes from the linked fixed commit. Equations describe those operations. Apart from worked examples, no new performance or quality measurements are claimed. Refer to the repository for build steps and dependencies.

Open repository ↗