Skip to main content
GameDev.net gamedev.net
🔒 Locked

Creating cubes with XNA primitives

Started by Jo Nov 26, 2011 at 9:50 AM 2 replies 2.8k views
Original Post
Jo
Jo
Hi guys, i'm trying to create cubes using XNA primitives, but i don't understand how to use triangle to make then. Help?
I made the first face, but i don't know how i can do the rest.

[color="#666666"][font="Arial"]
[source lang="cs"][/font][color="#666666"][font="Arial"]
[color="blue"]this.triangleStrip = [color="blue"]new [color="#2B91AF"]VertexPositionColor[4];
triangleStrip[0].Position = [color="blue"]new [color="#2B91AF"]Vector[color="#2B91AF"]3(450, 400, 0);
triangleStrip[1].Position = [color="blue"]new [color="#2B91AF"]Vector[color="#2B91AF"]3(550, 400, 0);
triangleStrip[2].Position = [color="blue"]new [color="#2B91AF"]Vector[color="#2B91AF"]3(450, 500, 0);
triangleStrip[3].Position = [color="blue"]new [color="#2B91AF"]Vector[color="#2B91AF"]3(550, 500, 0); [/font]
[color="#666666"][font="Arial"][/source][/font]
Starnick
Starnick
An easy way of considering a cube is to have it axis-aligned (each face is aligned with the x, y, z axes). So you write your cube creation function/class/etc, pass in a center point and a size (in the example code I use extents, or half lengths - the length from the center to a face on each respective axis) so then you can programmatically create a cube without hardcoding anything. Note, the following explanation and code uses triangle list, not triangle strip.

A cube has 8 corner vertices, but generally your cube will require 36 vertices in order to account for uniqueness - like UV coordinates and normals (or vertex colors in your case). By using indexed geometry, you can cut this down to 24 unique vertices since vertices can be shared by the triangles that make up each face (so no need to replicate that data). Following code is largely based on a Box class I wrote that can be found here.

[source lang=csharp]
private Vector3 XAxis = new Vector3(1, 0, 0);
private Vector3 YAxis = new Vector3(0, 1, 0);
private Vector3 ZAxis = new Vector3(0, 0, 1);

...

//Center is usually the origin, and X, Y, Z values of extents correspond to the half-length along each axis.
public void ComputeBox(Vector3 center, Vector3 extents) {

Vector3[] exAxes = new Vector3[3];
exAxes[0] = XAxis * extents.X;
exAxes[1] = YAxis * extents.Y;
exAxes[2] = ZAxis * extents.Z;

Vector3[] vertices = new Vector3[8];

//Use the scaled axes to compute the 8 corners
vertices[0] = ((center - exAxes[0]) + exAxes[1]) + exAxes[2];
vertices[1] = ((center + exAxes[0]) + exAxes[1]) + exAxes[2];
vertices[2] = ((center + exAxes[0]) - exAxes[1]) + exAxes[2];
vertices[3] = ((center - exAxes[0]) - exAxes[1]) + exAxes[2];


vertices[4] = ((center + exAxes[0]) + exAxes[1]) - exAxes[2];
vertices[5] = ((center - exAxes[0]) + xAxes[1]) - exAxes[2];
vertices[6] = ((center - exAxes[0]) - exAxes[1]) - exAxes[2];
vertices[7] = ((center + exAxes[0]) - exAxes[1]) - exAxes[2];

//Set position data
Vector3[] positions = new Vector3[24];

//Front face (facing +Z axis)
positions[0] = vertices[0];
positions[1] = vertices[1];
positions[2] = vertices[2];
positions[3] = vertices[3];

//Back face (facing -Z axis)
positions[4] = vertices[4];
positions[5] = vertices[5];
positions[6] = vertices[6];
positions[7] = vertices[7];

//Left face (facing -X axis)
positions[8] = vertices[5];
positions[9] = vertices[0];
positions[10] = vertices[3];
positions[11] = vertices[6];

//Right face (facing +X axis)
positions[12] = vertices[1];
positions[13] = vertices[4];
positions[14] = vertices[7];
positions[15] = vertices[2];

//Top face (facing +Y axis)
positions[16] = vertices[5];
positions[17] = vertices[4];
positions[18] = vertices[1];
positions[19] = vertices[0];

//Bottom face (facing -Y axis)
positions[20] = vertices[7];
positions[21] = vertices[6];
positions[22] = vertices[3];
positions[23] = vertices[2];

//Set normals, colors, UV coordinates, etc
//Normals can be the above directions for each face, or could have a crease, or inverted if you want an inside out box,
//need to swap the winding order of your indices to do that though (or use a rasterizer state)
//UV coordinates could be (0,0) (1,0) (1,1) (0,1) for each face

//Set indices
int[] indices = new int[36];

//Set indices for each triangle per face (two triangles, 6 faces). This should be CCW ordering for XNA.
for(int i = 0, j = 0; i < 24; i += 4) {
indices[j++] = i + 2;
indices[j++] = i + 1;
indices[j++] = i;

indices[j++] = i + 3;
indices[j++] = i + 2;
indices[j++] = i;
}

//Set geometry data to hardware buffers
}
[/source]
Jo
Jo

