Single-pass wireframe issue
Asked Answered
T

1

2

I am trying to implement single-pass wireframe, but I have got couple of issues in the process.

Question #1

For some reasons I get only wireframe without (like with glPolygoneMode - lines) filled geometry after my geometry shader worked.

  wireframe)

But if I disable the geometry shader I get my geometry:

  filled polygons

What I really like to achieve is both geometry and its wireframe.

Question #2

Actually, my primitives are triangle strips. I use them to avoid using on quads to improve performance. How can I skip edges of wireframe while drawing? (I've already saw post how it can be done, but it is still not to clear for me.)

Here are my shaders:

Vertex shader:

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

layout(location = 0) in vec3 in_Position;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 og_viewportTransformationMatrix;

out vec2 windowPosition;

vec4 og_ClipToWindowCoordinates(vec4 v, mat4 viewportTransformationMatrix);

void main()                     
{
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);

    windowPosition = og_ClipToWindowCoordinates(gl_Position, og_viewportTransformationMatrix).xy;
}

vec4 og_ClipToWindowCoordinates(vec4 v, mat4 viewportTransformationMatrix)
{
    v.xyz /= v.w;                                                  // normalized device coordinates
    v.xyz = (viewportTransformationMatrix * vec4(v.xyz, 1.0)).xyz; // window coordinates
    return v;
}

Geomerty shader:

#version 330 
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

in vec2 windowPosition[];
noperspective out vec3 distanceToEdges;

float og_distanceToLine(vec2 f, vec2 p0, vec2 p1);

void main()
{
    vec2 p0 = windowPosition[0];
    vec2 p1 = windowPosition[1];
    vec2 p2 = windowPosition[2];

    gl_Position = gl_in[0].gl_Position;
    distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 0.0);
    EmitVertex();

    gl_Position = gl_in[1].gl_Position;
    distanceToEdges = vec3(0.0, og_distanceToLine(p1, p2, p0), 0.0);
    EmitVertex();

    gl_Position = gl_in[2].gl_Position;
    distanceToEdges = vec3(0.0, 0.0, og_distanceToLine(p2, p0, p1));
    EmitVertex();
}

float og_distanceToLine(vec2 f, vec2 p0, vec2 p1)
{
    vec2 l = f - p0;
    vec2 d = p1 - p0;

    //
    // Closed point on line to f
    //
    vec2 p = p0 + (d * (dot(l, d) / dot(d, d)));
    return distance(f, p);
}

Fragment shader:

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

uniform float u_halfLineWidth;
uniform vec3 u_color;

noperspective in vec3 distanceToEdges;
out vec4 fragmentColor;

void main()
{
    float d = min(distanceToEdges.x, min(distanceToEdges.y, distanceToEdges.z));

    if (d > u_halfLineWidth + 1.0)
    {
        discard;
    }

    d = clamp(d - (u_halfLineWidth - 1.0), 0.0, 2.0);
    fragmentColor = vec4(u_color, exp2(-2.0 * d * d));
}

Help me to figure out where I've got it wrong.

Update:

I have updated Fragment shaderand Geometry shader as mention Andon M. Coleman in his answer, but problem described in Question 2 still not solved.

enter image description here

Update 2

I have just make some little edits in fragmet shader and that solves my problem.

Update fragment shader

#version 330
//
// (C) Copyright 2010 Patrick Cozzi and Deron Ohlarik
//
// Distributed under the MIT License.
// See License.txt or http://www.opensource.org/licenses/mit-license.php.
//

uniform float u_halfLineWidth;
uniform vec3 u_color;

noperspective in vec3 distanceToEdges;
out vec4 fragmentColor;

void main()
{
    float d = min(distanceToEdges.y, max(distanceToEdges.x, distanceToEdges.z));

    if (d > u_halfLineWidth + 1.0)
    {
        fragmentColor =  vec4(u_color, 1);
        return;
    }

    fragmentColor = vec4(vec3(0,0,0), 1);
}
Therefor answered 15/5, 2014 at 17:21 Comment(0)
K
4

Your first problem is related to your use of discard.

