C++ 如何用OpenGl绘制移动函数图?

C++ 如何用OpenGl绘制移动函数图?,c++,qt,opengl,animation,graph,C++,Qt,Opengl,Animation,Graph,我正在使用OpenGl制作一个图形的动画,它看起来像这样: 以下是我目前掌握的代码: void GLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0,1,0); //Green // Frequency Line glLineWidth(3.0); glBegin(GL_LINE_STRIP); glVertex2f(-1,0); gl

我正在使用OpenGl制作一个图形的动画,它看起来像这样:

以下是我目前掌握的代码:

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0,1,0);                   //Green

// Frequency Line
    glLineWidth(3.0);
    glBegin(GL_LINE_STRIP);
    glVertex2f(-1,0);
    glVertex2f(x1,y1);
    glEnd();
    y1 = randVarGen();
    x1 = randVarGen();

我有一个计时器,每50毫秒重新绘制一次图表。我想从一条直线开始,根据音频文件中的变量(我现在使用随机变量),图表应该像音乐可视化工具一样上下波动。

您需要对要绘制的函数进行采样

glBegin(GL_LINE_STRIP);
glVertex2f(0f, 0f);
for (float x = 1f; x < 100f; x += 1f)
  glVertex2f(x, randVarGen());
glVertex2f(100f, 0f);
glEnd();
glBegin(GL\u线\u带);
glVertex2f(0f,0f);
用于(浮动x=1f;x<100f;x+=1f)
glVertex2f(x,randVarGen());
glVertex2f(100f,0f);
格伦德();

Wikibooks OpenGL教程示例

在Ubuntu 16.04上测试

该回购协议的关键文件包括:

graph.cpp

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <GL/glew.h>
#include <GL/glut.h>

#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;
}
图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);
}

你的问题是什么?抱歉我不清楚。使用我现在的代码,一端保持静止,另一端疯狂地跳跃。有没有一种方法可以使两端固定,但中间会随着randVars的变化而变化?我相信您需要更多的点。例如,在glBegin/glEnd中创建一个循环,并多次调用glVertex2f以添加更多点。您可以共享此图的源代码吗。它可能对某些人有用。感谢您提供了有用的参考代码,但读者应该注意,这个答案缺少一些文件,无法按原样编译,您最好克隆整个gitlab repo。(另外,仅供参考,此复制/粘贴是合法的,因为代码和链接的文章是在公共域/WTFPL下发布的)。
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);
}