2016-01-08 2 views
2

Я пишу и приложение OpenGL, где у меня есть класс GrassPatch, который представляет участки травы на сцене. Я не хочу, чтобы обеспечить все ненужные детали, так что GrassPatch.cpp выглядит примерно так:Ошибка при нарушении доступа при вызове glDrawArrays

GrassPatch::GrassPatch(GLuint density) 
{ 
    m_density = density; 
    generateVertices(); 
} 

void GrassPatch::generateVertices() 
{ 
    const int quadVertexCount = 64; 
    GLfloat bladeWidth, bladeHeight, r; 
    GLfloat randomX, randomZ; 
    m_vertices = new GLfloat[quadVertexCount * m_density]; 
    srand(time(NULL)); 
    for (int i = 0; i < m_density; i++) 
    { 
     // generate 64 float values and put them into their respective indices in m_vertices 
    } 

    glGenBuffers(1, &m_VBO); 
    glGenVertexArrays(1, &m_VAO); 

    glBindVertexArray(m_VAO); 

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_density * quadVertexCount, m_vertices, GL_STATIC_DRAW); 

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)0); 
    glEnableVertexAttribArray(0); 

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 
    glEnableVertexAttribArray(1); 

    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(5 * sizeof(GLfloat))); 
    glEnableVertexAttribArray(2); 

    glVertexAttribPointer(3, 8, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat))); 
    glEnableVertexAttribArray(3); 

    glBindVertexArray(0); 
} 

void GrassPatch::draw() 
{ 
    glBindVertexArray(m_VAO); 
    glPatchParameteri(GL_PATCH_VERTICES, 4); 
    glDrawArrays(GL_PATCHES, 0, 4 * m_density); 
    glBindVertexArray(0); 
} 

Короче говоря, объект массива вершин (ВАО) для каждой травы патча генерируется внутри generatVertices. Мои данные плотно упакованы, а атрибуты для каждой вершины находятся в индексах 0, 3, 5, 8, где каждая вершина состоит из 16 float. Каждая травинка состоит из 4-х вершин, следовательно, quadVertexCount устанавливается на 64. вершинных шейдеров я использую довольно straighforward и выглядит следующим образом:

#version 440 core 
layout (location = 0) in vec3 position; 
layout (location = 1) in vec2 texCoord; 
layout (location = 2) in vec3 centerPos; 
layout (location = 3) in float randomValues[8]; 

out vec2 TexCoord_CS; 

void main() 
{ 
    TexCoord_CS = texCoord; 

    gl_Position = vec4(position, 1.0f); 
} 

Проблема здесь в том, когда я пытаюсь нарисовать каждую траву, используя лезвие draw() метод, я получаю ошибку нарушения доступа. Однако, если я немного измените индексы атрибутов на 0, 4, 8, 12 и сделаю необходимые изменения типа переменной в вершинном шейдере, проблема исчезнет, ​​и все будет отлично.

Что мне здесь не хватает, что может вызвать такую ​​проблему? Я провел часы в Интернете, пытаясь найти причину, но ничего не мог придумать. Я работаю с Visual Studio 2015 Community Edition. Графическая карта, которую я использую, - это NVIDIA GTX 770, и все драйверы обновлены.

ответ

2

Это не действительный вызов:

glVertexAttribPointer(3, 8, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat))); 

Второй аргумент (размер) должен быть 1, 2, 3 или 4. Если вы звоните glGetError(), вы должны увидеть код на GL_INVALID_VALUE ошибки от этого вызова.

Атрибуты вершины могут содержать только до 4 компонентов, соответствующих типу vec4 в шейдерном коде. Если вам нужно 8 значений для атрибута, вам придется разделить его на 2 атрибута по 4 значения каждый или использовать униформы вместо атрибутов.

1
layout (location = 3) in float randomValues[8]; 

Это не одно входное значение. Это array of input values. Хотя это совершенно законно, оно меняет то, что это значит.

В частности, это означает, что этот входной массив заполняется 8 отдельными атрибутами. Да, каждый из этих поплавков - это отдельный атрибут, со стороны OpenGL. Они назначаются местам последовательно, начиная с указанного вами местоположения. Таким образом, вход randomValues[4] происходит от местоположения атрибута 7 (3 + 4).

Так что ваша попытка предоставить 8 значений одним вызовом glVertexAttribPointer не будет работать. Ну, это никогда не будет работать, так как количество компонентов на атрибут должно быть в диапазоне [1, 4]. Но дважды-не работать, так как вы не заполнять другой 7.

Если вы хотите передать эти 8 элементов как 8 атрибутов, как это, вы, следовательно, нужно восемь независимых звонков в glVertexAttribPointer:

for(int ix = 0; ix < 8; ++ix) 
    glVertexAttribPointer(3 + ix, 1, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)((8 + ix) * sizeof(GLfloat))); 

Но, честно говоря, вы не должны этого делать.Вместо передачи 8 независимых атрибутов, вы должны пройти 2 vec4 «S:

layout (location = 3) in vec4 randomValues[2]; 

Таким образом, вам нужно всего лишь 2 атрибуты в вашем коде OpenGL:

glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat))); 
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 16 * sizeof(GLfloat), (GLvoid*)(12 * sizeof(GLfloat))); 
Смежные вопросы