opengl - Unexpected results with GLSL when using 1D texture buffers -
in following test program, trying render green square (250 x 250) in bottom left corner of screen (500 x 500).
i using 2 buffer textures pass in 2 int arrays (each array of size 500 * 500) fragment shader. arrays populated x (first array) , y (second array) values correspond (x, y) coordinates in screen space (this shown in init() part of code below).
in fragment shader, if current fragment location (in screen space) less 250.0 in both x , y directions, fragment colored green. otherwise, colored red. images shown below.
below full opengl code, along pass-through vertex shader (located in main program) , fragment shader (read in file). in fragment shader, there 3 tests (a, b, , c). tests b , c not working expected. draw green square on bottom right instead of bottom left.
test (correct): output of code works expected (a green square in bottom left corner of screen) when use gl_fragcoord.xy in conditional if check.
test b (incorrect): if use buffer textures along texelfetch retrieve x , y values of current fragment , use in conditional if check, green square gets drawn in lower right hand corner.
test c (incorrect): if forego buffer textures , instead compute current fragment index , use simple mod , division to x, y indices, green square still drawn on bottom right.
any insight appreciated.
i'm using:
ubuntu 12.04.5 lts, 64 bit glgetstring(gl_version) = 4.4.0 nvidia 331.113
main program: mytest.cc
// program modified from: // https://www.opengl.org/discussion_boards/showthread.php/173917-samplerbuffer-example-needed #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <fstream> #define gl_glext_prototypes 1 #include <gl/gl.h> #include <gl/glut.h> using namespace std; static const char vertex_src[] = "void main(void) \n" "{ \n" " gl_position = ftransform(); \n" "} \n"; std::string readfile(const char *filepath) { std::string content; std::ifstream filestream(filepath, std::ios::in); if(!filestream.is_open()) { std::cerr << "could not read file " << filepath << ". file not exist." << std::endl; return ""; } std::string line = ""; while(!filestream.eof()) { std::getline(filestream, line); content.append(line + "\n"); } filestream.close(); return content; } void keybd ( unsigned char, int, int ) { exit ( 0 ) ; } void reshape(int wid, int ht) { glviewport(0, 0, wid, ht); } void showglerror () { glenum err ; while ( (err = glgeterror()) != gl_no_error ) fprintf ( stderr, "opengl error: %s\n", gluerrorstring ( err ) ) ; } void display ( void ) { glmatrixmode(gl_projection); glloadidentity(); glortho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glmatrixmode(gl_modelview); glloadidentity(); glviewport(0, 0, 500, 500); glclearcolor(0.0, 0.0, 0.0, 0.0); glclear(gl_color_buffer_bit); // draw full screen quad. glfloat s = 1.0; glbegin(gl_quads); glvertex3f(0.0f, 0.0f, 0.0f); glvertex3f(s, 0.0f, 0.0f); glvertex3f(s, s, 0.0f); glvertex3f(0.0f, s, 0.0f); glend(); glpopattrib(); glmatrixmode(gl_projection); glpopmatrix(); glmatrixmode(gl_modelview); glpopmatrix(); glutswapbuffers () ; glutpostredisplay () ; } void showshaderinfo ( const char *what, gluint handle ) { int len = 0 ; glgetobjectparameterivarb ( handle, gl_object_info_log_length_arb, &len ) ; if ( len > 0 ) { int truelen ; char *s = new char [ len ] ; glgetinfologarb ( handle, len, &truelen, s ) ; if ( truelen > 0 && s [ 0 ] != '\0' ) fprintf ( stderr, "%s:\n%s\n", what, s ) ; delete [] s ; } } gluint compileshader ( const char *src, glenum type ) { const char *type_str = type == gl_vertex_shader ? "vertex" : "fragment"; gluint handle = glcreateshader( type ) ; glshadersource ( handle, 1, &src, 0 ) ; glcompileshader( handle ) ; glint compiled ; glgetshaderiv( handle, gl_compile_status, &compiled ) ; if ( !compiled ) { showshaderinfo ( type_str, handle ) ; fprintf ( stderr, "failed compile %s shader.\n", type_str ); exit ( 1 ) ; } return handle ; } gluint linkshaders ( gluint vshandle, gluint fshandle ) { glint linked ; gluint handle = glcreateprogram() ; glattachshader ( handle, vshandle ) ; glattachshader ( handle, fshandle ) ; gllinkprogram ( handle ) ; glgetprogramiv ( handle, gl_link_status, & linked ) ; if ( !linked ) { showshaderinfo ( "linking", handle ) ; fprintf ( stderr, "failed link shader program.\n" ) ; exit ( 1 ) ; } return handle ; } void init() { int arraysize = 500 * 500; int *array_x = new int[arraysize]; int *array_y = new int[arraysize]; // populate arrays. (int y = 0; y < 500; y++) { (int x = 0; x < 500; x++) { array_x[(y * 500) + x] = x; array_y[(y * 500) + x] = y; } } const size_t size = sizeof( int ) * arraysize; //// array_x // // generate , fill buffer object gluint buffer; glgenbuffers ( 1, &buffer ); glbindbuffer ( gl_texture_buffer, buffer ); glbufferdata ( gl_texture_buffer, size, array_x, gl_static_draw ); // alloc & fill // generate texture "wrapper" around buffer object gluint tex; glgentextures ( 1, &tex ); glactivetexture( gl_texture0); glbindtexture ( gl_texture_buffer, tex ); gltexbuffer ( gl_texture_buffer, gl_r32i, buffer ); //// array_y // // generate , fill buffer object gluint buffer2; glgenbuffers ( 1, &buffer2 ); glbindbuffer ( gl_texture_buffer, buffer2 ); glbufferdata ( gl_texture_buffer, size, array_y, gl_static_draw ); // alloc & fill // generate texture "wrapper" around buffer object gluint tex2; glgentextures ( 1, &tex2 ); glactivetexture( gl_texture0 + 1); glbindtexture ( gl_texture_buffer, tex2 ); gltexbuffer ( gl_texture_buffer, gl_r32i, buffer2 ); } int main ( int argc, char **argv ) { // init gl context glutinit ( &argc, argv ) ; glutinitdisplaymode ( glut_rgb | glut_depth | glut_double ) ; glutinitwindowsize ( 500, 500 ) ; glutcreatewindow ( "shader test" ) ; glutdisplayfunc ( display ) ; glutkeyboardfunc ( keybd ) ; glutreshapefunc ( reshape ) ; // create buffer object , texture buffer object wrapper init(); // load , compile shaders printf( "compiling vertex shader...\n" ); gluint vshandle = compileshader ( vertex_src, gl_vertex_shader ); printf( "compiling fragment shader...\n" ); gluint fshandle = compileshader ( (readfile("mytest.glsl")).c_str(), gl_fragment_shader); // link shaders printf( "linking...\n" ); gluint handle = linkshaders ( vshandle, fshandle ) ; // activate shader gluseprogram( handle ) ; // populate uniform // (buffer texture on texunit 0) gluniform1i( glgetuniformlocation( handle, "tex" ), 0 ); // (buffer2 texture on texunit 1) gluniform1i( glgetuniformlocation( handle, "tex2" ), 1 ); // draw shader glutmainloop () ; return 0 ; }
fragment shader: mytest.glsl
#version 130 #extension gl_ext_gpu_shader4: enable uniform isamplerbuffer tex; uniform isamplerbuffer tex2; void main(void) { int width = 500; // current screen index going work on. // (used test b , test c below.) int index = int((gl_fragcoord.y * float(width)) + gl_fragcoord.x); // test a: works expected. /*if (gl_fragcoord.x < 250.0 && gl_fragcoord.y < 250.0) { gl_fragcolor = vec4(0.0, 1.0, 0.0, 1.0); } else { gl_fragcolor = vec4(1.0, 0.0, 0.0, 1.0); }*/ // test b: use buffer textures value of arrays @ // index computed above. not work expected. int x_i = int(texelfetch(tex, index).r); int y_i = int(texelfetch(tex2, index).r); if (x_i < 250 && y_i < 250) { gl_fragcolor = vec4(0.0, 1.0, 0.0, 1.0); } else { gl_fragcolor = vec4(1.0, 0.0, 0.0, 1.0); } // test c: x, y screen space coordinates based on index // computed above. not work expected. /*int x_i = index % 500; int y_i = index / 500; if (x_i < 250 && y_i < 250) { gl_fragcolor = vec4(0.0, 1.0, 0.0, 1.0); } else { gl_fragcolor = vec4(1.0, 0.0, 0.0, 1.0); }*/ }
result of test a test http://www.shilpigupta.com/stack/testa.png
result of test b , test c (also notice green line artifact @ top right of image.) test b , test c http://www.shilpigupta.com/stack/testb.png
the mistake how calculate index:
int index = int((gl_fragcoord.y * float(width)) + gl_fragcoord.x);
this code work if fractional part of gl_fragcoord
zero. note opengl's window space defined in such way pixel centers lie @ half-integer positions ("at comma 5"). without mutlisampling or other fancy settings, fragment shader invoked pixel centers, of gl_fragcoord
values @ .5, results in shift in 0.5 * width pixels observing. (in case b , c, green area isn't square, because 1 line in height missing @ top, because start bottom line @ x_i=250).
the correct approach is
int index = int(gl_fragcoord.y) * width + int(gl_fragcoord.x);
Comments
Post a Comment