OpenGL Geometry Shader rendering triangle instead of square from a point - opengl

I am trying to render a square from a single point, here is my geometry shader code:
#version 330 core
layout (points) in;
layout(triangle_strip, max_vertices=4) out;
void main(){
vec4 pos=gl_in[0].gl_Position;
gl_Position=pos+vec4(1,1,0,0);
EmitVertex();
gl_Position=pos+vec4(1,-1,0,0);
EmitVertex();
gl_Position=pos+vec4(-1,-1,0,0);
EmitVertex();
gl_Position=pos+vec4(-1,1,0,0);
EmitVertex();
EndPrimitive();
}
Vertex shader looks like this:
#version 330 core
layout (location=0) in vec3 position;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 model;
void main(){
gl_Position=projection*view*model*vec4(position,1.0);
}
It only renders a triangle, I'm not sure why it only renders a triangle.

The vertices define a triangle strip. Every group of 3 adjacent vertices forms a triangle and the winding order is defined by the winding of the first triangle (successive triangles have reversed order). When face culling is enabled, you need to care about the winding order. The default winding order of front faces is counter clockwise. Therefore you have to swap the 1st and 2nd vertex:
void main(){
vec4 pos=gl_in[0].gl_Position;
gl_Position=pos+vec4( 1, -1, 0, 0);
EmitVertex();
gl_Position=pos+vec4( 1, 1, 0, 0);
EmitVertex();
gl_Position=pos+vec4(-1, -1, 0, 0);
EmitVertex();
gl_Position=pos+vec4(-1, 1, 0, 0);
EmitVertex();
EndPrimitive();
}

Related

