Voxelers / mcthings

A Python framework for creating 3D scenes in Minecraft and Minetest
Apache License 2.0
58 stars 11 forks source link

Design and Implement vox2schematic tool #99

Closed acs closed 4 years ago

acs commented 4 years ago

This tool must be used to import voxels and meshes into McThings (schematics format).

https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox-extension.txt

The primary goal is to import from vox format fo schematic. For that:

acs commented 4 years ago

Related to this one: https://github.com/juntosdesdecasa/mcthings/issues/100

acs commented 4 years ago

Maybe we should extend:

https://gitlab.com/bztsrc/mtsedit/blob/master/docs/batch.md

so it exports Schematic format. And that's all!

Add a

-S: output to Schematic

It is implemented in C language, like GNOME :)

acs commented 4 years ago

vox has several importers at:

https://github.com/Zarbuz/FileToVox

So the writting of vox files is well covered here.

And probably also the reading if they have good tests. It is implemented in C# and here we have the reader and writer:

https://github.com/Zarbuz/FileToVox/tree/master/SchematicToVoxCore/Vox

In this tool, it seems all the formats are comnverted to Schematics and the Schematics is converted to Vox. In McThings, my guess is that we will use also Schematics format as the common one. Why? Becase it has solid tools to process it (NBTtools) and the format is simple and flexible and complete.

acs commented 4 years ago

The writing to vox format seems to be pretty easy:

https://gitlab.com/bztsrc/mtsedit/-/commit/80569a64c0c91080699f46fd9a1302b14b1847b2

and it uses the Y, X, Z order as in schematics.

it is writing a header, the data and the palette. If it is so easy to do, probably we can just implement it from scratch and later, create a library with support for reading and writing VOX files like the NBT library.

acs commented 4 years ago

The process for a guy doing the same for Three.js: https://luciopaiva.com/magicavoxel-threejs-howto/

acs commented 4 years ago

VOX uses RIFF format, and in Python there is a module built-in for reading this kind of data:

https://docs.python.org/3.8/library/chunk.html

Great!

So we can do a clean job reading and writing VOX files.

acs commented 4 years ago

So my conclusion is that VOX format is so easy to read and write that:

So we have a plan!

acs commented 4 years ago

The name of the first library was vox-io. Not bad. I will use voxpy probably.

Screenshot from 2020-06-15 00-40-38

acs commented 4 years ago

https://github.com/RichysHub/MagicaVoxel-VOX-importer Blender importer for VOX format implemented in Python. A good reference.

And also in https://github.com/jpaver/opengametools they have a reader and writter implemented in C++ based on a vox parser C++ library.

For JS: https://github.com/dgoemans/VoxRenderer

acs commented 4 years ago

Some experiences supporting the new format:

https://github.com/RichysHub/MagicaVoxel-VOX-importer/issues/6

acs commented 4 years ago

A very useful command to see the structure of the vox file:

(venv) strings vxs.vox 
VOX 
MAIN
SIZE
XYZI
nTRN
nGRP
nTRN-
-1 -1 2nSHP
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
LAYR
_name
RGBA
MATL
_type
_diffuse
_weight
_rough
_spec
_spec_p
_ior
_att
-0.5
_flux
_ldr
0MATL
....
acs commented 4 years ago

The proposed reading process for chunks in python lib:

«Usually an IFF-type file consists of one or more chunks. The proposed usage of the Chunk class defined here is to instantiate an instance at the start of each chunk and read from the instance until it reaches the end, after which a new instance can be instantiated. At the end of the file, creating a new instance will fail with an EOFError exception.»

Let's try to follow it! Start a new chunk given the position of the chunk on the file.

A nice example doing just that here: https://www.programcreek.com/python/example/93077/chunk.Chunk

The key is to create Chunk with the file positioned correctly for reading the next chunk. Part of:

https://github.com/pyblish/pyblish-win/blob/master/lib/Python27/Lib/wave.py

And indeed this is a pretty interesing project: https://pyblish.com/ «Pyblish is what enables our artists to focus more on the artistic barrier of raising quality instead of the technical one whilst maintaining a pipeline that raises the bar for both.»

acs commented 4 years ago

Ok, let's try to describe at high level the format in the current version of the file (vox-extension) using the strings command output.

acs commented 4 years ago

So if we want to load 1 model and only the cubes, our focus must be the Model Chunk:

5. Chunk id 'SIZE' : model size
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4        | int        | size x
4        | int        | size y
4        | int        | size z : gravity direction
-------------------------------------------------------------------------------

