How to draw a moving function graph with OpenGl?

后端 未结 2 1593
星月不相逢
星月不相逢 2021-02-10 02:04

I\'m using OpenGl to animate a graph that looks something like this: \"enter

Here\'s the

2条回答
  •  遇见更好的自我
    2021-02-10 02:23

    Wikibooks OpenGL tutorial example

    Tested on Ubuntu 16.04.

    • https://en.wikibooks.org/wiki/OpenGL_Programming/Scientific_OpenGL_Tutorial_01
    • https://gitlab.com/wikibooks-opengl/modern-tutorials/tree/2d8a441d8db81b4a619cf583769d1ea1451f4529/graph01

    The key files of that repo are:

    graph.cpp

    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include "../common/shader_utils.h"
    
    #include "res_texture.c"
    
    GLuint program;
    GLint attribute_coord2d;
    GLint uniform_offset_x;
    GLint uniform_scale_x;
    GLint uniform_sprite;
    GLuint texture_id;
    GLint uniform_mytexture;
    
    float offset_x = 0.0;
    float scale_x = 1.0;
    int mode = 0;
    
    struct point {
        GLfloat x;
        GLfloat y;
    };
    
    GLuint vbo;
    
    int init_resources() {
        program = create_program("graph.v.glsl", "graph.f.glsl");
        if (program == 0)
                return 0;
    
        attribute_coord2d = get_attrib(program, "coord2d");
        uniform_offset_x = get_uniform(program, "offset_x");
        uniform_scale_x = get_uniform(program, "scale_x");
        uniform_sprite = get_uniform(program, "sprite");
        uniform_mytexture = get_uniform(program, "mytexture");
    
        if (attribute_coord2d == -1 || uniform_offset_x == -1 || uniform_scale_x == -1 || uniform_sprite == -1 || uniform_mytexture == -1)
                return 0;
    
        /* Enable blending */
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        /* Enable point sprites (not necessary for true OpenGL ES 2.0) */
    #ifndef GL_ES_VERSION_2_0
        glEnable(GL_POINT_SPRITE);
        glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
    #endif
    
        /* Upload the texture for our point sprites */
        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &texture_id);
        glBindTexture(GL_TEXTURE_2D, texture_id);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res_texture.width, res_texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, res_texture.pixel_data);
    
        // Create the vertex buffer object
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
    
        // Create our own temporary buffer
        point graph[2000];
    
        // Fill it in just like an array
        for (int i = 0; i < 2000; i++) {
                float x = (i - 1000.0) / 100.0;
    
                graph[i].x = x;
                graph[i].y = sin(x * 10.0) / (1.0 + x * x);
        }
    
        // Tell OpenGL to copy our array to the buffer object
        glBufferData(GL_ARRAY_BUFFER, sizeof graph, graph, GL_STATIC_DRAW);
    
        return 1;
    }
    
    void display() {
        glUseProgram(program);
        glUniform1i(uniform_mytexture, 0);
    
        glUniform1f(uniform_offset_x, offset_x);
        glUniform1f(uniform_scale_x, scale_x);
    
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
    
        /* Draw using the vertices in our vertex buffer object */
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
    
        glEnableVertexAttribArray(attribute_coord2d);
        glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0);
    
        /* Push each element in buffer_vertices to the vertex shader */
        switch (mode) {
        case 0:
                glUniform1f(uniform_sprite, 0);
                glDrawArrays(GL_LINE_STRIP, 0, 2000);
                break;
        case 1:
                glUniform1f(uniform_sprite, 1);
                glDrawArrays(GL_POINTS, 0, 2000);
                break;
        case 2:
                glUniform1f(uniform_sprite, res_texture.width);
                glDrawArrays(GL_POINTS, 0, 2000);
                break;
        }
    
        glutSwapBuffers();
    }
    
    void special(int key, int x, int y) {
        switch (key) {
        case GLUT_KEY_F1:
                mode = 0;
                printf("Now drawing using lines.\n");
                break;
        case GLUT_KEY_F2:
                mode = 1;
                printf("Now drawing using points.\n");
                break;
        case GLUT_KEY_F3:
                mode = 2;
                printf("Now drawing using point sprites.\n");
                break;
        case GLUT_KEY_LEFT:
                offset_x -= 0.1;
                break;
        case GLUT_KEY_RIGHT:
                offset_x += 0.1;
                break;
        case GLUT_KEY_UP:
                scale_x *= 1.5;
                break;
        case GLUT_KEY_DOWN:
                scale_x /= 1.5;
                break;
        case GLUT_KEY_HOME:
                offset_x = 0.0;
                scale_x = 1.0;
                break;
        }
    
        glutPostRedisplay();
    }
    
    void free_resources() {
        glDeleteProgram(program);
    }
    
    int main(int argc, char *argv[]) {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGB);
        glutInitWindowSize(640, 480);
        glutCreateWindow("My Graph");
    
        GLenum glew_status = glewInit();
    
        if (GLEW_OK != glew_status) {
                fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
                return 1;
        }
    
        if (!GLEW_VERSION_2_0) {
                fprintf(stderr, "No support for OpenGL 2.0 found\n");
                return 1;
        }
    
        GLfloat range[2];
    
        glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
        if (range[1] < res_texture.width)
                fprintf(stderr, "WARNING: point sprite range (%f, %f) too small\n", range[0], range[1]);
    
        printf("Use left/right to move horizontally.\n");
        printf("Use up/down to change the horizontal scale.\n");
        printf("Press home to reset the position and scale.\n");
        printf("Press F1 to draw lines.\n");
        printf("Press F2 to draw points.\n");
        printf("Press F3 to draw point sprites.\n");
    
        if (init_resources()) {
                glutDisplayFunc(display);
                glutSpecialFunc(special);
                glutMainLoop();
        }
    
        free_resources();
        return 0;
    }
    

    graph.f.glsl

    uniform sampler2D mytexture;
    varying vec4 f_color;
    uniform float sprite;
    
    void main(void) {
        if (sprite > 1.0)
                gl_FragColor = texture2D(mytexture, gl_PointCoord) * f_color;
        else
                gl_FragColor = f_color;
    }
    

    graph.v.glsl

    attribute vec2 coord2d;
    varying vec4 f_color;
    uniform float offset_x;
    uniform float scale_x;
    uniform lowp float sprite;
    
    void main(void) {
        gl_Position = vec4((coord2d.x + offset_x) * scale_x, coord2d.y, 0, 1);
        f_color = vec4(coord2d.xy / 2.0 + 0.5, 1, 1);
        gl_PointSize = max(1.0, sprite);
    }
    

提交回复
热议问题