Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: Wave/Ripple Fragment Shader Working but With Strange Side-Effects

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Junior Member Newbie
    Join Date
    Oct 2017
    Posts
    4

    Angry Wave/Ripple Fragment Shader Working but With Strange Side-Effects

    Greetings:

    Hopefully this is the right place to post for this problem. I'm not sure if the problem is OpenGL or the shader(s), which is why I'm here.

    Background
    I want to incorporate a ShaderToy ripple/wave effect into my main C++ windows program:
    https://www.shadertoy.com/view/4dK3Ww

    I slightly modified the fragment shader code to work under C++ with glew/freeglut and also removed mouse and image related code (image not needed for testing the problem). I'm using a basic "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" vertex shader.

    I borrowed and modified / simplified a multi-pass shader tester program in C++ from here:
    https://github.com/yasuohasegawa/Ope...-Shader-Sample

    I've attached all the code I am using. I am using the latest freeglut and glew. I'm developing / running this on Windows 8.1 x64.

    Problem
    The shader shows up and works under the ShaderTest program but has some strangeness to it. I'm not sure if this is a problem with my OpenGL approach or some kind of problem with running under OpenGL, rather than WebGL in the browser. The browser version runs fine for me.

    Strangeness Notes
    The shader effect creates a ripple and from that ripple the waves push out. In the WebGL version in the browser, this works perfectly. The ripple and wave generation will go on forever.

    Under the C++ test program, ripples are created, but also create ripple waves inside existing ripples (inner ripples), eventually creating an infinite loop of waves, which causes "black holes" to be generated over time. The black holes will consume the screen as time passes.

    When the shader runs in a full-screen quad, the "waves" will bounce off of the joined-triangles seem (a quad is two triangles joined).

    When the shader runs in an oversized triangle, the waves work correctly, but the inside ripples problem still happens.

    What I've Tried
    I've been at this problem for about a week now, so it's hard to detail everything I've tried. ShaderToy describes their buffer with linear 32-bit floating points. It seems that using that format for textures is correct.

    If I try using 16-bit float, or RBGA with unsigned byte, the side-effects get lesser and lesser, but never go away fully. The color quality of the effect obviously goes to crap, though, so it doesn't really help.

    With regards to textures and FBOs, I've tried many different approaches. Dual-FBOs, dual color-attachments with a single FBO, etc. Nothing seems to work. I have to use at least the one FBO on the buffer channel, it seems.

    Summary
    The two problems I'm trying to solve are:
    1: inner ripple / infinite waves
    2: quad seem reflection

    My guesses: projection or shader coordinates precision issue (or both).

    I've attached the two source files and the vert/frag shaders. Screenshots in 2nd post.

    Any help much appreciated.

    Thanks!

    ShaderTest.cpp.txt
    ShaderTest.h.txt
    shader.vert.txt
    ripples1_buffer.frag.txt
    ripples1_image.frag.txt
    Last edited by EloStorm; 10-05-2017 at 08:08 PM.

  2. #2
    Junior Member Newbie
    Join Date
    Oct 2017
    Posts
    4
    Working from ShaderToy (no texture)
    Click image for larger version. 

Name:	working.jpg 
Views:	9 
Size:	19.3 KB 
ID:	2504

    C++ Test: Oversized Triangle (no seem reflection)
    Click image for larger version. 

Name:	oversized_triangle_approach.jpg 
Views:	10 
Size:	36.3 KB 
ID:	2505

    C++ Test: Quad (triangles seem reflection)
    Click image for larger version. 