C++, OpenGL - geometry shader

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));
pos.x/=1.5;
pos.y/=1.5;
gl_Position=pos;
}
Now geometry shader:
layout (triangles) in;
layout (triangle_strip, max_vertices = 6) out;
out vec4 pos;
void main(void)
{
pos=vec4(1,1,1,1);
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?
It looks like the error is here, in your geometry shader.
gl_Position = gl_in[i].gl_Position+offset;
This adds an offset... but it adds the offset in clip space, which is probably not what you want. Add the offset in your vertex shader, or do the perspective projection in your geometry shader.
/* Passthrough vertex shader */
layout(location=0) in vec3 vertPos;
void main(){
gl_Position = vec4(vertPos, 1.0);
}
/* Geometry shader */
...
gl_Position = MVP * (ROT * (gl_in[i].gl_Position + offset));
EmitVertex();
...
Also, I noticed something unusual in your vertex shader.
pos.x/=1.5;
pos.y/=1.5;
This is unusual because it is a linear transformation that directly follows a matrix multiplication. It would probably be more straightforward to multiply your MVP matrix by the following matrix:
1/1.5 0 0 0
0 1/1.5 0 0
0 0 1 0
0 0 0 1
This would achieve the same result with less shader code.

Position Vector in Vertexshader conflicts with glTranslate

I'm trying to render an image and offset it by using glTranslate:
glPushMatrix();
glTranslatef(x, y, 0.0f);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glPopMatrix();
I'm also using a shader, and in the vertexshader I set the position of the vertices:
in vec2 position;
in vec3 color;
out vec3 Color;
void main() {
Color = color;
gl_Position = vec4(position, 0.0, 1.0);
}
However, this always renders the square at the same position. I'm thinking this is because the position vector is always the same. How can I use this shader but still be able to move the image around with glTranslate? I suspect I have to change my shader input, but how?
glTranslatef changes the MVP matrix which gets passed as a uniform into the vertex shader. There is a shortcut in pre 150 by using
gl_Position = ftransform();
Which applies the transformation matrices to the input position as it was passed in with glVertex*.
However glsl 150 core doesn't allow using that uniform or that function. Instead create a matrix uniform and pass it in:
#version 150 core
in vec2 position;
in vec3 color;
out vec3 Color;
uniform mat4 mvp;
void main() {
Color = color;
gl_Position = mvp * vec4(position, 0.0, 1.0);
}

OpenGL color transform

I'm using OpenGL to draw a large array of 2D points with their colors. Each point (vertex) has also defined it's alpha channel in MX.c array. I'd like to be able to increase or decrease the alpha value of whole array (of every vertex displayed). Is there a clever way to do it, using OpenGL functions? Here's my drawing method:
void PointsMX::drawMX()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, MX.c);
glVertexPointer(2, GL_DOUBLE, 0, MX.p);
glPushMatrix();
glTranslated(position[X], position[Y], 0.0);
glScaled(scale, scale, 1.0);
glDrawArrays(GL_POINTS, 0, MX.size);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
As datenwolf points out in his comments, you can do this pretty simply using a shader, but not using the fixed function pipeline (which is what you're using if you never call glUseProgram().
If you're not using lighting, reproducing the fixed function shaders isn't very hard, and a little googling will help you get up to that point.
The key here is that you want to change something that is normally a vertex attribute (the alpha channel of the color) to a configurable value for the entire drawing operation. In shader terms this means overriding the vertex attribute with a uniform. A uniform is simply a value you pass into an OpenGL program which then has the same value for every vertex or fragment processed (depending on whether you put it into the vertex or fragment shader).
Here's an example of a very basic vertex shader:
#version 330
uniform mat4 Projection = mat4(1);
uniform mat4 ModelView = mat4(1);
layout(location = 0) in vec3 Position;
layout(location = 3) in vec4 Color;
out vec4 vColor;
void main() {
gl_Position = Projection * ModelView * vec4(Position, 1);
vColor = Color;
}
And a corresponding fragment shader
#version 330
in vec4 vColor;
out vec4 FragColor;
void main()
{
FragColor = vColor;
}
In order to accomplish what you're trying to do, you'd want to change the vertex shader to add an additional uniform representing your alpha override:
#version 330
uniform mat4 Projection = mat4(1);
uniform mat4 ModelView = mat4(1);
uniform float AlphaOverride = -1.0;
layout(location = 0) in vec3 Position;
layout(location = 3) in vec4 Color;
out vec4 vColor;
void main() {
gl_Position = Projection * ModelView * vec4(Position, 1);
vColor = Color;
if (AlphaOverride > 0.0) {
vColor.a = AlphaOverride;
}
}
If you fail to set the AlphaOverride uniform it will be -1, and will therefore be ignored by the vertex shader. But if you set it to a value between 0 and 1, then it will be applied to the alpha channel of your vertex.

GLSL geometry shader requires glProgramParameteriEXT regardless of layout

I created a basic quad drawing shader using a single point and a geometry shader.
I've read many posts and articles suggesting that I would not need to use glProgramParameteriEXT and could use the layout keyword so long as I was using a shader #version 150 or higher. Some suggested #version 400 or #version 420. My computer will not support #version 420 or higher.
If I use only layout and #version 150 or higher, nothing draws. If I remove layout (or even keep it; it does not seem to care because it will compile) and use glProgramParameteriEXT, it renders.
In code, this does nothing:
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
This is the only code that works:
glProgramParameteriEXT( id, GL_GEOMETRY_INPUT_TYPE_EXT, GL_POINTS );
glProgramParameteriEXT( id, GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP );
glProgramParameteriEXT( id, GL_GEOMETRY_VERTICES_OUT_EXT, 4 );
The alternative is to create a parser that creates the parameters via shader source.
Source for quad rendering via geometry shader:
#version 330
#ifdef VERTEX_SHADER
in vec4 aTexture0;
in vec4 aColor;
in mat4 aMatrix;
out vec4 gvTex0;
out vec4 gvColor;
out mat4 gvMatrix;
void main()
{
// Texture color
gvTex0 = aTexture0;
// Vertex color
gvColor = aColor;
// Matrix
gvMatrix = aMatrix;
}
#endif
#ifdef GEOMETRY_SHADER
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
in vec4 gvTex0[1];
in vec4 gvColor[1];
in mat4 gvMatrix[1];
out vec2 vTex0;
out vec4 vColor;
void main()
{
vColor = gvColor[0];
// Top right.
//
gl_Position = gvMatrix[0] * vec4(1, 1, 0, 1);
vTex0 = vec2(gvTex0[0].z, gvTex0[0].y);
EmitVertex();
// Top left.
//
gl_Position = gvMatrix[0] * vec4(-1, 1, 0, 1);
vTex0 = vec2(gvTex0[0].x, gvTex0[0].y);
EmitVertex();
// Bottom right.
//
gl_Position = gvMatrix[0] * vec4(1, -1, 0, 1);
vTex0 = vec2(gvTex0[0].z, gvTex0[0].w);
EmitVertex();
// Bottom left.
//
gl_Position = gvMatrix[0] * vec4(-1, -1, 0, 1);
vTex0 = vec2(gvTex0[0].x, gvTex0[0].w);
EmitVertex();
EndPrimitive();
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D tex0;
in vec2 vTex0;
in vec4 vColor;
out vec4 vFragColor;
void main()
{
vFragColor = clamp(texture2D(tex0, vTex0) * vColor, 0.0, 1.0);
}
#endif
I am looking for suggestions as to why something like this might happen.

Is it possible to draw a sphere with strands using a unique geometry shader?

I'd like to display a simple UV sphere (exported from Blender) and generate lines with normal coordinates using a unique geometry shader.
In a first time, I wrote a simple geometry shader which simply return the input vertices informations to the fragment shader. For a sake of simplicity (for the exemple) I erased the luminosity calculations in the fragment shader.
Vertex shader :
#version 400
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
uniform mat4 MVP;
out vec3 VPosition;
out vec3 VNormal;
void main(void)
{
VNormal = VertexNormal;
gl_Position = vec4(VertexPosition, 1.0f);
}
Geometry shader :
#version 400
layout(points) in;
layout(line_strip, max_vertices = 2) out;
uniform mat4 MVP;
in vec3 VNormal[];
out vec3 fcolor;
void main(void)
{
float size = 2.5f;
fcolor = vec3(0.0f, 0.0f, 1.0f);
gl_Position = MVP * gl_in[0].gl_Position;
EmitVertex();
fcolor = vec3(1.0f, 1.0f, 0.0f);
gl_Position = MVP * vec4(gl_in[0].gl_Position.xyz + vec3(
VNormal[0].x * size, VNormal[0].y * size, VNormal[0].z * size), 1.0f);
EmitVertex();
EndPrimitive();
}
And the fragment shader :
#version 400
in vec3 Position;
in vec3 Normal;
in vec2 TexCoords;
out vec4 FragColor;
in vec3 fcolor;
void main(void)
{
FragColor = vec4(fcolor, 1.0f);
}
Now in the C++ code the primitive type to draw (here triangles):
glDrawArrays(GL_TRIANGLES, 0, meshList[idx]->getVertexBuffer()->getBufferSize());
And finally the output :
Until here all is ok.
Now I want to generate strands on the sphere as normals. To do the job done I wrote the following geometry shader (the vertex and fragment shaders are the sames).
#version 400
layout(points) in;
layout(line_strip, max_vertices = 2) out;
uniform mat4 MVP;
in vec3 VNormal[];
out vec3 fcolor;
void main(void)
{
float size = 1.0f;
fcolor = vec3(0.0f, 0.0f, 1.0f);
gl_Position = MVP * gl_in[0].gl_Position;
EmitVertex();
fcolor = vec3(1.0f, 1.0f, 0.0f);
gl_Position = MVP * vec4(gl_in[0].gl_Position.xyz + vec3(
VNormal[0].x * size, VNormal[0].y * size, VNormal[0].z * size), 1.0f);
EmitVertex();
EndPrimitive();
}
The input primitive type being points I modified the C++ code to draw the scene :
glDrawArrays(GL_POINTS, 0, meshList[idx]->getVertexBuffer()->getBufferSize());
And the output:
Finally if I want to get a triangle input as input primitive and a line_strip as output primitive in the geometry shader I have the following shader:
#version 400
layout(triangles, invocations = 3) in;
layout(line_strip, max_vertices = 6) out;
uniform mat4 MVP;
in vec3 VNormal[];
out vec3 fcolor;
void main(void)
{
float size = 1.0f;
for (int i = 0; i < 3; i++)
{
fcolor = vec3(0.0f, 0.0f, 1.0f);
gl_Position = MVP * gl_in[i].gl_Position;
EmitVertex();
fcolor = vec3(1.0f, 1.0f, 0.0f);
gl_Position = MVP * vec4(gl_in[0].gl_Position.xyz + vec3(
VNormal[0].x * size, VNormal[0].y * size, VNormal[0].z * size), 1.0f);
EmitVertex();
EndPrimitive();
}
}
And the output is the following :
But my goal is to display in one output the scene (sphere + strands) using the same geometry shader. I'd like to know if it's possible to do this. I don't think so because a geometry shader must have just one type of input primitive and an other one in output and not several types. I want to be sure if it's possible or not.
Who knows, maybe one day there'll be an extension to emit multiple primitive types from a geometry shader, but as you say it can't currently be done.
One alternative might be to draw the normal lines with triangles instead.
Another, but completely useless in this case, might be to use the transform feedback extension to save the vertex shader results and reuse that data with two separate geometry shaders. I only mention this as it's the closest thing I could think of to emit multiple primitive types after the vertex stage.
EDIT
The two geometry shaders for drawing normals confuses me. In the second one, max_vertices = 3, which should be 6 for 3 separate lines and EndPrimitive should also be inside the for-loop so the 3 lines aren't connected. But you've already sorted this out by drawing GL_POINTS in the previous one. Is this intended to be structured for multiple primitive output, if it were supported? (fixed)
Given your geometry reuses many vertices, indices with glDrawElements would be more efficient. Although you'd still want to use glDrawArrays for drawing normal lines to avoid drawing duplicate vertices referenced by an index array.