- Home /
How to create a custom cuboids at runtime?
I am creating a voxel based game (think Minecraft adventure mode) and the performance of having many box colliders and unneeded vertices/draw calls of separate cubes was really low. My first approach was combining the cubes into single mesh, which I did(for each block type) but I still had separate colliders for each block and I still had performance issues when a bigger area was loaded and a huge spike when dynamically loading world around me due to the overhead of creating colliders.
So I decided to compress blocks into bigger cuboids but I can't work out how to create custom cuboids at runtime(specified by two Vector3s). My first approach was taking the basic cube and scaling it, but I'm not a huge fan of scaling and I had some texturing issues, so I decided to use the Mesh class and create it from scratch. I looked at the examples but it's a bit unclear, so I am asking for people with experience using the Mesh class to help me work out how to create a custom cuboid.
Thank you for taking your time!
No, they are origin and end (for image http://kjmaclean.com/Geometry/Cubeoctahedron_files/image004.jpg points A and G), should have been more clear in the question. Sorry.
And how are you thinking of mapping a texture onto it? Texture covers each face completely?
Yes, I am gonna create a texture for the compound cuboid probably. I actually figured most out myself and already supplied an answer. Any suggestions are welcome.
Answer by raoz · Jan 05, 2013 at 12:43 PM
After looking at some examples, I managed to figure it out, it's only missing UV coords(I just put in default X-Z planar UV coords as a placeholder). The task seemed more intimidating than it actually was. Here's the code:
EDIT: Split up the vertices for texture mapping and did the texture mapping work. Also added adding a box collider.
using UnityEngine;
using System.Collections;
public static class CreateArbitaryPrimitive {
public static void CreateCuboid(Vector3 origin, Vector3 end)
{
Vector3 diff = end - origin;
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[24];
Vector2[] uv = new Vector2[vertices.Length];
int[] triangles = new int[36];
vertices[0] = new Vector3(0, 0, 0);//side1
uv[0] = new Vector2(1 / 6f, 0);
vertices[1] = new Vector3(diff.x, 0, 0);//side1
uv[1] = new Vector2(0 / 6f, 0);
vertices[2] = new Vector3(0, diff.y, 0);//side1
uv[2] = new Vector2(1 / 6f, 1);
vertices[4] = new Vector3(diff.x, diff.y, 0);//side1
uv[4] = new Vector2(0 / 6f, 1);
vertices[3] = new Vector3(0, 0, diff.z); //side2
uv[3] = new Vector2(1 / 6f, 0);
vertices[8] = new Vector3(0, diff.y, 0); //side2
uv[8] = new Vector2(2 / 6f, 1);
vertices[5] = new Vector3(0, diff.y, diff.z);//side2
uv[5] = new Vector2(1 / 6f, 1);
vertices[9] = new Vector3(0, 0, 0);//side2
uv[9] = new Vector2(2 / 6f, 0);
vertices[10] = new Vector3(0, diff.y, diff.z);//side3
uv[10] = new Vector2(3 / 6f, 1);
vertices[6] = new Vector3(diff.x, 0, diff.z);//side3
uv[6] = new Vector2(2 / 6f, 0);
vertices[7] = new Vector3(diff.x, diff.y, diff.z);//side3
uv[7] = new Vector2(2 / 6f, 1);
vertices[11] = new Vector3(0, 0, diff.z);//side3
uv[11] = new Vector2(3 / 6f, 0);
vertices[12] = new Vector3(diff.x, diff.y, diff.z);//side4
uv[12] = new Vector2(4 / 6f, 1);
vertices[13] = new Vector3(diff.x, 0, diff.z);//side4
uv[13] = new Vector2(4 / 6f, 0);
vertices[14] = new Vector3(diff.x, diff.y, 0);//side4
uv[14] = new Vector2(3 / 6f, 1);
vertices[15] = new Vector3(diff.x, 0, 0);//side4
uv[15] = new Vector2(3 / 6f, 0);
vertices[16] = new Vector3(0, 0, 0);//bottom
uv[16] = new Vector2(5 / 6f, 0);
vertices[17] = new Vector3(diff.x, 0, diff.z);//bottom
uv[17] = new Vector2(4 / 6f, 1);
vertices[18] = new Vector3(0, 0, diff.z);//bottom
uv[18] = new Vector2(5 / 6f, 1);
vertices[19] = new Vector3(diff.x, 0, 0);//bottom
uv[19] = new Vector2(4 / 6f, 0);
vertices[20] = new Vector3(diff.x, diff.y, diff.z);//top
uv[20] = new Vector2(1, 1);
vertices[21] = new Vector3(0, diff.y, 0); //top
uv[21] = new Vector2(5 / 6f, 0);
vertices[22] = new Vector3(0, diff.y, diff.z);//top
uv[22] = new Vector2(5 / 6f, 1);
vertices[23] = new Vector3(diff.x, diff.y, 0);//top
uv[23] = new Vector2(1, 0);//top
#region Triangles
//sides
//side1
triangles[0] = 2;
triangles[1] = 1;
triangles[2] = 0;
triangles[3] = 1;
triangles[4] = 2;
triangles[5] = 4;
//side2
triangles[6] = 3;
triangles[7] = 8;
triangles[8] = 9;
triangles[9] = 5;
triangles[10] = 8;
triangles[11] = 3;
//side3
triangles[12] = 10;
triangles[13] = 6;
triangles[14] = 7;
triangles[15] = 11;
triangles[16] = 6;
triangles[17] = 10;
//side4
triangles[18] = 12;
triangles[19] = 13;
triangles[20] = 14;
triangles[21] = 14;
triangles[22] = 13;
triangles[23] = 15;
//bottom
triangles[24] = 16;
triangles[25] = 17;
triangles[26] = 18;
triangles[27] = 19;
triangles[28] = 17;
triangles[29] = 16;
//top
triangles[30] = 22;
triangles[31] = 20;
triangles[32] = 21;
triangles[33] = 21;
triangles[34] = 20;
triangles[35] = 23;
#endregion
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uv;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
GameObject go = new GameObject("Cuboid", typeof(MeshRenderer), typeof(MeshFilter), typeof(BoxCollider));
go.transform.position = origin;
go.GetComponent<MeshFilter>().mesh = mesh;
BoxCollider collider = go.GetComponent<BoxCollider>();
collider.size = mesh.bounds.size;
collider.center = mesh.bounds.size / 2;
}
}
You might want to dupe up some of the vertices if you want to effectively have them with different UV coordinates (which I think you do...)
So F in your diagram for instance probably needs a different UV for the face it shares with A to the coordinates with the face it shares with G.
I see what you mean, didn't think about that. Figuring the whole thing out in my head is a pain.
Yeah - I know :) So your code produced a very efficient cube and would be correct if you want to create a single texture that wraps the cube (usually this is a cross shape - but that is a inefficient as there is wasted space so you probably want to "fill in the gaps" - even so the texture needs to be square)
X
XXXX
X
I could probably move the cross to a line, but this is getting really complicated :) I better create a spec for the texture in my spec wiki :)