2013-09-15 1 views
7

У меня есть простая программа OpenGL, в которой я пытаюсь использовать объекты буфера Vertex для рендеринга вместо старого glBegin() - glEnd(). В основном пользователь нажимает на окно, указывающее начальную точку, а затем нажимает клавишу, чтобы генерировать последующие точки, которые OpenGL рисует в виде строки.Использование VBO для рисования линий из вектора точек в OpenGL

Я реализовал это с помощью glBegin() и glEnd(), но не успел использовать VBO. Мне интересно, проблема в том, что после инициализации VBO я добавляю больше вершин, для которых у него нет выделенной памяти, и, следовательно, не отображает их.

Редактировать: Кроме того, я немного смущен относительно того, как он точно знает, какие значения в вершинной структуре использовать для x и y, а также для r, g, b. Я не смог найти ясный пример этого.

#include <windows.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <Math.h> 
#include <iostream> 
#include <vector> 
#include <GL/glew.h> 
#include <GL/glut.h> 

struct vertex { 
    float x, y, u, v, r, g, b; 
}; 

const int D = 10; // distance 
const int A = 10; // angle 
const int WINDOW_WIDTH = 500, WINDOW_HEIGHT = 500; 

std::vector<vertex> vertices; 
boolean start = false; 
GLuint vboId; 

void update_line_point() { 
    vertex temp; 
    temp.x = vertices.back().x + D * vertices.back().u; 
    temp.y = vertices.back().y + D * vertices.back().v; 
    temp.u = vertices.back().u; 
    temp.v = vertices.back().v; 
    vertices.push_back(temp); 
} 

void update_line_angle() { 
    float u_prime, v_prime; 
    u_prime = vertices.back().u * cos(A) - vertices.back().v * sin(A); 
    v_prime = vertices.back().u * sin(A) + vertices.back().v * cos(A); 
    vertices.back().u = u_prime; 
    vertices.back().v = v_prime; 
} 

void initVertexBuffer() { 
    glGenBuffers(1, &vboId); 
    glBindBuffer(GL_ARRAY_BUFFER, vboId); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
} 

void displayCB() { 
    glClear(GL_COLOR_BUFFER_BIT); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT); 

    if (start) { 
     glBindBuffer(GL_ARRAY_BUFFER, vboId); 
     glEnableClientState(GL_VERTEX_ARRAY); 
     glEnableClientState(GL_COLOR_ARRAY); 
     glVertexPointer(2, GL_FLOAT, sizeof(vertex), &vertices[0]); 
     glColorPointer(3, GL_FLOAT, sizeof(vertex), &vertices[0]); 
     glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); 
     glDisableClientState(GL_VERTEX_ARRAY); 
     glDisableClientState(GL_COLOR_ARRAY); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
    } 

    /***** this is what I'm trying to achieve 
    glColor3f(1, 0, 0); 
    glBegin(GL_LINE_STRIP); 
    for (std::vector<vertex>::size_type i = 0; i < vertices.size(); i++) { 
      glVertex2f(vertices[i].x, vertices[i].y); 
    } 
    glEnd(); 
    *****/ 

    glFlush(); 
    glutSwapBuffers(); 
} 


void mouseCB(int button, int state, int x, int y) { 
    if (state == GLUT_DOWN) { 
     vertices.clear(); 
     vertex temp = {x, WINDOW_HEIGHT - y, 1, 0, 1, 0, 0}; // default red color 
     vertices.push_back(temp); 
     start = true; 
     initVertexBuffer(); 
    } 
    glutPostRedisplay(); 
} 

void keyboardCB(unsigned char key, int x, int y) { 
    switch(key) { 
    case 'f': 
     if (start) { 
      update_line_point(); 
     } 
     break; 
    case 't': 
     if (start) { 
      update_line_angle(); 
     } 
     break; 
    } 

    glutPostRedisplay(); 
} 

void initCallbackFunc() { 
    glutDisplayFunc(displayCB); 
    glutMouseFunc(mouseCB); 
    glutKeyboardFunc(keyboardCB); 
} 

int main(int argc, char** argv) { 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); 
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); 
    glutInitWindowPosition(100, 100); 
    glutCreateWindow("Test"); 
    initCallbackFunc(); 

    // initialize glew 
    GLenum glewInitResult; 
    glewExperimental = GL_TRUE; 
    glewInitResult = glewInit(); 
    if (GLEW_OK != glewInitResult) { 
     std::cerr << "Error initializing glew." << std::endl; 
     return 1; 
    } 
    glClearColor(1, 1, 1, 0); 
    glutMainLoop(); 

    return 0; 
} 

ответ

4

