Nano Hash - криптовалюты, майнинг, программирование

OpenGL 3/4 glVertexAttribPointer шаг и просчет смещения

У меня возникла проблема с правильным указанием массива вершин:

const float vertices[] = {
/* position */ 0.75f, 0.75f, 0.0f, 1.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
/* position */ 0.75f, -0.75f, 0.0f, 1.0f, /* color */ 0.0f, 1.0f, 0.0f, 1.0f,
/* position */ -0.75f, -0.75f, 0.0f, 1.0f, /* color */ 0.0f, 0.0f, 1.0f, 1.0f, };

...

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)16);

glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

Я не понимаю, как работают шаг и смещение. Как правильно использовать glVertexAttribPointer() в моей ситуации?


Ответы:


1

Поскольку glVertexAttribPointer часто создает проблемы, я попытаюсь объяснить это здесь.

Формула для вычисления начальной позиции i-го атрибута в массиве атрибутов:

startPos(i) = offset + i * stride (из другого ответа Дерхасса)

И поясняется на графике ниже: плотно упакованный массив arrtibute


Если вам нужен пример кода, продолжайте читать.

Из Форматирование данных VBO мы знаем, что можем управлять данными вершин в трех форматах. Сделайте пример рисования треугольника со смешанным цветом вершины и цветом текстуры, вот способ подготовки данных атрибута вершины:


#way1 Каждый атрибут VBO.

этот формат, например: (xyzxyz...)(rgbrgb...)(stst....), и мы можем указать как sride = 0, так и offset = 0.

void prepareVertData_moreVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
    GLfloat vertPos[] = {
        -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // positon
    };
    GLfloat vertColor[] = {
      1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
    };
   GLfloat vertTextCoord[] = {
      0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
   };
    
    GLuint VBOId[3];
   
    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);
    glGenBuffers(3, VBOId);
    // specify position attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertPos), vertPos, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(0);
    // specify color attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertColor), vertColor, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(1);
    // specify texture coordinate attribute
    glBindBuffer(GL_ARRAY_BUFFER, VBOId[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertTextCoord), vertTextCoord, GL_STATIC_DRAW);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.push_back(VBOId[0]);
    VBOIdVec.push_back(VBOId[1]);
    VBOIdVec.push_back(VBOId[2]);
}

#way2: каждый атрибут является последовательным и группируется в одном VBO.

этот формат выглядит следующим образом: (xyzxyzxyz... rgbrgb... ststst...), мы можем оставить шаг=0, но нужно указать смещение.

void prepareVertData_seqBatchVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
   
    GLfloat vertices[] = {
     -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,  // position
     1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // color
     0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f     // texture coordinate
    };
    
    GLuint VBOId;
    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);
    
    glGenBuffers(1, &VBOId);
    glBindBuffer(GL_ARRAY_BUFFER, VBOId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // specifiy position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // stride can aslo be 3 * sizeof(GLfloat)
    glEnableVertexAttribArray(0);
    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(9 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(18 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.push_back(VBOId);
}

#way3: чередование атрибутов в одном VBO

этот формат похож на: (xyzrgbstxyzrgbst...), мы должны вручную указать смещение и шаг.

void prepareVertData_interleavedBatchVBO(GLuint& VAOId, std::vector<GLuint>& VBOIdVec)
{
    // interleaved data
    GLfloat vertices[] = {
       -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,  // 0
       0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // 1
       0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,  // 2
    };
    
    GLuint VBOId;
    glGenVertexArrays(1, &VAOId);
    glBindVertexArray(VAOId);
    glGenBuffers(1, &VBOId);
    glBindBuffer(GL_ARRAY_BUFFER, VBOId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // specify position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // specify color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
        8 * sizeof(GLfloat),(GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // specify texture coordinate
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 
        8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    VBOIdVec.push_back(VBOId);
}

И спасибо за ответ Дерхасса.

25.09.2016
  • Вау, я пытался понять разницу между тремя методами большую часть дня (в основном чередование по сравнению с другими и как правильно использовать смещение), затем я увидел это рядом, и это все стало ясно. Спасибо. ;) Любая идея, которая обычно быстрее? 04.01.2017
  • @JamesWilkins Согласно рекомендациям, которые я прочитал (например, рекомендации Apple IOS, версия с чередующимися данными работает быстрее. 20.06.2018
  • Я думаю, это имеет смысл, поскольку система может легко преобразовать значения в структуру вместо того, чтобы копировать каждое по одному из отдельных массивов. 21.06.2018
  • sizeof(GL_FLOAT) выглядит некорректно и работает случайно. Должно быть sizeof(GLfloat) 28.11.2018

  • 2

    Шаг и смещение задаются в байтах. Вы используете чередующийся массив вершин с позицией и цветом как 4 числа с плавающей запятой. Чтобы перейти от th i-го элемента в конкретном массиве атрибутов к следующему, существует расстояние 8 float, поэтому шаг должен быть 8 * sizeof (GLfloat). Смещение — это байтовая позиция первого элемента каждого массива атрибутов в буфере, поэтому в вашем примере для позиции это 0, а для цвета — 4*sizeof(GLfloat)

    05.05.2013
  • какими должны быть мои два значения шага и смещения glVertexAttribPointer? 06.05.2013
  • @ user2350858: Как я уже писал в ответе: шаг равен 8 * sizeof (GLfloat) (обычно 32), смещение 0 для позиции и 4 * sizeof (GLfloat) для цвета (как вы уже делаете) 06.05.2013
  • Тип смещения должен быть const void*, как бы вы этого добились? Я считал nullptr + offset, но тип не тот. Я попробовал (void*)0 + offset, но у меня это пока не работает (не уверен, что еще может быть не так). 07.10.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..