Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for import sample code #146

Closed
unphased opened this issue Mar 31, 2020 · 6 comments
Closed

Request for import sample code #146

unphased opened this issue Mar 31, 2020 · 6 comments

Comments

@unphased
Copy link

unphased commented Mar 31, 2020

I'm currently using .vox format writing code that I found here: https://codepen.io/quasimondo/pen/QjqZvV This has apparently also been mirrored here: https://github.com/chaojian-zhang/MagicaVoxelWriter

I took the code from the first link and hacked it into a functioning node.js script that I use with my intermediate format which is one voxel per line, with

X Y Z M

where M is the material/palette index.

I am having kind of bad luck so far. At first I thought it was working great, but then I realized that there is some inconsistent behavior where sometimes the top few z-slices of my .vox export appear to just be missing, lopped off.

I'm currently using .vox files to debug a triangle-aabb collision routine I'm coding up, so I have some screenshots here to illustrate:

image

image

I'm highly confident that my files contain the full set of voxels, but somewhere there is either a bug in this MV build or in my shoddy node script that is causing some number of z-layers to go missing.

The node script contents:

#!/usr/bin/env node

const fs = require('fs');
function VOX(X, Y, Z) {
  this.X = X;
  this.Y = Y;
  this.Z = Z;
  this.vcount = 0;
  this.voxels = [];
  this.palette = [];

  // greyscale placeholder palette
  for (let i = 256; i > -1; --i) {
    this.palette.push(0xff000000 | i | (i << 8) | (i << 16));
  }

  this.setVoxel = function(x, y, z, i) {
    i |= 0;
    x |= 0;
    y |= 0;
    z |= 0;

    if (i >= 0 && i < 256 && x >= 0 && y >= 0 && z >= 0 && x < this.X && z < this.Y && z < this.Z) {
      const key = x + "_" + y + "_" + z;
      if (i > 0) {
        if (!this.voxels[key]) this.vcount++;
        this.voxels[key] = i;
      } else {
        if (this.voxels[key]) this.vcount--;
        delete this.voxels[key];
      }
    }
  };

  this.appendString = function(data, str) {
    for (var i = 0, j = str.length; i < j; ++i) {
      data.push(str.charCodeAt(i));
    }
  };

  this.appendUInt32 = function(data, n) {
    data.push(n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff);
  };
 
  this.appendRGBA = function(data, n) {
    data.push((n >>> 16) & 0xff,(n >>> 8) & 0xff, n & 0xff, (n >>> 24) & 0xff);
  };

  this.appendVoxel = function(data, key) {
    var v = key.split("_");
    data.push(v[0], v[1], v[2], this.voxels[key]);
  };

  this.export = function(filename) {
    var data = [];
    this.appendString(data, "VOX ");
    this.appendUInt32(data, 150);
    this.appendString(data, "MAIN");
    this.appendUInt32(data, 0);
    this.appendUInt32(data, this.vcount * 4 + 0x434);

    this.appendString(data, "SIZE");
    this.appendUInt32(data, 12);
    this.appendUInt32(data, 0);
    this.appendUInt32(data, this.X);
    this.appendUInt32(data, this.Y);
    this.appendUInt32(data, this.Z);
    this.appendString(data, "XYZI");
    this.appendUInt32(data, 4 + this.vcount * 4);
    this.appendUInt32(data, 0);
    this.appendUInt32(data, this.vcount);
    for (var key in this.voxels) {
      this.appendVoxel(data, key);
    }
    this.appendString(data, "RGBA");
    this.appendUInt32(data, 0x400);
    this.appendUInt32(data, 0);
    for (var i = 0; i < 256; i++) {
        this.appendRGBA(data, this.palette[i]);
    }
    this.saveByteArray(new Uint8Array(data), filename);
    return;
  };

  this.saveByteArray = function (data, name_) {
    fs.writeFileSync(name_, data);
  };
}

// read my basic voxel format into .vox
// it is just an ascii list of xyz asserted voxels with no dimensions specified.
const read = fs.readFileSync(process.argv[2], 'utf8');
const parsed = read.replace(/\n$/g, '').split('\n').map(line => line.split(' ').map(Number));
console.log(parsed);
console.assert(parsed.every(v => v.length === 4), `not parsed.every(vox => vox.length === 4)`);
const max = [0,0,0];
parsed.map((v) => {
  for (let i = 0; i < 3; ++i) {
    if (v[i] > max[i]) {
      // console.log('accepted max, i, ii, max[i], v[i]:', i, ii, max[i], v[i]);
      max[i] = v[i];
    }
  }
});
console.log('max:', max);
const vox = new VOX(max[0] + 1, max[1] + 1, max[2] + 1);
parsed.map(v => {
  vox.setVoxel(v[0], v[1], v[2], v[3]);
});
vox.export(process.argv[2] + '.vox');

In particular I'm scratching my head over this code: this.vcount * 4 + 0x434 and I wonder if that is related.

I will also note that I have done checks where layer z=156 is missing and should be there, and I look in my output format and it is indeed present. Not only that, but the calculation for the z size in the node script also correctly sets the boundary size in MV to that value, just the voxels don't appear.

The ability to have the beautiful renders has already been invaluable in allowing me to troubleshoot voxel based algorithms, and I can only see myself using MV more and more for voxel based software going forward. It will only add to this tool's influence for developers to be able to rapidly create .vox exporters!

I would really appreciate a more thorough documentation of the file format representation. In particular it would be useful to be able to reliably import arbitrarily sized scenes, whether or not we have to manually break them down into 126^3 or whatever size models.

@unphased
Copy link
Author

Note I also found https://github.com/aiekick/MagicaVoxel_File_Writer which looks even more promising, however this code currently has missing dependencies and cannot be built.

@unphased
Copy link
Author

unphased commented Mar 31, 2020

@ephtracy Could you check if this .vox
x12.vox.zip

(corresponding to the 2nd screenshot) really has any voxels on coordinates z=59 thru z=66?

@unphased
Copy link
Author

unphased commented Apr 1, 2020

Meanwhile, I did get @aiekick’s .vox writer c++ building after he gave me the missing dependencies, so I’ll be doing tests using that to see if it has the same issue, as well as post a link to my fork of it (since the build steps are nontrivial).

thanks

@unphased
Copy link
Author

unphased commented Apr 1, 2020

I also expect things to change soon since I’ve been seeing ephtracy’s recent tweets; especially when the max model size will be jumping up to 256^3. I do consider it at least somewhat likely that newer builds would be able to load “legacy” vox files though!

@unphased
Copy link
Author

unphased commented Apr 2, 2020

I'll reopen this issue if I continue to see it with @aiekick's .vox writer. If anyone wants the code you can find it here: https://github.com/unphased/MagicaVoxel_File_Writer

It already works for me for enormous generated scenes, so I'd be surprised if it also has issues within a single 126^3 model. I think the bug comes from the janky js that I posted above.

@unphased unphased closed this as completed Apr 2, 2020
@mgerhardy
Copy link

You could check out this: https://github.com/Eisenwave/voxel-io
Or my code here: https://github.com/mgerhardy/engine/blob/master/src/modules/voxelformat/VoxFormat.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants