Reputation: 60858
Is it possible to draw a whole cube using just a single GL_TRIANGLE_STRIP
?
Obviously it's just the cube combinatorics I'm concerned about here, it might as well be stretched into any kind of box or similar object.
Upvotes: 22
Views: 14993
Reputation: 546
Based on Quazil's post, the following is a correct implementation of a perfect cube using TRIANGLE_STRIP of 8 vertices with 14 indices.
let [x, y, z] = [0.0, 0.0, 0.0]; // positions
let [xw, yh, zd] = [1.0, 1.0, 1.0]; // dimensions
let vertices = [
xw, yh, z, // [1, 1, 0] [00]
x, yh, z, // [0, 1, 0] [01]
xw, yh, zd, // [1, 1, 1] [02]
x, yh, zd, // [0, 1, 1] [03]
xw, y, z, // [1, 0, 0] [04]
x, y, z, // [0, 0, 0] [05]
x, y, zd, // [0, 0, 1] [06]
xw, y, zd, // [1, 0, 1] [07]
];
let indices = [
0, 1, 4, 5, 6, 1, 3, 0, 2, 4, 7, 6, 2, 3
];
The orientation of the faces produced from this implementation respect OpenGL's default face (GL_BACK
) when using glCullFace.
Upvotes: 0
Reputation: 47
The paper mentioned above has the triangles wound in the wrong direction however is there is a simple correction, reverse the order of vertices, and it will become front-facing-outward (not inward).
1 2 5 6 7 2 4 1 3 5 8 7 3 4
And here is a set of vertices for a unit-cube. You can apply a transformation to this and render your bounding-boxes (axis-aligned or oriented).
static const std::array<float> cube_strip = {
+0.5, +0.5, -0.5, // Back-top-right
-0.5, +0.5, -0.5, // Back-top-left
+0.5, -0.5, -0.5, // Back-bottom-right
-0.5, -0.5, -0.5, // Back-bottom-left
-0.5, -0.5, +0.5, // Front-bottom-left
-0.5, +0.5, -0.5, // Back-top-left
-0.5, +0.5, +0.5, // Front-top-left
+0.5, +0.5, -0.5, // Back-top-right
+0.5, +0.5, +0.5, // Front-top-right
+0.5, -0.5, -0.5, // Back-bottom-right
+0.5, -0.5, +0.5, // Front-bottom-right
-0.5, -0.5, +0.5, // Front-bottom-left
+0.5, +0.5, +0.5, // Front-top-right
-0.5, +0.5, +0.5, // Front-top-left
};
Upvotes: 2
Reputation: 2617
This version also has texture coordinates and normals just in case you need those.
I tested this with WebGL and the cube is texture mapped correctly but has peculiarities due to the fact that you really need three texture coordinates for each corner - one for each face. Because of this you can use these UVs to texture map 4 sides of the cube, but the top and bottom will not have proper textures.
const Cube = function () {
const u0 = 0;
const u1 = 1;
const v0 = 0;
const v1 = 1 / 3;
const v2 = 2 / 3;
const v3 = 1;
const verticies = [
+1, +1, -1,
-1, +1, -1,
+1, -1, -1,
-1, -1, -1,
+1, +1, +1,
-1, +1, +1,
-1, -1, +1,
+1, -1, +1,
];
const uvs = [
u0, v3,
u0, v0,
u0, v2,
u0, v1,
u1, v3,
u1, v0,
u1, v1,
u1, v2,
];
const indexes = [3, 2, 6, 7, 4, 2, 0, 3, 1, 6, 5, 4, 1, 0];
const v = [];
const u = [];
for (var i = 0; i < indexes.length; i++) {
const corner = indexes[i];
v.push(verticies[corner * 3 + 0]);
v.push(verticies[corner * 3 + 1]);
v.push(verticies[corner * 3 + 2]);
u.push(uvs[corner * 2 + 0]);
u.push(uvs[corner * 2 + 1]);
}
return {
verticies: v,
uvs: u,
normals: v
};
};
Upvotes: 1
Reputation: 31
May be useful to some, here's a geometry shader that will take in a point and output a triangle strip of a unit cube
#version 410
layout(points) in;
layout(triangle_strip, max_vertices = 12) out;
uniform mat4 mvp;
void main() {
vec4 center = gl_in[0].gl_Position;
vec4 dx = mvp[0];
vec4 dy = mvp[1];
vec4 dz = mvp[2];
vec4 p1 = center;
vec4 p2 = center + dx;
vec4 p3 = center + dy;
vec4 p4 = p2 + dy;
vec4 p5 = p1 + dz;
vec4 p6 = p2 + dz;
vec4 p7 = p3 + dz;
vec4 p8 = p4 + dz;
gl_Position = p7;
EmitVertex();
gl_Position = p8;
EmitVertex();
gl_Position = p5;
EmitVertex();
gl_Position = p6;
EmitVertex();
gl_Position = p2;
EmitVertex();
gl_Position = p8;
EmitVertex();
gl_Position = p4;
EmitVertex();
gl_Position = p7;
EmitVertex();
gl_Position = p3;
EmitVertex();
gl_Position = p5;
EmitVertex();
gl_Position = p1;
EmitVertex();
gl_Position = p2;
EmitVertex();
gl_Position = p3;
EmitVertex();
gl_Position = p4;
EmitVertex();
}
Upvotes: 3
Reputation: 3937
For those of you who are lazy (like me), here's a copy-paste version of rob mayoff's answer ;)
static const GLfloat cube_strip[] = {
-1.f, 1.f, 1.f, // Front-top-left
1.f, 1.f, 1.f, // Front-top-right
-1.f, -1.f, 1.f, // Front-bottom-left
1.f, -1.f, 1.f, // Front-bottom-right
1.f, -1.f, -1.f, // Back-bottom-right
1.f, 1.f, 1.f, // Front-top-right
1.f, 1.f, -1.f, // Back-top-right
-1.f, 1.f, 1.f, // Front-top-left
-1.f, 1.f, -1.f, // Back-top-left
-1.f, -1.f, 1.f, // Front-bottom-left
-1.f, -1.f, -1.f, // Back-bottom-left
1.f, -1.f, -1.f, // Back-bottom-right
-1.f, 1.f, -1.f, // Back-top-left
1.f, 1.f, -1.f // Back-top-right
};
Upvotes: 17
Reputation: 385500
From the paper Optimizing Triangle Strips for Fast Rendering by Evans, Skiena, and Varshney:
Upvotes: 34
Reputation: 60858
Yes, after a bit of experimenting I found the answer myself. Imagine the corners of your cube are colored alternatingly black and white. Draw a triangle edge along each face between the two black corners. That way, the diagonals form a tetrahedron inside the cube. For the [0,1]³ cube, a possible sequence of coordinates would be the following:
Vertex Triangle Face
------+-----------+-----
0 0 0
0 1 0
1 0 0 000 010 100 **0
1 1 0 100 010 110 **0
1 1 1 100 110 111 1**
0 1 0 111 110 010 *1*
0 1 1 111 010 011 *1*
0 0 1 011 010 001 0**
1 1 1 011 001 111 **1
1 0 1 111 001 101 **1
1 0 0 111 101 100 1**
0 0 1 100 101 001 *0*
0 0 0 100 001 000 *0*
0 1 0 000 001 010 0**
Upvotes: 6