RichysHub / MagicaVoxel-VOX-importer

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

Join objects (and/or boolean union) by material #13

Open wizardgsz opened 5 years ago

wizardgsz commented 5 years ago

How to reduce number of vertices/faces for "high voxels" models? How to speed-up objects roto-translations for new scene-graph structure?

RichysHub commented 5 years ago

I'm not 100% sure I understand the behaviour you're suggesting.

I have not looked into it, but I believe one way that the import may be sped up would be the use of instancing (previously known as dupli-faces). That would result in only a single real cube in the scene, with all the others being replaced by single quad faces.

I believe using instancing for rigid body collision modelling is already a common practice, though I'm not sure how material information would be handled. Perhaps it would be that each material would have its own master cube.

wizardgsz commented 5 years ago

My reflection starts from the simple use of VOX models in Blender: move, rotate, or anything else is so slow, but I have a very slow hardware.

For example, after importing a file with 1000 cubes or more, try moving them or simply deleting them all: having to manage 1000 cubes, Blender is really slow. Try doing the same with "joined" objects (CTRL+J) and everything will be instantaneous!

In practise, I have compable times to:

A subsequent reflection is: having to support scene-graph (and therefore objects hierarchically linked), how will Blender work using 1000 roto-translations rather than a single one (the "joined" object)?

Obviously it depends on how you'll use imported data:

Finally, but I understand that it is well beyond the context of the importer:

Working with tens of thousands of voxels, such sort of "optimization" can make the difference. But only for "static" objects of course.

That is, for the 4854 voxels sample:

I preferred to edit the post with a real example :-)

RichysHub commented 5 years ago

Perhaps my views are best explained if I give a little background to this repository, and why it was made.

October of 2017 I was playing around with making voxel models, working on a reasonably small scale, something like 28³. At that time I was using VoxelShop.

VoxelShop supported exporting the voxel models to several combined formats, such as .obj, but I wanted to have access to all the voxels for physics simulations (moreso just something easy that looks neat)

That led me down the path of finding VoxelShop's ability to export to .vox, and therefore to MagicaVoxel. As this format was openly documented, it served as a good interface format for me to get the data I wanted into Blender.

From there I built upon what I had done, to automate the material creation and so forth.

I do seem to remember the process of using Blender on these models running a lot smoother, pre 2.80, this might be a case where the new engine suffers more than previous version. It might also be me misremembering, or perhaps I did some joining and splitting workflow. I don't happen to have 2.7x installed to test.

Hopefully that puts into perspective why I chose to maintain all the original geometry, so far. Now, going forward, is that the only use case for a vox importer? Certainly not, importing directly rather than having to go via .obj or something is certainly appealing.

Having an option to join everything down certainly sounds like a good thing to pursue, and if that's something you'd want to work on, I will happily help incorporate it into the repo.

Furthermore, removing internal geometry entirely sounds quite difficult to achieve, but the same applies. I am happy to make this a multi-purpose importer able to handle everything.

wizardgsz commented 5 years ago

The fastest option to join objects should be fine (default=False, do not merge voxels); moreover, I do not know how to remove duplicates data using Python right now 😄

I will work on it later... thanks.

def join_selected(context):

    active = context.active_object
    selection = context.selected_objects
    selected = set(selection).difference(set([active]))

    if not (active and selected):
        return

    print("Active object:", active.name)
    print("Selected objects:", len(selected), len(selection))

    bpy.ops.object.join()

Having:

wizardgsz commented 5 years ago

https://github.com/RichysHub/MagicaVoxel-VOX-importer/pull/14

wizardgsz commented 5 years ago

How to set the new "pivot" as the center of the "bounding box" (having x, y, z loaded from SIZE chunk)?

I write here just a "note", a code snippet, to further investigate about it (especially when scene-graph will be implemented I think):

# Set object pivot using cursor location
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
RichysHub commented 5 years ago

Hmm, I wonder if there is a common way of handling the origin of imported models.

If the other import options all import it relative to (0, 0, 0), or to the cursor, it would be wise to follow suit.

Having access to the dimensions in the SIZE will definitely make it straightforward; I could imagine a calculated offset of -x/2, -y/2, -z/2 being applied to each voxel for example, to result in centering upon the origin.

wizardgsz commented 5 years ago

I've never thought about it but your reasoning makes sense!

ldo commented 3 years ago

I have an algorithm for coalescing cubes and removing interior faces in my importer.