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.
0
votes
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
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.