c++openglglslsfmlgeometry-shader

How to pass center of each primitive to fragment shader?


In the following example I would like to manually create points (x, y, angle) from SFML then fill a circle around each point. The angle will be used later, for now I use it for debugging.

  1. SFML draws 2 points
  2. Vertex shader convert points to -1..1 range
  3. Geometry shader creates squares at each point position and pass the center to fragment shader
  4. Fragment shader would pain a circle within each square.

From my understanding, in the geometry shader I emit center which is the center coordinates of each primitive. From computing the distance from this center I would be able to paint a circle in each primitive from the fragment shader.

In the picture below I notice the center is only set once and I don't understand why.

enter image description here

SFML App

#include <iostream>
#include <SFML/Graphics.hpp>
#include <vector>
#include <GL/glew.h>
#include <random>

#define WIDTH 800
int main() {
    sf::RenderWindow window(sf::VideoMode(WIDTH, WIDTH), "Test");

    sf::Shader shader;
    shader.loadFromFile("shader.vert", "shader.geom", "shader.frag");
    sf::Transform matrix = sf::Transform::Identity;
    matrix.scale(1.0 / WIDTH, 1.0 / WIDTH);
    sf::Glsl::Mat4 projectionViewMatrix = matrix;

    shader.setUniform("projectionViewMatrix", projectionViewMatrix);

    std::vector<GLfloat> vertices;
    vertices.push_back(400.0); vertices.push_back(400.0); vertices.push_back(0.0);
    vertices.push_back(400.0); vertices.push_back(-400.0); vertices.push_back(0.25);
    vertices.push_back(-400.0); vertices.push_back(-400.0); vertices.push_back(0.5);
    vertices.push_back(-400.0); vertices.push_back(400.0); vertices.push_back(0.75);

    while (window.isOpen()) {
        sf::Event currEvent;
        while (window.pollEvent(currEvent)) {
            switch (currEvent.type) {
            case(sf::Event::Closed):
                window.close(); break;
            }
        }
        window.clear(sf::Color::Black);

        glVertexPointer(3, GL_FLOAT, 0, vertices.data());
        glEnableClientState(GL_VERTEX_ARRAY);
        glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
        glDisableClientState(GL_VERTEX_ARRAY);
        sf::Shader::bind(&shader);
        window.display();
    }
}

Vertex Shader

#version 150
in vec3 position;

out vec3 pass_colour;
out float angle;

uniform mat4 projectionViewMatrix;

void main(void) {
    gl_Position = projectionViewMatrix * vec4(position.xy, 0.0 ,1.0);
    angle = position.z;
    pass_colour = vec3(1.0);
}

Geometry shader

#version 150

layout (points) in;
layout (triangle_strip, max_vertices = 6) out;

in vec3 pass_colour[];
in float angle[];
out vec3 finalColour;
out vec4 centerPosition;

uniform mat4 projectionViewMatrix;

vec3 hsv2rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

void createVertex(vec3 offset, vec3 colour, float z = 0.0) {
    vec4 actualOffset = vec4(offset, z);
    vec4 worldPosition = gl_in[0].gl_Position + actualOffset;
    gl_Position = worldPosition;
    finalColour = colour;
    vec4 pointPosition = gl_in[0].gl_Position;
    centerPosition = pointPosition;
    EmitVertex();
}
    
void main(void) {
    float corner = 0.3;
    vec3 colour = hsv2rgb(vec3(angle[0], 1.0, 1.0));
    createVertex(vec3(-corner, -corner, 0.0), colour, 0.0);
    createVertex(vec3(corner, -corner, 0.0), colour, 0.0);
    createVertex(vec3(-corner, corner, 0.0), colour, 0.0);
    createVertex(vec3(corner, corner, 0.0), colour, 0.0);
    createVertex(vec3(corner, -corner, 0.0), colour, 0.0);
    createVertex(vec3(-corner, corner, 0.0), colour, 0.0);

    EndPrimitive();
}

Fragment shader

#version 150
in vec3 finalColour;
in vec4 centerPosition;

out vec4 out_Colour;

void main(void){
    vec2 resolution = vec2(800.0/2.0, 800.0/2.0);
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    vec2 uvc = (centerPosition.xy + vec2(1.0)) / 2.0;

    float dist = length(uv - uvc);
    out_Colour = vec4(finalColour * dist, 0.8);
}

Solution

  • I still don't explain everything, but it works with this fragment:

    #version 150
    in vec4 finalColour;
    in vec4 centerPosition;
    
    out vec4 out_Colour;
    
    void main(void){
        vec2 resolution = vec2(800.0/2.0, 800.0/2.0);
        vec2 uv = gl_FragCoord.xy / resolution.xy;
        vec2 p = vec2(1.0, 1.0) + centerPosition.xy;
        vec2 uvc = p;
    
        float dist = length(uv - uvc);
        float col = 1.0 - smoothstep(0.0, 0.1, dist);
        out_Colour = vec4(finalColour.rgb * col, 1.0);
    }
    

    enter image description here