6. Chunk id 'XYZI' : model voxels
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4        | int        | numVoxels (N)
4 x N    | int        | (x, y, z, colorIndex) : 1 byte for each component
-------------------------------------------------------------------------------

and the palette

7. Chunk id 'RGBA' : palette
-------------------------------------------------------------------------------
# Bytes  | Type       | Value
-------------------------------------------------------------------------------
4 x 256  | int        | (R, G, B, A) : 1 byte for each component
                      | * <NOTICE>
                      | * color [0-254] are mapped to palette index [1-255], e.g : 
                      | 
                      | for ( int i = 0; i <= 254; i++ ) {
                      |     palette[i + 1] = ReadRGBA(); 
                      | }
-------------------------------------------------------------------------------
acs commented 4 years ago

In the first iteration the goal is to support the last version of the format, but probably, it is easy to support older formats.

acs commented 4 years ago

Great, it seems it is going to be easy and clean to support VOX format. The code is taking shape at:

https://github.com/acs/mcthings/blob/99-vox2schematics/mcthings/vox.py

acs commented 4 years ago

Great, it is a bit tricky to use the chunk python lib to read the vox file, but once I know how to do it, it will be much maintainable having the Chunk concept supported in the logic. 2h aprox to have a first working version.

acs commented 4 years ago

Ok, now we can read the blocks and the colors from a MagicaVoxel file. Cool! Now it is time to map it to Minecraft. And this is a tough problem because we don't have all colors in Minecraft. Using wool we can replicate partially the colors.

https://www.stuffaboutcode.com/p/minecraft-api-reference.html

Data Values of blocks: WOOL: 0: White 1: Orange 2: Magenta 3: Light Blue 4: Yellow 5: Lime 6: Pink 7: Grey 8: Light grey 9: Cyan 10: Purple 11: Blue 12: Brown 13: Green 14: Red 15: Black

So we need to map the RGBA colors to this ones. The best thing is to have a Minecraft palette in MagicaVoxel to create the models using them. In this case, let's do a hack:

ee 00 00 is 14.

acs commented 4 years ago

Ok, here we go:

Screenshot from 2020-06-28 10-16-32

from

Screenshot from 2020-06-28 10-19-11

acs commented 4 years ago

mv2mc

acs commented 4 years ago

Colors from 15 to 0:

mc_colors

we need to create a magicavoxel palette with them (we need the hex codes for them).

COLORS = [
        "White",
        "Orange",
        "Magenta",
        "Light Blue",
        "Yellow",
        "Lime",
        "Pink",
        "Grey",
        "Light grey",
        "Cyan",
        "Purple",
        "Blue",
        "Brown",
        "Green",
        "Red",
        "Black"
    ]

https://gaming.stackexchange.com/questions/47212/what-are-the-color-values-for-dyed-wool

• White - FFe4e4e4 • Orange - FFea7e35 • Magenta - FFbe49c9 • Light Blue - FF6387d2 • Yellow - FFc2b51c • Lime Green - FF39ba2e • Pink - FFd98199 • Dark Gray - FF414141 • Light Gray - FFa0a7a7 • Cyan - FF267191 • Purple - FF7e34bf • Blue - FF253193 • Brown - FF56331c • Green - FF364b18 • Red - FF9e2b27 • Black - FF181414

So our next step is to create a palette in MagicaVoxel with this colors.

acs commented 4 years ago

But before working at the color detail, let's check all is working with some models in vox format.

One of our goals is to support the loading of:

https://github.com/mikelovesrobots/mmmm

And maybe this is the old version format. The goal is to support it also. So let's work on that.

Let's play with this one wich is 8 (z) x 4 (x) x 11 (y): 332 blocks. alien_engi1a

Screenshot from 2020-06-28 18-05-06

It has 4 colors: blue, black, gray and light gray. So an accurate job could be done!

It is a 6 years old model, and I love to support this old models!!! Let's do it :100:

The old format is simpler:

(venv) strings alien_engi1a.vox 
VOX 
MAIN
SIZE
XYZI
RGBA

To check the correct loading of the palette we can do it in MV. For each palette there are 32 * 8 = 256 colors.

And we can check the colors in MV:

Screenshot from 2020-06-28 21-08-22

To check the full palette:

Screenshot from 2020-06-28 21-01-10

In this palette the first color is (index 1): ffffff . The index 2: ffffcc. index 3: ffff99.

and the last color is index 255 is 111111. The 249 is aaaaaa (256 can not be selected and it is not part of the palette). So the palette goes from 0 to 254 (at least in the old version).

