RichysHub / MagicaVoxel-VOX-importer

Blender import script for MagicaVoxel .vox format as cube primitives.
MIT License
225 stars 56 forks source link

Join voxels #14

Closed wizardgsz closed 4 years ago

wizardgsz commented 4 years ago

To join voxels creating a single object in Blender.

Just a question: where is the "origin" of the merged object? I am using the first voxel position but it could not be the right choice 😈

The target object will have all materials: should we name them differently? "Human readable" naming convention?

RichysHub commented 4 years ago

Okay, just gave this a quick test, looks good to me, and by the time you see this, I should have already completed the pull.

Model Origin: I suppose one could argue any number of different options. I think first voxel is about as useful as any other convention.

Removing duplicates: Might be some value in using Merge by distance

Material Names: I like the idea of naming materials in a more descriptive manner, and would be interested to know what thoughts you have in this regard. Have made issue #15 for this purpose.

wizardgsz commented 4 years ago

Model Origin: for the "future" scene-graph structure used in latest file format, I think we should set the "pivot" to che center of the "bounding box" info read in SIZEchunk. SIZE contains # of voxels in x, y, z indeed (we have voxel_size and voxel_spacing to use).

If we have to roto-translate models it makes sense to set the right "pivot".

Material / Model Names: currently I have no proposal but we can talk about it in #15 .

ps. I thinks MagicaVoxels uses only 90 degrees rotations (at least until today)

RichysHub commented 4 years ago

Moving origin based on the SIZE seems like a very smart choice, and basically free for us to do. ✔

I agree that the rotations are 90 limited, and I think have to be within the current byte they are encoded in.

(c) ROTATION type

store 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)

If this were to ever be extended further, I think the assigned number of bytes would change, so it would be an incompatible change we'd have to handle anyway.

wizardgsz commented 4 years ago

I added a code snippet, feel free to use it as you prefer:

# Set object pivot using cursor location and model size
saved_location = bpy.context.scene.cursor.location.copy()
bpy.context.scene.cursor.location = (x * voxel_spacing / 2.0, y * voxel_spacing / 2.0, z * voxel_spacing / 2.0)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
bpy.context.scene.cursor.location = saved_location

Remember to comment out the SIZE chunk ofc 😄

# model size
x, y, z = struct.unpack('<3i', vox.read(12))
#vox.read(12)