MagicaVoxel VOX loading
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
- The vox-format crate for the VOX loading
- Mike Judge's Mini Mike's Metro Minis for the model in the screenshot
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;
}