¿Is that the default one? I think so (but in the file, index 1 is 000000, and the colors are in different order: ffff99 is 99ffff.

Let's check that we are reading the palette correctly (I am pretty sure there are no issues with the blocks).

acs commented 4 years ago

The results are promising.

alien_engi1a_mc

As expected we need to fix the colors. But we are in the right path!

acs commented 4 years ago

Ok, before putting all focus in the colors transformation, let's try to conversion to Schematic. This is something already available in McThings, so just testing the plumbing.

The goal is to generate the Voxelers logo as a Schematic.

Screenshot from 2020-06-28 23-23-45

Loaded from a Schematic. For some reason we are exporting 24 blocks instead of 6. We need to review it, but it is working in the dev branch for vox support.

Screenshot from 2020-06-28 23-26-55

The problem is "x-axis" that must be 1 and it is 4. I will recheck it.

Screenshot from 2020-06-29 05-29-12

So the problem is the self.position. If we use init_pos and end_pos for schematic extraction, it will work. But why self.position is not init_pos? Let's review.

It is working nicely. Why? Let's take a look to MV:

Screenshot from 2020-06-29 05-41-28

The position of z is +3, x +1 and y +0- So the blocks go from z:0, 2 x:0, 3 y:0,1 (3 x 4 x 2 = 24). So the schematic is perfect. In order to avoid the offset, we need to create in MV without offset.

Screenshot from 2020-06-29 05-50-20

And using this vox model we get in the schematic:

2020-06-29 05:51:12,466 Schematic: Exporting blocks: 6

And we get the right number of blocks (3 empty blocks, and 3 red blocks)

acs commented 4 years ago

Ok, time to create our Minecraft wool palette for MV.

https://gaming.stackexchange.com/questions/47212/what-are-the-color-values-for-dyed-wool

• White -      e4e4e4
• Orange -     ea7e35
• Magenta -    be49c9
• Light Blue - 6387d2
• Yellow -     c2b51c
• Lime Green - 39ba2e
• Pink -       d98199
• Dark Gray -  414141
• Light Gray - a0a7a7
• Cyan -       267191
• Purple -     7e34bf
• Blue -       253193
• Brown -      56331c
• Green -      364b18
• Red -        9e2b27
• Black -      181414

Screenshot from 2020-06-29 06-33-08

minecraft_wool_palette

acs commented 4 years ago

wool_wall

Mostly we have it! It is flipped but this should be easy to fix.

acs commented 4 years ago

Ok, just pending:

acs commented 4 years ago

In order to fix the flip issue, the best approach is to implement the flip operation in mcthings: https://github.com/Voxelers/mcthings/issues/112

But we have not a flip issue. It is just to look to the wall from the right side (the same side we use in MV).

wool_wall_ok

But, is it the same for the alien robot? No

alien_flip

And we have the same issue when going through vox->obj->binvox->schematic

The problem is that in general x grows in this direction >--->---> but in MC it grows in <----<-----< (and the same for z). So we need to flip.

acs commented 4 years ago

Much better now with the flip operation implemented.

Screenshot from 2020-06-30 08-33-17

acs commented 4 years ago

Ok, let's play with colors and then review code, improve tests, prepare demos and implement the command line tool and disseminate.

acs commented 4 years ago

Let's try to reproduce the alien colors in Minecraft. For doing it:

This is a general workflow to be done each time you want to have valid colors inside Minecraft.

Also, we can add more colors using other blocks in Minecraft:

acs commented 4 years ago

But first, let's check if flip_z is needed also. And let's do it by default when loading VOX data for both use cases. Let's play with the model veh_ambulance.vox:

Screenshot from 2020-07-01 05-15-57

Screenshot from 2020-07-01 05-23-48

acs commented 4 years ago

Ok, it seems there are no flipping issues in z-axis. Let's try to recreate the ambulance colors.

For doing it, let's use the MC palette y MV.

Screenshot from 2020-07-01 05-27-12

Screenshot from 2020-07-01 05-28-12

To the left the original one, to the right using the MC wool colors:

Screenshot from 2020-07-01 05-37-59

and the result in MC:

Screenshot from 2020-07-01 05-41-24

The dark gray wool is getting red wool for some reason. But the rest of the colors are ok. Bug found: the grey in this region is not the MC one, but the empty one without color!

Screenshot from 2020-07-01 05-54-12

acs commented 4 years ago

Ok, just pending:

acs commented 4 years ago

Command line tool

vox2schematic:

In the first version that's all. In new version we can add an optional map from MV colors to MC blocks/wool colors.

The tool will work from memory version of the models, so it must be pretty fast. Test it with the 400 models from Mike.

acs commented 4 years ago

Goals:

acs commented 4 years ago

Ok, let's create the tool: vox2schematic. At some point it could be also interesting the schematic2vox, but I think it is less interesting.

acs commented 4 years ago

Ok, right now we are collecting the data in build_schematic_nbt from the data in the renderer. But this information is available in memory also, because we are using the Minecraft format for the memory schemas. So we need to have at least a method build_schematic_nbt_from_memory that uses the data in memory and that does not try to collect the data from the renderer.

But we are pretty close to have the feature implemented.

acs commented 4 years ago

Ok, the script is working:

(venv) bin/vox2schematic.py ~/devel/mmmm/vox/obj_house6.vox -o tests/schematics/obj_house6.schematic

It is slow, but increase the performace should be easy to reach a reasonable performance.

Screenshot from 2020-07-02 18-55-42 Screenshot from 2020-07-02 18-55-30

For example, with this house with 78336 blocks, it has not finished yet after 5 minutes. So let's implement the first improvement.

Fixed the performance issue:

(venv) bin/vox2schematic.py ~/devel/mmmm/vox/obj_house6.vox -o tests/schematics/obj_house6.schematic
2020-07-02 19:12:20,855 Vox input file: /home/adelcastillo/devel/mmmm/vox/obj_house6.vox
2020-07-02 19:12:20,855 Schematic output file: tests/schematics/obj_house6.schematic
2020-07-02 19:12:22,006 Schematic: Exporting blocks: 78336
2020-07-02 19:12:22,053 Creating the memory cache with positions
2020-07-02 19:12:22,119 Done memory cache with positions
2020-07-02 19:12:22,552 Schematic export finished in 0.55 secs

and the schematic result is ...

Screenshot from 2020-07-02 19-15-57 Screenshot from 2020-07-02 19-15-25

acs commented 4 years ago

5 minutes investment colouring the house:

Screenshot from 2020-07-02 19-21-51 Screenshot from 2020-07-02 19-28-38

and the result in Minecraft:

(venv) bin/vox2schematic.py ~/devel/voxels/MagicaVoxel-0.99.5.1-win64/export/obj_house6-mc.vox -o tests/schematics/obj_house6-mc.schematic
....
    voxel_color = self.palette[voxel.color_index]
IndexError: list index out of range

Found a bug. Let's fix it! The format of the file is different, We need to improve our parser. The problem is that for some reason during colouring two models were created. Right now, only one model is supported. Fixed.

And the result house:

Screenshot from 2020-07-03 06-25-34 Screenshot from 2020-07-03 06-24-53

acs commented 4 years ago

The main issue with this house is that it is for giants. So it is not at the right dimension for MC. So we need to work in MV at a smaller scale so the creations are natural inside the MC world. But this can be done. But it is a new way to create inside MV: for Minecraft. And also, the models are filled, so the house is a thick block.

So this kind of models are not useful in Minecraft to interact with them. So the question is .... is it better to create in MV that inside MC directly? My guess is that yes, but we need to improve the MC blocks can be used inside MV, and there are things that will be done better inside MC.

acs commented 4 years ago

Ok, so next steps:

acs commented 4 years ago

Tool included in 0.51.1 and working.

Next step is to put focus in the tests!!

acs commented 4 years ago

About the tool, we need to capture the exceptions if the format is not the expected one: only one model for legacy and current format.

acs commented 4 years ago

Hay muchos conversores de otros formatos a VOX (https://github.com/Eisenwave/voxel-io y otros proyectos), así que todos ellos los podríamos llevar a Minecraft.

acs commented 4 years ago

More repos with models to test the conversor: https://www.mediafire.com/folder/a0znmricqxlkz/Free_Voxels

acs commented 4 years ago

Should we add the multi model support? Probably not in the first iteration: it is complex to have useful results with complete scenes ... but it is pretty alignet with McThings. The scene could be broken in schematics and added individually.

acs commented 4 years ago

Probably if we can not convert a color to the right Minecraft one, it is better to leave the block as a grey one (or stone or a fixed block).

acs commented 4 years ago

Ok, next steps:

acs commented 4 years ago

Using an improved version of the automatic coloring based on the above proposal the results are:

Screenshot from 2020-07-04 09-08-18 Screenshot from 2020-07-04 09-11-47 Screenshot from 2020-07-04 09-08-36 Screenshot from 2020-07-04 09-12-00 Screenshot from 2020-07-04 09-12-22