jpaver / opengametools

A set of open c++ game development tools that are lightweight, easy-to-integrate and free to use. Currently hosting a magicavoxel .vox full scene loader.
MIT License
373 stars 35 forks source link

ogt_vox: looks like the transforms are not yet correctly handled #48

Closed mgerhardy closed 1 year ago

mgerhardy commented 1 year ago

https://github.com/Eisenwave/voxel-io/blob/master/src/format/vox.cpp line 248ff and 353ff as well as the divFloor implementation might be interesting here.

There is a vox test file attached to a ticket in vengi - contributed by the voxelmax author: https://github.com/mgerhardy/vengi/issues/275

jpaver commented 1 year ago

Oh interesting, I wasn't aware that magicavoxel can support transform flips. I'll look into that. Thanks!

jpaver commented 1 year ago

Hey @mgerhardy - so I'm able to import that vox file into my own engine and it looks identical to what is visible in magicavoxel when I open it there. Is there anything particular about the way you're importing it in your vengi tools?

mgerhardy commented 1 year ago

hm. I only do the coordinate conversion with this matrix

glm::mat4 {
  -1.0f, 0.0f, 0.0f, 0.0f, 
   0.0f, 0.0f, 1.0f, 0.0f, 
   0.0f, 1.0f, 0.0f, 0.0f, 
   0.0f, 0.0f, 0.0f, 1.0f
};

which is basically this

glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f));

and here is my per voxel transform:

static inline glm::vec4 calcTransform(const glm::mat4x4 &mat, const glm::ivec3 &pos, const glm::vec4 &pivot) {
  return glm::floor(mat * (glm::vec4((float)pos.x + 0.5f, (float)pos.y + 0.5f, (float)pos.z + 0.5f, 1.0f) - pivot));
}

pivot is this:

glm::vec4 pivot((float)(int)(ogtModel->size_x / 2), (float)(int)(ogtModel->size_y / 2), (float)(int)(ogtModel->size_z / 2), 0.0f);

and the last step is basically this

for (uint32_t k = 0; k < ogtModel->size_z; ++k) {
  for (uint32_t j = 0; j < ogtModel->size_y; ++j) {
    for (uint32_t i = 0; i < ogtModel->size_x; ++i, ++ogtVoxel) {
      if (ogtVoxel[0] == 0) {
        continue;
      }
      const voxel::Voxel voxel = voxel::createVoxel(palette, ogtVoxel[0] - 1);
      const glm::ivec3 &pos = calcTransform(ogtMat, glm::ivec3(i, j, k), pivot);
      const glm::ivec3 &poszUp = calcTransform(zUpMat, pos, glm::ivec4(0));
      const glm::ivec3 &regionPos = poszUp - shift;
      v->setVoxel(regionPos, voxel);
    }
  }
}

there I iterate over all voxels and do the transform - the first for the ogt_vox transform matrix and the second for the coordinate system change.

I wonder if you are doing the transformation on a per-voxel basis - or if you just load the model and apply the transformation matrix to the vertices? Asking because I move the rotated volume back to 0,0,0 (that's the strange shift value in the for loop above) - but I would rather prefer to apply the transforms only to the scene graph nodes - and thus the vertices.

mgerhardy commented 1 year ago

this is not an issue of ogt_vox - but an issue on my side - sorry for the noise.

i've now compiled vox2obj and can see that ogt_vox handles everything correctly.