darkfall / MagicaVoxelUnity

Unity3D plugin for MagicaVoxel's vox format.
MIT License
197 stars 34 forks source link

Individual voxels #16

Open barraudf opened 6 years ago

barraudf commented 6 years ago

When "Import as Individual Voxels is selected", there is a bug with mesh building : in the following screen, I've imported a model as individual voxels, then used the "Combine Selected" function on the left half of the voxels.

individual-bug

There clearly is a problem with lighting and I believe this is due to incorrect normals. In MVImporter.CubeMeshWithColor(float, Color) only 8 vertices are added to the mesh, one for each "corner". There should 3 for each corner : one for each corner and for each face (normal).

On the other hand models will have 3 times more data...

I'm not concerned about individual voxels (yet), so I just open this ticket so that people knows what's going on with lighting. I don't know if this should be fixed or not.

K-Anator commented 4 years ago

Just wanted to throw this in here in case someone finds it useful. I'm using this in Unity 2019.3.10f and while it works (we'll ignore the 100s of console messages I don't understand). I was looking to get individual voxels, and the lighting thing threw me for a loop. So my solution, instead of generating meshes, generate Unity cube primitives.

In MVImporter.CreateIndividualVoxelGameObjectsForChunk() I commented out the line GameObject go = CreateGameObject (...) and replaced it with:

GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name = string.Format("Voxel ({0}, {1}, {2})", x, y, z);
go.transform.parent = parent;
go.transform.localPosition = new Vector3(px, py, pz);
go.transform.localScale = new Vector3(sizePerVox, sizePerVox, sizePerVox);  

MeshRenderer mr = go.GetComponent<MeshRenderer>();
mr.material.SetColor("_BaseColor", palatte[cidx -1]);

One other change I've made, is that the default material has been changed to an HDRP/Lit. So return new Material (Shader.Find ("Diffuse")); needs to be changed to return new Material (Shader.Find ("HDRP/Lit"));

I feel like I've done some stuff poorly, but this gets me what I want, a bunch of cubes the same color they were in MagicaVoxel, with colliders.

I'm going to look at creating a ShaderGraph that will look at the pallet, and texture the cubes according to those instead, that way I can have it handle separate materials differently like glass, and such.

Left ship is an import straight from MV. Right one was exported from MV as OBJ, cleaned up in Blender to be exported as FBX, and finally imported to Unity. Also, ships are at 0.1 scale, knight is default.

image

I'd also like to note that this throws a bunch of warnings about using renderer.material instead of renderer.sharedMaterial but it doesn't work otherwise with what I can do.

Update: More hacky hacky!

I now have it check for a material asset matching the RGBA in hex, if that material doesn't exist, it's created, if not, it's just applied. This made more sense to me than doing a custom shader.

GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name = string.Format("Voxel ({0}, {1}, {2})", x, y, z);
go.transform.parent = parent;
go.transform.localPosition = new Vector3(px, py, pz);
go.transform.localScale = new Vector3(sizePerVox, sizePerVox, sizePerVox);

Material tempMat = (Material)AssetDatabase.LoadAssetAtPath("Assets/MagicaVoxel/Materials/" + ColorUtility.ToHtmlStringRGBA(palette[cidx - 1]) + ".mat", typeof(Material));

if (tempMat == null) { 
    Material material = new Material(Shader.Find("HDRP/Lit"));
    material.SetColor("_BaseColor", palette[cidx - 1]);
    AssetDatabase.CreateAsset(material, "Assets/MagicaVoxel/Materials/" + ColorUtility.ToHtmlStringRGBA(palette[cidx - 1]) + ".mat");
}
MeshRenderer mr = go.GetComponent<MeshRenderer>();
mr.material = tempMat;

image