An easy way of considering a cube is to have it axis-aligned (each face is aligned with the x, y, z axes). So you write your cube creation function/class/etc, pass in a center point and a size (in the example code I use extents, or half lengths - the length from the center to a face on each respective axis) so then you can programmatically create a cube without hardcoding anything. Note, the following explanation and code uses triangle list, not triangle strip.

A cube has 8 corner vertices, but generally your cube will require 36 vertices in order to account for uniqueness - like UV coordinates and normals (or vertex colors in your case). By using indexed geometry, you can cut this down to 24 unique vertices since vertices can be shared by the triangles that make up each face (so no need to replicate that data). Following code is largely based on a Box class I wrote that can be found here.

[source lang=csharp]
private Vector3 XAxis = new Vector3(1, 0, 0);
private Vector3 YAxis = new Vector3(0, 1, 0);
private Vector3 ZAxis = new Vector3(0, 0, 1);

...

//Center is usually the origin, and X, Y, Z values of extents correspond to the half-length along each axis.
public void ComputeBox(Vector3 center, Vector3 extents) {

Vector3[] exAxes = new exAxes[3];
exAxes[0] = XAxis * extents.X;
exAxes[1] = YAxis * extents.Y;
exAxes[2] = ZAxis * extents.Z;

Vector3[] vertices = new Vector3[8];

//Use the scaled axes to compute the 8 corners
vertices[0] = ((center - exAxes[0]) + exAxes[1]) + exAxes[2];
vertices[1] = ((center + exAxes[0]) + exAxes[1]) + exAxes[2];
vertices[2] = ((center + exAxes[0]) - exAxes[1]) + exAxes[2];
vertices[3] = ((center - exAxes[0]) - exAxes[1]) + exAxes[2];


vertices[4] = ((center + exAxes[0]) + exAxes[1]) - exAxes[2];
vertices[5] = ((center - exAxes[0]) + xAxes[1]) - exAxes[2];
vertices[6] = ((center - exAxes[0]) - exAxes[1]) - exAxes[2];
vertices[7] = ((center + exAxes[0]) - exAxes[1]) - exAxes[2];

//Set position data
Vector3[] positions = new Vector3[24];

//Front face (facing +Z axis)
positions[vertices[0]];
positions[vertices[1]];
positions[vertices[2]];
positions[vertices[3]];

//Back face (facing -Z axis)
positions[vertices[4]];
positions[vertices[5]];
positions[vertices[6]];
positions[vertices[7]];

//Left face (facing -X axis)
positions[vertices[5]];
positions[vertices[0]];
positions[vertices[3]];
positions[vertices[6]];

//Right face (facing +X axis)
positions[vertices[1]];
positions[vertices[4]];
positions[vertices[7]];
positions[vertices[2]];

//Top face (facing +Y axis)
positions[vertices[5]];
positions[vertices[4]];
positions[vertices[1]];
positions[vertices[0]];

//Bottom face (facing -Y axis)
positions[vertices[7]];
positions[vertices[6]];
positions[vertices[3]];
positions[vertices[2]];

//Set normals, colors, UV coordinates, etc
//Normals can be the above directions for each face, or could have a crease, or inverted if you want an inside out box,
//need to swap the winding order of your indices to do that though (or use a rasterizer state)
//UV coordinates could be (0,0) (1,0) (1,1) (0,1) for each face

//Set indices
int[] indices = new int[36];

//Set indices for each triangle per face (two triangles, 6 faces). This should be CCW ordering for XNA.
for(int i = 0, j = 0; i < 24; i += 4) {
indices[j++] = i + 2;
indices[j++] = i + 1;
indices[j++] = i;

indices[j++] = i + 3;
indices[j++] = i + 2;
indices[j++] = i;
}

//Set geometry data to hardware buffers
}
[/source]



Hi, thanks for the explanation, but, i've tryed to test your code, but i found some problems.. in [source lang=csharp]
Vector3[] exAxes = new exAxes[3];
[/source]


On line: [source lang=csharp]
[font="Consolas,"] positions[vertices[0]];[/font]
[font="Consolas,"][/source][/font]
i got the problem:
[color="#222222"][font="arial, sans-serif"]Only assignment, call, increment, decrement, and new object expressions can be used as a statement[/font]



Is your code working fine with you?
Starnick
Starnick
Well that was a gigantic embarrassing mistake . In my original code (the Box class link) I wrap arrays in something called a DataBuffer, so if you have a DataBuffer you can use Set(Vector3), which adds the value to the underlying array at the current position (index) and increments the position. But I replaced all that with a regular old array, but forgot to add in the indices! The original code snippet is corrected now.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.