0
votes

I would like to perform a per-pixel operation on every instance of a mesh. I found a variable called gl_FragCoord but it seems that it's coordinates are the SCREEN coordinates. I would like to have access to the LOCAL coordinates so that I could make changes that would affect every mesh independently. I would like to have coordinates where for example the (0.0, 0.0) coordinates are the top-left corner of the fragment and (1.0, 1.0) are the bottom-right ones.

3
The canonical projection matrix in OpenGL will produce (0.0, 0.0) as the bottom-left corner. If you want that to be the top-left you need to flip the Y-axis, but be aware that this will change the handedness of your projection and you will need to do other things like compensate for winding orders, etc.Andon M. Coleman

3 Answers

1
votes

You can pass the viewport as a uniform and divide your frag coord X by the viewport W and the Y frag coord by the viewport H

1
votes

Thanks for your support and ideas, what I needed was to pass the LOCAL position of the vertex via vertex shader to the fragment shader. We can do it without any additional computations as it is a value that is know to the vertex shader. I still don't have what I exactly wanted in the beginning but now I know more about how I can use the fragment shader to do the effects I wanted :).

0
votes

Use barycentric coordinates and an additional vertex attribute to construct a triangle-local coordinate system:

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <vector>
using namespace std;

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp> 
#include <glm/gtx/transform.hpp>
using namespace glm;

void CheckStatus( GLuint obj )
{
    GLint status = GL_FALSE;
    if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
    if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
    if( status == GL_TRUE ) return;
    GLchar log[ 1 << 16 ] = { 0 };
    if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
    if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
    std::cerr << log << std::endl;
    exit( -1 );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

GLuint LoadProgram( const char* vert, const char* geom, const char* frag )
{
    GLuint prog = glCreateProgram();
    if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
    if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
    if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog );
    return prog;
}

#define GLSL(version, shader) "#version " #version "\n" #shader

const char* vert = GLSL
(
    120,
    uniform mat4 u_projection;
    uniform mat4 u_modelview;

    attribute vec3 a_pos;
    attribute vec3 a_bc;

    varying vec3 v_bc;

    void main()
    {
        v_bc = a_bc;
        gl_Position = u_projection * u_modelview * vec4( a_pos, 1.0 );
    }
);

const char* frag = GLSL
(
    120,
    varying vec3 v_bc;
    void main()
    {
        gl_FragColor = vec4( v_bc, 1.0 );
    }
);

struct Vertex
{
    Vertex( const vec3& pos, const vec3& bc )
        : pos( pos )
        , bc( bc )
    {}
    vec3 pos;
    vec3 bc;
};

void AddTriangle( const vec3& p1, const vec3& p2, const vec3& p3, vector< Vertex >& verts )
{
    verts.push_back( Vertex( p1, vec3( 1, 0, 0 ) ) );
    verts.push_back( Vertex( p2, vec3( 0, 1, 0 ) ) );
    verts.push_back( Vertex( p3, vec3( 0, 0, 1 ) ) );
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    double w = glutGet( GLUT_WINDOW_WIDTH );
    double h = glutGet( GLUT_WINDOW_HEIGHT );
    double ar = w / h;
    mat4 projection = glm::ortho< float >( -2 * ar, 2 * ar, -2.0, 2.0, -1.0, 1.0 );

    mat4 modelview = mat4( 1.0 );

    // prepare to render
    static GLuint prog = LoadProgram( vert, NULL, frag );
    glUseProgram( prog );

    GLint proj = glGetUniformLocation( prog, "u_projection" );
    glUniformMatrix4fv( proj, 1, GL_FALSE, glm::value_ptr( projection ) );

    GLint model = glGetUniformLocation( prog, "u_modelview" );
    glUniformMatrix4fv( model, 1, GL_FALSE, glm::value_ptr( modelview) );

    vector< Vertex > verts;
    AddTriangle
        (
        vec3( 0, 0, 0 ),
        vec3( 1, 0, 0 ),
        vec3( 1, 1, 0 ),
        verts
        );

    GLint pos = glGetAttribLocation( prog, "a_pos" );
    glVertexAttribPointer( pos, 3, GL_FLOAT, GL_FALSE, sizeof( Vertex ), &verts[0].pos );
    glEnableVertexAttribArray( pos );

    GLint bc = glGetAttribLocation( prog, "a_bc" );
    glVertexAttribPointer( bc, 3, GL_FLOAT, GL_FALSE, sizeof( Vertex ), &verts[0].bc );
    glEnableVertexAttribArray( bc );

    glDrawArrays( GL_TRIANGLES, 0, verts.size() );

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    glutInit( &argc, argv );
    glutSetOption( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );
    glewInit();

    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}

If v_bc == (1,0,0) then your fragment lies on the first vertex.

If v_bc == (0,1,0) then your fragment lies on the second vertex.

If v_bc == (0,0,1) then your fragment lies on the third vertex.