Closed m4b closed 2 years ago
hi..... I've just come across the library and i need this, is anyone working on a PR to do it or should I do it myself?
To the best of my knowledge its not being worked on at the moment - PRs are more than welcome.
alright, thank you
Okay, I'm reading in the scene graph and layer chunks now over at my fork. I'm not yet entering this information into the DotVoxData
because I'm not 100% sure about the best format for a few reasons:
One last thing: I've had to put #![allow(missing_docs)]
at the top of scene.rs due to all the pub parse macros generating "requires documentation" errors when I try to compile them. I have no idea why. In model.rs
, macros are defined the exact same way and there is no error. I would preferably like to not include this in the final PR but I am not too familliar with this part of Rust besides knowing that, because of how doc comments work, you can't put a documentation comment on a function declared inside a macro from outside it.
Edit: just ran cargo fmt
, will push soon.
Another problem I have is that when I read in the attributes Dict
for a transform node, which is supposed to contain "_t" and "_r", the respective translation and rotation, my debugger tells me that it contains no keys at all. I am not sure why this is.
Edit: Oops! Those are in frame attributes. However, the frame Dict
s contain no data either.
Another problem I have is that when I read in the attributes Dict for a transform node, which is supposed to contain "_t" and "_r", [...]
@Sixmorphugus
Have you looked at the tracker of the voxel-model
repo? Specifically this one?
That thread mentions a (still open) PR that may help explain things.
I would just file issues with each of your questions in that tracker.
Another problem I have is that when I read in the attributes Dict for a transform node, which is supposed to contain "_t" and "_r", [...]
@Sixmorphugus Have you looked at the tracker of the
voxel-model
repo? Specifically this one? That thread mentions a (still open) PR that may help explain things.I would just file issues with each of your questions in that tracker.
Ah, that's a good idea. Thanks.
Good news! I've imported and rendered out a full scene built in MagicaVoxel in my game with my fork of dot_vox
.
This means the work for reading the scene graph node chunks is basically all done, however I do want to add some general utility functions in another file for reading the transform node frame locations as the Dict they come in by default is difficult to comprehend and rather bad to work with. I'm also going to add some tests and then I'll make a PR.
@Sixmorphugus Your fork looks good.
Any chance for some example code that uses these new Scene*
types?
@Sixmorphugus Your fork looks good.
Any chance for some example code that uses these new
Scene*
types?
Hi, I've been quite busy recently but I can show the function I made in my bevy_vox changes to read scene graphs:
/// Recursive scene reader function
fn read_scene_node(scene: &Vec<SceneNode>, model_handles: &Vec<Handle<Mesh>>, current_node: usize, mut world: &mut World, cumulative_position: Vec3, cumulative_rotation: Quat) {
match &scene[current_node] {
SceneNode::Transform {attributes, frames, child} => {
// For now we care only for the content of the first frame.
let mut position = Vec3::default();
let mut rotation = Quat::default();
if frames.len() == 1 {
if let Some(value) = frames[0].get("_t") {
let values : Vec<&str> = value.split(" ").collect();
if values.len() == 3 {
position = Vec3::new(values[0].parse::<f32>().unwrap(), values[2].parse::<f32>().unwrap(), values[1].parse::<f32>().unwrap());
}
}
if let Some(value) = frames[0].get("_r") {
let byte_rotation = value.parse::<u8>().unwrap();
// .vox stores a row-major rotation in the bits of a byte.
//
// for example :
// R =
// 0 1 0
// 0 0 -1
// -1 0 0
// ==>
// unsigned char _r = (1 << 0) | (2 << 2) | (0 << 4) | (1 << 5) | (1 << 6)
//
// bit | value
// 0-1 : 1 : index of the non-zero entry in the first row
// 2-3 : 2 : index of the non-zero entry in the second row
// 4 : 0 : the sign in the first row (0 : positive; 1 : negative)
// 5 : 1 : the sign in the second row (0 : positive; 1 : negative)
// 6 : 1 : the sign in the third row (0 : positive; 1 : negative)
// First two indices
let index_nz1 = (byte_rotation & 0b11) as usize;
let index_nz2 = ((byte_rotation & 0b1100) >> 2) as usize;
// You get the third index out via a process of elimination here. It's the one that wasn't used for the other rows.
let possible_thirds = [
index_nz1 == 0 || index_nz2 == 0,
index_nz1 == 1 || index_nz2 == 1,
index_nz1 == 2 || index_nz2 == 2,
];
let mut index_nz3 = 0;
for i in 0..possible_thirds.len()
{
if possible_thirds[i] == false
{
index_nz3 = i;
}
}
// Values of all three columns (1 or 0)
let val_1 = if (byte_rotation & 0b1_0000) >> 4 == 1 { -1. } else { 1. };
let val_2 = if (byte_rotation & 0b10_0000) >> 5 == 1{ -1. } else { 1. };
let val_3 = if (byte_rotation & 0b100_0000) >> 6 == 1 { -1. } else { 1. };
// Columns as read from file
let mut initial_cols: [[f32; 3]; 3] = [
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.],
];
initial_cols[0][index_nz1] = val_1;
initial_cols[1][index_nz2] = val_2;
initial_cols[2][index_nz3] = val_3;
let initial_matrix = Mat3::from_cols_array_2d(&initial_cols);
// Convert!
/*
let mut cols : [[f32; 3]; 3] = [
[ initial_cols[0][0], 0., initial_cols[1][0]],
[ 0., 1., 0.], // this is ALWAYS this value
[ initial_cols[0][1], 0., initial_cols[1][1]],
];
// Make a Mat3
let matrix = Mat3::from_cols_array_2d(&cols);
*/
// We need to rotate the initial matrix by this to make it actually correct in bevy.
let magicavoxel_identity = Mat3::from_cols_array_2d(&[
[-1., 0., 0.],
[ 0., 0., 1.],
[ 0., 1., 0.],
]);
let matrix = magicavoxel_identity.transpose().mul_mat3(&initial_matrix).mul_mat3(&magicavoxel_identity);
// Convert the matrix rotation to a Quat
rotation = Quat::from_rotation_mat3(&matrix);
}
} else { panic!("Non-1 number of frames in .vox transform scene node ({})", frames.len()) }
// Update the cululative translation and rotation
let cumulative_position = cumulative_position + position;
let cumulative_rotation = rotation; //cumulative_rotation.mul_quat(rotation);
// Parse the child node
read_scene_node(scene, model_handles, *child as usize, world, cumulative_position, cumulative_rotation);
},
SceneNode::Group {attributes, children} => {
// In comparrison to transforms (dear god) this one is pretty straightforward.
for i in children {
read_scene_node(scene, model_handles, *i as usize, world, cumulative_position, cumulative_rotation);
}
},
SceneNode::Shape {attributes, models} => {
// For now we only care about the first model.
if models.len() == 1 {
// Spawn a voxel model in the world with the correct mesh
world
.spawn()
.insert_bundle(MarlaMeshBundle {
mesh: model_handles[models[0].model_id as usize].clone(),
transform: Transform {
translation: cumulative_position,
rotation: cumulative_rotation,
scale: Vec3::ONE,
},
..Default::default()
});
} else { panic!("Non-1 number of models in .vox shape scene node ({})", models.len()) }
},
}
}
I'm not sure when I will have time to resume work here, so if anyone wants to take what I have and continue on please feel free.
@Sixmorphugus I have a small comment about the example code that you showed here:
// You get the third index out via a process of elimination here. It's the one that wasn't used for the other rows.
Some observations that we can make here:
index_nz1 != index_nz2
index_nzx <= 2
Therefore, we can prove that index_nz1 + index_nz2 + index_nz3 = 3
.
So, maybe you can simply write index_nz3 = 3 - index_nz1 - index_nz2
in your SceneNode::Transform
case.
Also @Sixmorphugus your branch looks good. Do you wanna open a PR so that we can do some reviews?
Bump! @Neo-Zhixing if @Sixmorphugus doesn't have time to create a PR, someone else could do it.
I could just fork his fork and open a PR if this about process. I.e. the code is there to review since half a year now. Just saying. 😉
@virtualritz PR added!
Nice!!! :)
PR merged.
It looks like the only remaining major feature left is to extract the scene graph information:
which is an extension https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox-extension.txt
This doesn't seem like a whole lot of work since much of the groundwork is already laid, but i'm not really sure?