At present, you are discarding the fragments that do not lie within an appropriate distance from your wireframe in the fragment shader. That is incorrect behavior, this will only draw the wireframe.

What you need to do is actually replace the discard with a different color.

if (d > u_halfLineWidth + 1.0)
{
    //discard; // DO NOT DO THIS

    //
    // Instead, do this
    //
    fragmentColor = vec4 (0.0, 0.0, 0.0, 1.0);
    return;
}

Granted this is going to produce a black filled mesh, but if you used the color u_color, the filled part of the mesh would be indistinguishable from the wireframe. Ultimately you probably want to define a per-vertex color that is separate from the wireframe color, but it is up to you to figure out how to do that.


As for Question #2, that is solved by tweaking the edge distances:

The idea in the article you linked to was that for each triangle your geometry shader emits, it should write a distance to the opposite edge for each vertex. If you know that one of the edges in your triangle is an interior edge and thus should not be included in the wireframe, you should set the distance for the vertex opposite that edge far enough away that it never interpolates to 0 (or whatever width you chose for the wireframe).

The following modifications to your GS will remove the interior edges of the triangle strip:

void main()
{
    vec2 p0 = windowPosition[0];
    vec2 p1 = windowPosition[1];
    vec2 p2 = windowPosition[2];

    // Alternate between using the first and last vertex as the one opposite the
    // interior edge based on primitive ID.
    bool strip_flip = (bool (gl_PrimitiveIDIn & 1));

    gl_Position = gl_in[0].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 0.0);
    else
      distanceToEdges = vec3(og_distanceToLine(p0, p1, p2), 0.0, 99999.0);
    EmitVertex();

    gl_Position = gl_in[1].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(99999.0, og_distanceToLine(p1, p2, p0), 0.0);
    else
      distanceToEdges = vec3(0.0,     og_distanceToLine(p1, p2, p0), 99999.0);
    EmitVertex();

    gl_Position = gl_in[2].gl_Position;
    if (strip_flip)
      distanceToEdges = vec3(99999.0, 0.0, og_distanceToLine(p2, p0, p1));
    else
      distanceToEdges = vec3(    0.0, 0.0, og_distanceToLine(p2, p0, p1));
    EmitVertex();
}

This works by alternating between first/last vertex serving as the vertex opposite the interior edge that the strip inserted. For each odd triangle, the interior edge is opposite the first vertex, for each even triangle it is opposite the last. This is fundamentally how triangle strips operate, the winding is reversed on each successive triangle and that makes it easy to identify which edge to remove.

To ensure that distanceToEdges never interpolates to anything less than or equal to u_HalfLineWidth + 1.0 in the direction of this edge, said coordinates are pushed from their normal 0.0 value to 99999.0.

Thus, if you refer to the dashed edge in the following diagram, Q is 99999.0:

        Edge Diagram

Imagine a triangle mirrored across that dashed edge and then you should have a pretty good idea of what the Geometry Shader is doing.

Kropotkin answered 15/5, 2014 at 17:37 Comment(8)
Really, it solves part of my problem. Can you recommend anything for second part of question?Therefor
@frankie: Yes, sorry I had to edit your question a little bit before I even noticed it was two-part. I think my new addition to the answer may help to explain things a little bit better.Kropotkin
I made single edit at geometry shader. As your recommend I place gl_Position = gl_in[0].gl_Position; distanceToEdges = vec3(999999999999999999.0, 0.0, 0.0); EmitVertex(); But this did not remove undesirable edge.Therefor
Not it doesn't remove any edge. Can you place here some really small piece of code that tests gl_PrimitiveIDIn?Therefor
Provided code cause compile time error. Unfortunately I don't know any facilities to detect errors in code :(Therefor
@frankie: Look into glGetShaderInfoLog (...), but I think the problem may actually be implicit conversion to bool. There is no such conversion defined for int to bool, this conversion requires a constructor, so the expression may need to be: bool odd = !(bool (gl_PrimitiveIDIn & 1));Kropotkin
@frankie: Updated code should work, I was solving the wrong problem.Kropotkin
I edit my shaders as you post. But still it is not desirable result. :(Therefor

© 2022 - 2024 — McMap. All rights reserved.