1
\$\begingroup\$

I'm stuck with geometry shaders in OpenGL - c++ programming. I want to create simple cube by repeating 6 times drawing one rotated wall. Here is my vertex shader (everyting has #version 330 core in preamble):

uniform mat4 MVP;
uniform mat4 ROT;
layout(location=0) in vec3 vertPos;
void main(){
    vec4 pos=(MVP*ROT*vec4(vertPos,1.5));
    gl_Position=pos;
}

Now geometry shader:

layout (triangles) in;
layout (triangle_strip, max_vertices = 6) out;
out vec4 pos;
void main(void)
{
    for (int i = 0; i < 3; i++)
    {
        vec4 offset=vec4(i/2.,0,0,0);
        gl_Position = gl_in[i].gl_Position+offset;
        EmitVertex();
    }
    EndPrimitive();
}

And now fragment shader:

uniform mat4 MVP;
in vec4 pos;
out vec3 color;
void main(){
    vec3 light=(MVP*vec4(0,0,0,1)).xyz;
    vec3 dd=pos.xyz-light;
    float cosTheta=length(dd)*length(dd);
    color=vec3(1,0,0);
}

Well, there is some junk, I wanted also put shading into my cube, but I've got a problem with sending coordinates. The main problem is - here I get my scaled square (by MVP matrix), I can even rotate it with basic interface (ROT matrix), but when I uncomment my "+offset" line I get some mess. What should I do to make clean 6-times repeating?

\$\endgroup\$
  • 2
    \$\begingroup\$ This question appears to be off-topic because it is asking for a tutorial. \$\endgroup\$ – Seth Battin Jan 8 '15 at 16:22
3
+50
\$\begingroup\$

Your geometry shader should take a single point (center of the cube) with a front vector and an up vector.

You can then output 12 triangles (6 faces x 2 tri for a quad) using the single point as the center of the cube and the cross-product of front & up for the right vector.

// table of all triangle vertices to make the cube
const vec3 face_table[12*3] = {
  vec3(1, 1, 1), vec3(-1, 1, 1), vec3(-1, -1, 1),  // first face Z=1
  vec3(1, 1, 1), vec3(-1, -1, 1), vec3(1, -1, 1), 
  vec3(-1, 1, -1), vec3(1, 1, -1), vec3(1, -1, -1),  // second face Z=-1 (note the inverted X for culling)
  vec3(-1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), 
  ... // and so on
};

Then generate the faces in a 12 triangle loop:

vec3 right_vector = cross(front_vector, up_vector); // or you can preset it as uniform

for(int i=0; i < 12*3; ++i){
  gl_Position = MVP*vec4((gl_in[i].gl_Position.xyz + face_table[i].x * right_vector + face_table[i].y * up_vector + face_table[i].z * front_vector), 1);
  EmitVertex();
}

Note that you can also use your ROT matrix uniform in the geometry shader instead: right_vector = ROT[0], up_vector = ROT[1], front_vector = ROT[2].

And that MVP is now in the geometry shader. The vertex shader should be a simple pass-through gl_Position=vec4(vertPos, 1).

EDIT: fixed vec4+vec3 error, flipped the face vertex order of -Z face for proper culling.

\$\endgroup\$
  • \$\begingroup\$ You're scalar adding dot(table,direction) to position, no way that would work. \$\endgroup\$ – Khlorghaal Jan 18 '15 at 19:12
  • \$\begingroup\$ I'd just remove the first part entirely, its pointless to mvp multiply twice. \$\endgroup\$ – Khlorghaal Jan 18 '15 at 19:13
2
\$\begingroup\$

Instead of building the cube in geometry shader from a point, its better to do an instanced render of a simple cube VBO, and forego a geometry shader entirely.

The only time you wouldn't want to do that is if each cube has rapidly changing orientation and you need to recalculate its modelview every pass.
In which case, have position and orientation as vertex attributes, then build the mvp per point-cube in the vertex shader, then do as Stephane explained in geometry using a corner-table.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.