Frage

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 :

enter image description here

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:

enter image description here

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 :

enter image description here

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.

War es hilfreich?

Lösung

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top