Search code examples
c++openglfreeglut

Waving Flag Effect in Opengl (C++)


as a part of a project; I need to create a flag with waving effect as shown below:

https://i.sstatic.net/db5zB.gif

I couldn't manage to add wave effect so I removed the crescent & star and now trying to wave the flag itself.

I believe when I pass the time, it doesn't update so animation doesn't happen. What I did so far is:

    #include "Angel.h"
float PI = 3.14;
int verticeNumber = 0;
float time;
struct point {
    GLfloat x;
    GLfloat y;
};
point vertices[500];




// OpenGL initialization
void init()
{

    // Create a vertex array object
    vertices[0].x = -0.75;
    vertices[0].y = 0.5;
    vertices[1].x = 0.75;
    vertices[1].y = 0.5;
    vertices[2].x = 0.75;
    vertices[2].y = -0.5;
    vertices[3].x = -0.75;
    vertices[3].y = -0.5;
    vertices[4].x = -0.75;
    vertices[4].y = 0.5;

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // Load shaders and use the resulting shader program
    time = glutGet(GLUT_ELAPSED_TIME);
    GLuint program = InitShader("vshader.glsl", "fshader.glsl");
    glUseProgram(program);
    // set up vertex arrays
    GLuint vPosition = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
    // Paint the background
    glClearColor(0.36, 0.74, 0.82, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 5);


    glutSwapBuffers();

}
void display(void)
{

}


// Ends the program on ESC press.
void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 033:
        exit(EXIT_SUCCESS);
        break;
    }
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(800, 800);

    // OpenGL Version Check
    glutInitContextVersion(3, 2);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    // Name the window
    glutCreateWindow("I'm Rick Harrison, and this is my pawn shop");
    glewExperimental = GL_TRUE;
    glewInit();

    init();

    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);

    glutMainLoop();
    return 0;
}

My shader files are:

#version 430
varying vec4 f_color;

void main(void) {
    gl_FragColor = vec4(1,0,0,1);
}

and

#version 430
in vec4 vPosition;
in float time;
void main()
{
    vec4 temp = vPosition;
    temp.y = cos(0.1*time)*temp.y;
    gl_Position = temp;
}

It results in this: https://i.sstatic.net/MVSp0.png without any animations.


Solution

  • Time is needed to be updated that mentioned by user2927848. I just want to advise your waving effect. If you want to pass the time in your vertex shader, you need more than four vertices that you generated by yourself, because of your vertex shader only be called 4 times by pipleline, one of each vertex. so you will not get the beauty wave effect that you expected.

    In conclusion, There are two ways for your flag waving smoothly.

    1. Pass more vertex to Vertex Shader
    2. Pass the time variable to Fragment Shader

    In first suggestion, you need to generate maybe 100 * 50 vertices to make it smoothly, or maybe more to look better as you like.

    The second suggestion also has a little issue, If your image is entirely fit in your plane, then you need to somehow let the image have some margin away from border. The easy way to slove this is to make your *.png image have some transparency margin at the border and do whatever your waving function at the uv value.

    I just implement the simplest waving effect in the shadertoy. Also put the code below, because it is short...

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        vec2 uv = fragCoord.xy / iResolution.xy;
        uv.y = uv.y + 0.1 * sin(iGlobalTime +  10.0 * uv.x);
        vec4 textureColor = texture2D(iChannel0, uv);
        fragColor = textureColor;
    }