Если у вас есть ВБО связанные тогда pointer аргумента к gl*Pointer() вызовам интерпретируются как байты смещения от начала VBO, не фактического указатель. Однако ваше использование согласуется с использованием массива вершин.

Так для vertex STRUCT x начинается с байта нулевой и r начинается в байте sizeof(float) * 4.

Кроме того, ваш обратный вызов мыши сбрасывает ваш вектор вершин на каждый вызов, поэтому вы никогда не сможете иметь в нем несколько вершин. Он также пропустил имена VBO через glGenBuffers() в initVertexBuffer().

Дайте этот выстрел:

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

struct vertex 
{ 
    float x, y; 
    float u, v; 
    float r, g, b; 
}; 

GLuint vboId; 
std::vector<vertex> vertices; 
void mouseCB(int button, int state, int x, int y) 
{ 
    y = glutGet(GLUT_WINDOW_HEIGHT) - y; 
    if (state == GLUT_DOWN) 
    { 
     vertex temp = {x, y, 1, 0, 1, 0, 0}; // default red color 
     vertices.push_back(temp); 
     glBindBuffer(GL_ARRAY_BUFFER, vboId); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
    } 
    glutPostRedisplay(); 
} 

void displayCB() 
{ 
    glClearColor(1, 1, 1, 0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    double w = glutGet(GLUT_WINDOW_WIDTH); 
    double h = glutGet(GLUT_WINDOW_HEIGHT); 
    glOrtho(0, w, 0, h, -1, 1); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    if (vertices.size() > 1) 
    { 
     glBindBuffer(GL_ARRAY_BUFFER, vboId); 
     glEnableClientState(GL_VERTEX_ARRAY); 
     glEnableClientState(GL_COLOR_ARRAY); 
     glVertexPointer(2, GL_FLOAT, sizeof(vertex), (void*)(sizeof(float) * 0)); 
     glColorPointer(3, GL_FLOAT, sizeof(vertex), (void*)(sizeof(float) * 4)); 
     glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); 
     glDisableClientState(GL_VERTEX_ARRAY); 
     glDisableClientState(GL_COLOR_ARRAY); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
    } 

    glutSwapBuffers(); 
} 

int main(int argc, char** argv) 
{ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); 
    glutInitWindowSize(500, 500); 
    glutInitWindowPosition(100, 100); 
    glutCreateWindow("Test"); 

    // initialize glew 
    glewExperimental = GL_TRUE; 
    GLenum glewInitResult = glewInit(); 
    if (GLEW_OK != glewInitResult) { 
     std::cerr << "Error initializing glew." << std::endl; 
     return 1; 
    } 

    glGenBuffers(1, &vboId); 

    glutDisplayFunc(displayCB); 
    glutMouseFunc(mouseCB); 
    glutMainLoop(); 
    return 0; 
} 
4

ВБО является буфер находится где-то в памяти (почти всегда в выделенной памяти GPU - VRAM) фиксированного размера. Этот размер указывается в glBufferData, и вы также одновременно предоставляете GL-указателю для копирования. Ключевым словом здесь является копия. Все, что вы делаете с вектором после glBufferData, не отражено в VBO.

Вы должны быть обязательными и делать еще один вызов glBufferData после изменения вектора. Вероятно, вы также получите более высокую производительность от glBufferSubData или glMapBuffer, если VBO уже достаточно велик, чтобы обрабатывать новые данные, но в таком маленьком приложении, как и в случае с быстрым вызовом glBufferData, каждый раз в принципе не существует.

Кроме того, чтобы задать другой вопрос о значениях, которые вам нужно выбрать, x, y и т. Д. Способ настройки вашего VBO заключается в том, что значения чередуются. поэтому в памяти, ваши вершины будут выглядеть следующим образом:

+------------------------------------------------- 
| x | y | u | v | r | g | b | x | y | u | v | ... 
+------------------------------------------------- 

Вы говорите OpenGL, где ваши вершины и цвет с функциями glVertexPointer и glColorPointer соответственно.

  • Параметр размера указывает количество элементов для каждой вершины. В этом случае это 2 для вершин и 3 для цветов.
  • Параметр type указывает тип каждого элемента. В вашем случае это GL_FLOAT для обоих.
  • Параметр stride - сколько байтов необходимо пропустить с начала одной вершины до начала следующего. С чередующейся настройкой, подобной вашей, это просто sizeof(vertex) для обоих.
  • Последний параметр, указатель, на самом деле не является указателем на ваш вектор в этом случае. Когда VBO привязан, указатель становится смещением байта в VBO. Для вершин это должно быть 0, так как первая вершина начинается с самого первого байта VBO. Для цветов это должно быть 4 * sizeof(float), так как первому цвету предшествуют 4 поплавка.