dust-engine / dot_vox

Rust parser for MagicaVoxel .vox files.
MIT License
51 stars 20 forks source link

Coordinate system clarification for models and transforms #47

Closed davids91 closed 1 month ago

davids91 commented 1 month ago

Hey! Thanks for the awesome library! I'd like to support it with a voxel raytracing engine I'm writing.

I started to implement parsing the files based on the library here, but I kind of got stuck on the used coordinate system, as I expected it to be Y-Up, but after displaying a model, I assume it is Z-up, from the teapot model I parsed:

in the editor: image

In the engine: image

Is this in alignment with the implementation? What coordinate system is being used within the format? Z-up/Y-up - Left handed, right handed?

It would be nice to have this documented.

Neo-Zhixing commented 1 month ago

Hello David,

Thanks for bringing this up! dot-vox is simply a parser for the .vox format, so the coordinate system is just whatever MagicaVoxel uses. If I remembered correctly, MagicaVoxel uses z-up, left-handed. It would be great if you can verify and open a PR to add this into the docs.

This is how I convert this into the right-handed, y-up coordinate system that bevy / wgpu uses:

https://github.com/dust-engine/dust/blob/fa635f952e51c571b4b0fd49a3be3ec159d0b24f/crates/vox/src/loader.rs#L248-L253

Thanks again!

davids91 commented 1 month ago

With the following implementation:

enum CoordinateSystemType {
    LZUP, // Left handed Z Up
    LYUP, // Left handed Y Up
    RZUP, // Right handed Z Up
    RYUP, // Right handed Y Up
}

fn convert_coordinate(
    c: Vec3,
    src_type: CoordinateSystemType,
    dst_type: CoordinateSystemType,
) -> Vec3 {
    match (src_type, dst_type) {
        (CoordinateSystemType::LZUP, CoordinateSystemType::LZUP) => c,
        (CoordinateSystemType::LYUP, CoordinateSystemType::LYUP) => c,
        (CoordinateSystemType::RZUP, CoordinateSystemType::RZUP) => c,
        (CoordinateSystemType::RYUP, CoordinateSystemType::RYUP) => c,

        (CoordinateSystemType::LYUP, CoordinateSystemType::RYUP)
        | (CoordinateSystemType::RYUP, CoordinateSystemType::LYUP) => Vec3::new(c.x, c.y, -c.z),

        (CoordinateSystemType::LZUP, CoordinateSystemType::RZUP)
        | (CoordinateSystemType::RZUP, CoordinateSystemType::LZUP) => Vec3::new(c.x, -c.y, c.z),

        (CoordinateSystemType::LYUP, CoordinateSystemType::LZUP)
        | (CoordinateSystemType::RYUP, CoordinateSystemType::RZUP) => Vec3::new(c.x, -c.z, c.y),
        (CoordinateSystemType::LZUP, CoordinateSystemType::LYUP)
        | (CoordinateSystemType::RZUP, CoordinateSystemType::RYUP) => Vec3::new(c.x, c.z, -c.y),

        (CoordinateSystemType::LYUP, CoordinateSystemType::RZUP)
        | (CoordinateSystemType::RZUP, CoordinateSystemType::LYUP)
        | (CoordinateSystemType::RYUP, CoordinateSystemType::LZUP)
        | (CoordinateSystemType::LZUP, CoordinateSystemType::RYUP) => Vec3::new(c.x, c.z, c.y),
    }
}

...

for voxel in &model.voxels {
    let voxel_position = convert_coordinate(
        Vec3::new(voxel.x, voxel.y, voxel.z),
        CoordinateSystemType::RZUP,
        CoordinateSystemType::LYUP,
    );
    octree.insert(
            &voxel_position,
            T::new(vox_tree.palette[voxel.i as usize].into(), 0),
        )
        .ok();
}

I managed to make the teapot look as expected! The indexing verifies to my experience that the models are in a Right handed Z up coordinate system.

I can't seem to wrap my head around the transform positions though, do you have any pointers for them?

davids91 commented 1 month ago

I've created a file with 3 voxel models, representing Left handed Y up ( what my framework use ) so it can be compared with what the editor actually uses ( It is Right handed Z up ) image