Name:	quad_approach.jpg 
Views:	11 
Size:	44.7 KB 
ID:	2506

    ShaderTest.cpp
    Code :
    //
    //  code based on https://github.com/yasuohasegawa/OpenGL-Multipass-Shader-Sample 
    //
     
    #include <GL/glew.h>
    #include <GL/glut.h>
    #include "ShaderTest.h"
     
    #define TIMER_MS 25
    #define CYCLE 1000.0f
    #define APP_WIDTH  640
    #define APP_HEIGHT 360
     
    static GLuint _s_program1 = 0;
    static GLuint _s_program2 = 0;
    static GLuint _s_fb = 0;
    static GLuint _s_texBuffer = 0;
    static GLuint _s_texImage = 0;
    static GLuint _s_frame = 0;
     
    void init(){
    	glewInit();
    	_s_program1 = loadShader("./shaders/shader.vert","./shaders/ripples1_buffer.frag");
    	_s_program2 = loadShader("./shaders/shader.vert","./shaders/ripples1_image.frag");
     
        // buffer texture
        glGenTextures(1, &_s_texBuffer);
        glBindTexture(GL_TEXTURE_2D, _s_texBuffer);
    		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glBindTexture(GL_TEXTURE_2D, 0);
     
        // image buffer
        glGenTextures(1, &_s_texImage);
        glBindTexture(GL_TEXTURE_2D, _s_texImage);
    		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    		//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glBindTexture(GL_TEXTURE_2D, 0);
     
        // fbo
        glGenFramebuffers(1, &_s_fb);
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
    		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _s_texBuffer, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
     
    void draw_quad(){
    	glBegin(GL_QUADS);
    		glTexCoord2f(0.0, 0.0); glVertex2i(0,			0);
    		glTexCoord2f(1.0, 0.0); glVertex2i(APP_WIDTH,	0);
    		glTexCoord2f(1.0, 1.0); glVertex2i(APP_WIDTH,	APP_HEIGHT);
    		glTexCoord2f(0.0, 1.0); glVertex2i(0,			APP_HEIGHT);
    	glEnd();
    }
     
    void draw_triangle(){
    	glBegin(GL_TRIANGLES);
    		glVertex2i(0,			0);
    		glVertex2i(0,			APP_HEIGHT);
    		glVertex2i(APP_WIDTH,	APP_HEIGHT);
    	glEnd();
    }
     
    void update_shader(){
    	bool draw_oversized_triangle_instead_of_quad = true;
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    	glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(0, 0, APP_WIDTH, APP_HEIGHT);
        glOrtho(0, APP_WIDTH, 0, APP_HEIGHT, -1, 1);
     
    	if (draw_oversized_triangle_instead_of_quad){
    		glTranslatef(0.0, -APP_HEIGHT, 0.0);
    		glScalef(2.0, 2.0, 0.0);
    	}
     
    	// buffer
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
    		glActiveTexture(GL_TEXTURE0);
    		glBindTexture(GL_TEXTURE_2D, _s_texBuffer);
     
    		glUseProgram(_s_program1);
    		glUniform2f(glGetUniformLocation(_s_program1, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
    		glUniform1f(glGetUniformLocation(_s_program1, "iTime"), (float) glutGet(GLUT_ELAPSED_TIME) / CYCLE);
    		glUniform1i(glGetUniformLocation(_s_program1, "iFrame"), _s_frame);
    		glUniform1i(glGetUniformLocation(_s_program1, "iChannel0"), 0);
     
    		if (draw_oversized_triangle_instead_of_quad)
    			 draw_triangle();
    		else draw_quad();
     
    		glBindTexture(GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
    	// image
    	glActiveTexture(GL_TEXTURE0);
    	glBindTexture(GL_TEXTURE_2D, _s_texBuffer);
    	glActiveTexture(GL_TEXTURE1);
    	glBindTexture(GL_TEXTURE_2D, _s_texImage);
     
    		glUseProgram(_s_program2);    
    		glUniform2f(glGetUniformLocation(_s_program2, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
    		glUniform1i(glGetUniformLocation(_s_program2, "iChannel0"), 0);
    		glUniform1i(glGetUniformLocation(_s_program2, "iChannel1"), 1);
     
    		if (draw_oversized_triangle_instead_of_quad)
    			 draw_triangle();
    		else draw_quad();
     
    		glUseProgram(0);
    	glBindTexture(GL_TEXTURE_2D, 0);
    	glFlush();
     
    	_s_frame++;
    }
     
    void timer(int){
    	update_shader();
        glutTimerFunc(TIMER_MS, timer, 0);
    }
     
    void display(){}
    int main(int argc, char *argv[]){
        glutInit(&argc, argv);
        glutInitWindowPosition(0, 0);
        glutInitWindowSize(APP_WIDTH, APP_HEIGHT);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
        glutCreateWindow(argv[0]);
        glutDisplayFunc(display);
    	glutTimerFunc(TIMER_MS, timer, 0);
        init();
        glutMainLoop();
        return 0;
    }

    ShaderTest.h
    Code :
    //
    //  code based on https://github.com/yasuohasegawa/OpenGL-Multipass-Shader-Sample 
    //
     
    #include <fstream>
    #include <iostream>
     
    int read_shader_file(GLuint shader, const char *name){
        int ret;
     
        std::ifstream file(name, std::ios::binary);
        if (file.fail()) {
            std::cerr << "Can't open file: " << name << std::endl;
            ret = -1;
        } else {
            file.seekg(0L, std::ios::end);
            GLsizei length = file.tellg();
     
            const GLchar *source = new GLchar[length];
     
            file.seekg(0L, std::ios::beg);
            file.read((char *)source, length);
     
            if (file.bad()) {
                std::cerr << "Could not read file: " << name << std::endl;
                ret = -1;
            } else {            
                glShaderSource(shader, 1, &source, &length);
                ret = 0;
            }
     
            delete[] source;
        }
     
        return ret;
    }
     
    void print_shader_info(GLuint shader){
        GLsizei bufSize;
     
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &bufSize);
     
        if (bufSize > 1) {
            GLchar *infoLog;
     
            infoLog = (GLchar *)malloc(bufSize);
            if (infoLog != NULL) {
                GLsizei length;
     
                glGetShaderInfoLog(shader, bufSize, &length, infoLog);
                fprintf(stderr, "InfoLog:\n%s\n\n", infoLog);
                free(infoLog);
            } else fprintf(stderr, "Could not allocate InfoLog buffer.\n");
        }
    }
     
    void print_program_info(GLuint program){
        GLsizei bufSize;
     
        glGetProgramiv(program, GL_INFO_LOG_LENGTH , &bufSize);
     
        if (bufSize > 1) {
            GLchar *infoLog;
     
            infoLog = (GLchar *)malloc(bufSize);
            if (infoLog != NULL) {
                GLsizei length;
     
                glGetProgramInfoLog(program, bufSize, &length, infoLog);
                fprintf(stderr, "InfoLog:\n%s\n\n", infoLog);
                free(infoLog);
            } else fprintf(stderr, "Could not allocate InfoLog buffer.\n");
        }
    }
     
    GLuint loadShader(const char *vert, const char *frag){
        GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
        GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
     
        if (read_shader_file(vertShader, vert)) exit(1);
        if (read_shader_file(fragShader, frag)) exit(1);
     
        GLint compiled, linked;
     
        glCompileShader(vertShader);
        glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compiled);
        print_shader_info(vertShader);
        if (compiled == GL_FALSE) {
            fprintf(stderr, "Compile error in vertex shader.\n");
            exit(1);
        }
     
        glCompileShader(fragShader);
        glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compiled);
        print_shader_info(fragShader);
        if (compiled == GL_FALSE) {
            fprintf(stderr, "Compile error in fragment shader.\n");
            exit(1);
        }
     
        GLuint gl2Program = glCreateProgram();
     
        glAttachShader(gl2Program, vertShader);
        glAttachShader(gl2Program, fragShader);
     
        glDeleteShader(vertShader);
        glDeleteShader(fragShader);
     
        glLinkProgram(gl2Program);
        glGetProgramiv(gl2Program, GL_LINK_STATUS, &linked);
        print_program_info(gl2Program);
        if (linked == GL_FALSE) {
            fprintf(stderr, "Link error.\n");
            exit(1);
        }
     
        return gl2Program;
    }

    shader.vert
    Code :
    void main(){
      gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    }

    ripples1_buffer.frag
    Code :
    // https://www.shadertoy.com/view/4dK3Ww
    #version 130
     
    uniform vec2         iViewportResolution;
    uniform float        iTime;               // shader playback time (in seconds)
    uniform int          iFrame;              // shader playback frame
    //uniform samplerXX  iChannel0..3;        // input channel. XX = 2D/Cube
    uniform sampler2D    iChannel0;
     
    void main(){
       vec3 e = vec3(vec2(1.)/iViewportResolution.xy,0.);
       vec2 q = gl_FragCoord.xy/iViewportResolution.xy;
     
       vec4 c = texture(iChannel0, q);
     
       float p11 = c.y;
     
       float p10 = texture(iChannel0, q-e.zy).x;
       float p01 = texture(iChannel0, q-e.xz).x;
       float p21 = texture(iChannel0, q+e.xz).x;
       float p12 = texture(iChannel0, q+e.zy).x;
     
       float d = 0.;
     
       // --------------------
       // MOUSE CODE REMOVED
       // --------------------
       //if (iTime >= 2.5 && iTime < 3.0){
          // Simulate rain drops
          float t = iTime*2.;
          vec2 pos = fract(floor(t)*vec2(0.456665,0.708618))*iViewportResolution.xy;
          float amp = 1.-step(.05,fract(t));
          d = -amp*smoothstep(2.5,.5,length(pos - gl_FragCoord.xy));
       //}
     
       // The actual propagation:
       d += -(p11-.5)*2. + (p10 + p01 + p21 + p12 - 2.);
       d *= .99; // dampening
       d *= float(iFrame>=50); // clear the buffer at iFrame < 2
       d = d*.5 + .5;
     
       // Put previous state as "y":
       gl_FragColor = vec4(d, c.x, 0, 0);
    }

    ripples1_image.frag
    Code :
    // https://www.shadertoy.com/view/4dK3Ww
    #version 130
     
    uniform vec2        iViewportResolution;
    uniform vec2        iImageResolution;
    //uniform samplerXX iChannel0..3;       // input channel. XX = 2D/Cube
    uniform sampler2D   iChannel0;
    uniform sampler2D   iChannel1;
     
     
    void main(){
        vec2 q = gl_FragCoord.xy/iViewportResolution.xy;
     
        // -----------------------
        // FORCING NON-TEXTURED VERSION
        // -----------------------
        float h = texture(iChannel0, q).x;
        float sh = 1.35 - h*2.;
        vec3 c =
           vec3(exp(pow(sh-.75,2.)*-10.),
                exp(pow(sh-.50,2.)*-20.),
                exp(pow(sh-.25,2.)*-10.));
        gl_FragColor = vec4(c,1.);
    }
    Last edited by EloStorm; 10-05-2017 at 08:07 PM.

  3. #3
    Junior Member Newbie
    Join Date
    Oct 2017
    Posts
    4
    I've further simplified the ShaderTest.cpp code to eliminate the need for the image texture. I draw to the texture within the FBO and then blit it to the screen. The colors are not correct but helps to simplify for testing and diagnosing the problem.

    I have tried a quad, triangle fan, oversized triangle, and also a triangle_strip. The code allows for easy switching (see draw enum).

    After reading posts and blogs for days, I am leaning towards some kind of precision issue with values within the frag shader. Not really sure to how best test against that.

    I found this older thread that describes my problem, although the issue was never resolved, so I don't know if it was actually the same problem or how it was solved:
    https://www.opengl.org/discussion_bo...-triangle-seam

    Thanks.

    (NOTE: red diagonal line on image is added by me)
    Refined CPP Code Below: Quad Seam / Inner Ripples
    Click image for larger version. 

Name:	single_buffer_quad_diagonal_seam.jpg 
Views:	8 
Size:	22.7 KB 
ID:	2508

    ShaderTest.cpp V2
    Code :
    //
    //  code based on https://github.com/yasuohasegawa/OpenGL-Multipass-Shader-Sample 
    //
     
    #include <GL/glew.h>
    #include <GL/glut.h>
    #include "ShaderTest.h"
     
    #define TIMER_MS 25
    #define CYCLE 1000.0f
    #define APP_WIDTH  640
    #define APP_HEIGHT 360
     
    static GLuint _s_program1 = 0;
    static GLuint _s_fb = 0;
    static GLuint _s_texBuffer = 0;
    static GLuint _s_frame = 0;
     
    static enum eDrawMethod{
        DRAW_QUAD,
        DRAW_TRIANGLE_FAN,
        DRAW_TRIANGLE_STRIP,
        DRAW_TRIANGLE_OVERSIZED
    } _s_drawMethod = DRAW_QUAD;
     
     
    void draw(){
        if (_s_drawMethod == DRAW_QUAD){
            glBegin(GL_QUADS);
                glTexCoord2f(0.0, 0.0); glVertex2i(0,            0);
                glTexCoord2f(1.0, 0.0); glVertex2i(APP_WIDTH,    0);
                glTexCoord2f(1.0, 1.0); glVertex2i(APP_WIDTH,    APP_HEIGHT);
                glTexCoord2f(0.0, 1.0); glVertex2i(0,            APP_HEIGHT);
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_FAN) {
            glBegin(GL_TRIANGLE_FAN);
                glVertex2i(0,            0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
                glVertex2i(APP_WIDTH,    0);
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_STRIP) {
            glBegin(GL_TRIANGLE_STRIP);
                glVertex2i(0,            0);
                glVertex2i(APP_WIDTH,    0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED) {
            glBegin(GL_TRIANGLES);
                glVertex2i(0,            0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
            glEnd();
        }
    }
     
    void init(){
        glewInit();
        _s_program1 = loadShader("./shaders/shader.vert","./shaders/ripples1_buffer.frag");
     
        // buffer texture
        glGenTextures(1, &_s_texBuffer);
        glBindTexture(GL_TEXTURE_2D, _s_texBuffer);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glBindTexture(GL_TEXTURE_2D, 0);
     
        // fbo
        glGenFramebuffers(1, &_s_fb);
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _s_texBuffer, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
     
    void render(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(0, 0, APP_WIDTH, APP_HEIGHT);
        glOrtho(0, APP_WIDTH, 0, APP_HEIGHT, -1, 1);
     
        if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED){
            glTranslatef(0.0, -APP_HEIGHT, 0.0);
            glScalef(2.0, 2.0, 0.0);
        }
     
        // buffer
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, _s_texBuffer);
                glUseProgram(_s_program1);
                glUniform2f(glGetUniformLocation(_s_program1, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
                glUniform1f(glGetUniformLocation(_s_program1, "iTime"), (float) glutGet(GLUT_ELAPSED_TIME) / CYCLE);
                glUniform1i(glGetUniformLocation(_s_program1, "iFrame"), _s_frame++);
                glUniform1i(glGetUniformLocation(_s_program1, "iChannel0"), 0);
                    draw();
                glUseProgram(0);
            glBindTexture(GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
        // blit testing...
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            glReadBuffer(GL_COLOR_ATTACHMENT0);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
                glBlitFramebuffer(0, 0, APP_WIDTH, APP_HEIGHT, 0, 0, APP_WIDTH, APP_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
        // flush / swap buffers
        glFlush();
    }
     
    void timer(int){
        render();
        glutTimerFunc(TIMER_MS, timer, 0);
    }
     
    void display(){}
    int main(int argc, char *argv[]){
        glutInit(&argc, argv);
        glutInitWindowPosition(0, 0);
        glutInitWindowSize(APP_WIDTH, APP_HEIGHT);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
        glutCreateWindow(argv[0]);
        glutDisplayFunc(display);
        glutTimerFunc(TIMER_MS, timer, 0);
        init();
     
        glutMainLoop();
        return 0;
    }
    Last edited by EloStorm; 10-06-2017 at 09:02 AM.

  4. #4
    Junior Member Newbie
    Join Date
    Oct 2017
    Posts
    4
    Figured it out. Needed to ping-pong between two textures for the alternating of read/write during rendering.

    ShaderTest.cpp V3 (working)
    Code :
    //
    //  code based on https://github.com/yasuohasegawa/OpenGL-Multipass-Shader-Sample 
    //
     
    #include <GL/glew.h>
    #include <GL/glut.h>
    #include "ShaderTest.h"
     
    #define TIMER_MS 25
    #define CYCLE 1000.0f
    #define APP_WIDTH  640
    #define APP_HEIGHT 360
    #define BLIT_TESTING_MODE 0
     
    #define TEXTURES_COUNT 2
    static GLuint _s_texBuffer[TEXTURES_COUNT] = {0, 0};
    static GLuint _s_texBufferIndex = 0;
     
    static GLuint _s_program1 = 0;
    static GLuint _s_program2 = 0;
    static GLuint _s_fb = 0;
    static GLuint _s_texImage = 0;
    static GLuint _s_frame = 0;
     
    static enum eDrawMethod{
        DRAW_QUAD,
        DRAW_TRIANGLE_FAN,
        DRAW_TRIANGLE_DUAL,
        DRAW_TRIANGLE_STRIP,
        DRAW_TRIANGLE_OVERSIZED
    } _s_drawMethod = DRAW_QUAD;
     
     
    void draw(){
        if (_s_drawMethod == DRAW_QUAD){
            glBegin(GL_QUADS);
                glTexCoord2f(0.0, 0.0); glVertex2i(0,            0);
                glTexCoord2f(1.0, 0.0); glVertex2i(APP_WIDTH,    0);
                glTexCoord2f(1.0, 1.0); glVertex2i(APP_WIDTH,    APP_HEIGHT);
                glTexCoord2f(0.0, 1.0); glVertex2i(0,            APP_HEIGHT);
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_FAN) {
            glBegin(GL_TRIANGLE_FAN);
                glVertex2i(0,            0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
                glVertex2i(APP_WIDTH,    0);
            glEnd();
     
        // 1---2
        // | / |
        // 3---4
        } else if (_s_drawMethod == DRAW_TRIANGLE_DUAL) {
            glBegin(GL_TRIANGLES);
                glVertex2i(0,            APP_HEIGHT);    // 1
                glVertex2i(APP_WIDTH,    APP_HEIGHT);    // 2
                glVertex2i(0,            0);                // 3
                glVertex2i(APP_WIDTH,    0);                // 4
                glVertex2i(0,            0);                // 3
                glVertex2i(APP_WIDTH,    APP_HEIGHT);    // 2
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_STRIP) {
            glBegin(GL_TRIANGLE_STRIP);
                glVertex2i(0,            0);
                glVertex2i(APP_WIDTH,    0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
            glEnd();
     
        } else if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED) {
            glBegin(GL_TRIANGLES);
                glVertex2i(0,            0);
                glVertex2i(0,            APP_HEIGHT);
                glVertex2i(APP_WIDTH,    APP_HEIGHT);
            glEnd();
        }
    }
     
    void init(){
        glewInit();
        _s_program1 = loadShader("./shaders/shader.vert","./shaders/ripples1_buffer.frag");
        _s_program2 = loadShader("./shaders/shader.vert","./shaders/ripples1_image.frag");
     
        // buffer textures
        for (int i = 0; i < TEXTURES_COUNT; ++i){
            glGenTextures(1, &_s_texBuffer[i]);
            glBindTexture(GL_TEXTURE_2D, _s_texBuffer[i]);
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_FLOAT, 0);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glBindTexture(GL_TEXTURE_2D, 0);
        }
     
        // image/screen texture
        glGenTextures(1, &_s_texImage);
        glBindTexture(GL_TEXTURE_2D, _s_texImage);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, APP_WIDTH, APP_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glBindTexture(GL_TEXTURE_2D, 0);
     
        // fbo
        glGenFramebuffers(1, &_s_fb);
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            for (int i = 0; i < TEXTURES_COUNT; ++i)
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, _s_texBuffer[i], 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
     
    void render(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(0, 0, APP_WIDTH, APP_HEIGHT);
        glOrtho(0, APP_WIDTH, 0, APP_HEIGHT, -1, 1);
     
        if (_s_drawMethod == DRAW_TRIANGLE_OVERSIZED){
            glTranslatef(0.0, -APP_HEIGHT, 0.0);
            glScalef(2.0, 2.0, 0.0);
        }
     
        // buffer
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            glDrawBuffer(GL_COLOR_ATTACHMENT0 + _s_texBufferIndex);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, _s_texBuffer[_s_texBufferIndex ? 0 : 1]);
                glUseProgram(_s_program1);
                glUniform2f(glGetUniformLocation(_s_program1, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
                glUniform1f(glGetUniformLocation(_s_program1, "iTime"), (float) glutGet(GLUT_ELAPSED_TIME) / CYCLE);
                glUniform1i(glGetUniformLocation(_s_program1, "iFrame"), _s_frame++);
                glUniform1i(glGetUniformLocation(_s_program1, "iChannel0"), 0);
                    draw();
                glUseProgram(0);
            glBindTexture(GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
        // image / screen
        // check for blit testing, rather than rendering to the image/screen texture
    #if BLIT_TESTING_MODE
        glBindFramebuffer(GL_FRAMEBUFFER, _s_fb);
            glReadBuffer(GL_COLOR_ATTACHMENT0 + _s_texBufferIndex);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
                glBlitFramebuffer(0, 0, APP_WIDTH, APP_HEIGHT, 0, 0, APP_WIDTH, APP_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    #else
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, _s_texBuffer[_s_texBufferIndex]);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, _s_texImage);
            glUseProgram(_s_program2);    
            glUniform2f(glGetUniformLocation(_s_program2, "iViewportResolution"), (float) APP_WIDTH, (float) APP_HEIGHT);
            glUniform1i(glGetUniformLocation(_s_program2, "iChannel0"), 0);
            glUniform1i(glGetUniformLocation(_s_program2, "iChannel1"), 1);
                draw();
            glUseProgram(0);
        glBindTexture(GL_TEXTURE_2D, 0);
    #endif
     
        // update texture index (ping pong)
        _s_texBufferIndex = _s_texBufferIndex ? 0 : 1;
     
        glFlush();
    }
     
    void timer(int){
        render();
        glutTimerFunc(TIMER_MS, timer, 0);
    }
     
    void display(){}
    int main(int argc, char *argv[]){
        glutInit(&argc, argv);
        glutInitWindowPosition(0, 0);
        glutInitWindowSize(APP_WIDTH, APP_HEIGHT);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
        glutCreateWindow(argv[0]);
        glutDisplayFunc(display);
        glutTimerFunc(TIMER_MS, timer, 0);
        init();
        glutMainLoop();
        return 0;
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •