1
$\begingroup$

I have a set of points, which I triangulate to a Delaunay graph to make a mesh.

Every mesh vertex has a unique colour, and I can render it without any problem. But I want Voronoi rendering to be possible too. Ideally, I want to make a shader which computes the distance from every vertex, and colours the vertex fragments with the colour of the nearest vertex, but somehow I get the wrong result.

This is the GLSL shader I'm using:

Vertex:

#version 330

layout (location=0) in vec2 position;
layout (location=1) in vec3 inColour;

flat out vec3 col_in;

void main()
{
    gl_Position = vec4(position, 0.0, 1.0);

    col_in = inColour;
}

Geometry:

#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

uniform vec2 window_size;

flat in vec3 col_in[];

out vec4 vertex_a;
out vec4 vertex_b;
out vec4 vertex_c;

flat out vec3 colour_a;
flat out vec3 colour_b;
flat out vec3 colour_c;

void main() {    
    vertex_a = (gl_in[0].gl_Position);
    vertex_b = (gl_in[1].gl_Position);
    vertex_c = (gl_in[2].gl_Position);

    gl_Position = vertex_a; 
    colour_a = col_in[0];
    EmitVertex();

    gl_Position = vertex_b;
    colour_b = col_in[1];
    EmitVertex();

    gl_Position = vertex_c;
    colour_c = col_in[2];
    EmitVertex();
    
    EndPrimitive();
} 

Fragment:

#version 330 core

uniform vec2 window_size;

in vec4 vertex_a;
in vec4 vertex_b;
in vec4 vertex_c;

flat in vec3 colour_a;
flat in vec3 colour_b;
flat in vec3 colour_c;

out vec4 fragColor;

void main()
{   
    vec2 uv = (gl_FragCoord.xy / window_size) - vec2(0.5);

    float da = distance(vertex_a * 0.5, vec4(uv, 0.0, 0.0));
    float db = distance(vertex_b * 0.5, vec4(uv, 0.0, 0.0));
    float dc = distance(vertex_c * 0.5, vec4(uv, 0.0, 0.0));

    if(da < db && da < dc){
        fragColor = vec4(colour_a, 1.0);
    } else if (db < da && db < dc){
        fragColor = vec4(colour_b, 1.0);
    } else if(dc < da && dc < db) {
        fragColor = vec4(colour_c, 1.0);
    } else {
        fragColor = vec4(1.0);
    }
}  

This is the result:

Result

Wireframe:

Result - Wireframe rendered

My question is: why is my result not a Voronoi diagram? Does it depend on the shader, or maybe the triangulation is wrong? Is this the best way to do this? If not, what should I do?

$\endgroup$

1 Answer 1

2
$\begingroup$

Your geometry shader is broken. Every time you do EmitVertex, all of the out variables acquire unspecified values (ie: implementations aren't required to preserve those values). So you must reset them for every vertex.

That being said, your algorithm is unnecessarily complex. It'd be way easier to just let your GPU's depth test do it. For each vertex in your triangulation, draw a cone with the vertex (in 2D) where the tip of the cone is, and with the tip pointing into the camera using an orthographic projection. The cones need to be pretty wide. Each cone should have its own color.

Where two cones intersect will define the place where two vertices are equal-distances to each other.

$\endgroup$
3
  • $\begingroup$ Oh, that's actually pretty clever. Is that efficient? $\endgroup$ Jan 21, 2023 at 20:15
  • $\begingroup$ @FrankSoll: Neither method is going to stress even an integrated GPU. The main issue with the cone method is that its accuracy depends on how good of a cone you render. If you start zooming in, you need to use a finer cone. $\endgroup$ Jan 21, 2023 at 20:22
  • $\begingroup$ ok, I'll create one cone and use istancing I guess. Thanks. $\endgroup$ Jan 21, 2023 at 20:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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