Skip to main content

3 posts tagged with "wgsl"

View All Tags

Render passes

· One min read

What's exciting about the below image?

It is rendering lines.

alt text

Mostly internal work to refactor code and conceptual work to understand the various components of the WGPU architecture, but the engine code now supports rendering lines. This involved setting up a separate shader, render pass, line geometry buffer, and a few other things.

Not too exciting, but progress!

Also: an engine debug view

Also in the not-that-exciting category, I added a debug web view. The engine starts a small HTTP server that serves up basic data about the engine state. There's not much there yet!

alt text

MagicaVoxel VOX loading

· 3 min read

Added support for loading MagicaVoxel VOX models. This relies almost entirely on the work of others as the model below was created by Mike Judge and the VOX loading code comes from jgraef's vox-format crate. The only real addition to the Snowfall code was to add a YAML descriptor for VOX models and to write a quick translation from the vox-format format to the existing internal voxel format.

From the todo list...

  • Support loading MagicaVoxel VOX files
  • Display attribution info as the models are loaded
  • Add voxel colors rather than just the normal-based shader

alt text

Credits

World coordinate based voxel shading/darkening

Note that the shader is randomly darkening each voxel a bit based on it's world coordinate to make for an (intentionally) less uniformly colored look to the final render.

Note that the array look-ups need to be expanded out as if-else branches as WGSL rejects attempts to index using a non-const value (i.e. return shade_x[xi] + shade_y[yi] + shade_z[zi]; does not compile).

const shade_x = array<f32, 7>(0.05, 0.18, 0.10, 0.96, 0.46, 0.75, 0.55);
const shade_y = array<f32, 7>(0.52, 0.52, 0.34, 0.03, 0.38, 0.01, 0.66);
const shade_z = array<f32, 7>(0.33, 0.60, 0.80, 0.30, 0.16, 0.85, 0.13);

// Shade the color based on the world coordinate grid position
//
// This gives a subtle variation to each voxel based on world position
// so that there's less uniformity to everything. Subjectively produces
// a better looking result.
//
// Returns a [0-1] value.
//
fn shade_world_coord(world_coord : vec3<f32>) -> f32 {
var grid_wc = vec3<i32>(floor(world_coord));
var ix = (1 * grid_wc.x + 13 * grid_wc.y + 31 * grid_wc.z) % 7;
var iy = (1 * grid_wc.y + 17 * grid_wc.z + 43 * grid_wc.x) % 7;
var iz = (1 * grid_wc.z + 37 * grid_wc.x + 3 * grid_wc.y) % 7;


// The shade arrays are [0-1] in range, so shade is [0-3]
var shade = 0.0;

if ix == 0 {
shade += shade_x[0];
} else if ix == 1 {
shade += shade_x[1];
} else if ix == 2 {
shade += shade_x[2];
} else if ix == 3 {
shade += shade_x[3];
} else if ix == 4 {
shade += shade_x[4];
} else if ix == 5 {
shade += shade_x[5];
} else if ix == 6 {
shade += shade_x[6];
}

if iy == 0 {
shade += shade_y[0];
} else if iy == 1 {
shade += shade_y[1];
} else if iy == 2 {
shade += shade_y[2];
} else if iy == 3 {
shade += shade_y[3];
} else if iy == 4 {
shade += shade_y[4];
} else if iy == 5 {
shade += shade_y[5];
} else if iy == 6 {
shade += shade_y[6];
}

if iz == 0 {
shade += shade_z[0];
} else if iz == 1 {
shade += shade_z[1];
} else if iz == 2 {
shade += shade_z[2];
} else if iz == 3 {
shade += shade_z[3];
} else if iz == 4 {
shade += shade_z[4];
} else if iz == 5 {
shade += shade_z[5];
} else if iz == 6 {
shade += shade_z[6];
}

return shade/3.0;
}

Progress

· 2 min read

Shading placeholder

Added shading based on world coordinate positions. This was mostly a test of adding new uniforms and vertex shader outputs to the shader program.

alt text

Voxels

Added a voxel model. Very inefficient at this point, but "correct."

alt text

Bug! 🐛

Tried increasing the resolution and found bugs :)

alt text

Guess: missing array data?

Manually counting the input data matches the generated positions array and checking against the runtime data...

  • 4416 voxels * 6 faces/voxel * 8 positions/face => 105984 positiions
  • 4416 voxels * 6 faces/voxel * 6 indices/face => 158976 indices

...seems correct.

Guess: too many draw calls?

Seems impossible as this is a single mesh.

Investigation: is it always the same voxels that are missing?

Flipping the order of the voxels during generation changes the missing voxels. Not sure what to conclude from this yet.

alt text

Drawing just the Z+ face on the voxels seems to work correctly. The same seems to be true when rendering any one of the six faces.

alt text

...but if as soon as 3 faces are rendered together, voxels seem to be lost.

Guess: too many indicies

Yup. The code is using u16 which has a max representable value of 256*256 = 65,536. There are 158,976 indices.

Changing to a u32 index buffer addresses the problem.

alt text

Resolution

Bumping the render code to always use u32 seems fine for this stage of development. Using the larger buffer size affords more flexibility, which is a higher priority right now than optimization for memory or performance.

Voxel chunking and optimizing away invisible faces need to be done regardless. After that is done, it should be easier to move back to a u16 index buffer.

A larger model

With the bug fixed, here's a sine + cosine generated voxel heightmap of 128x128x32 resolution.

alt text