Хобрук: Ваш путь к мастерству в программировании

glBufferSubData смещения для структур

На самом деле я работаю над движком рендеринга OpenGL 3.3, именно я пытаюсь создать динамическое количество источников света в своей сцене.

Для этого я работаю с унифицированными буферными объектами (UBO), и у меня возникают проблемы, когда я пытаюсь передать данные через UBO, которые будут считываться или записываться в структуру с данными другого типа.

Я сделал это для точечных и направленных источников света, и все в порядке, потому что я использую только vec3 данные. Проблема в том, что когда я определяю фокусные источники света, структура которых:

#version 330 core

#define MAX_NUM_TOTAL_LIGHTS 100
...
struct FocalLight{
    vec3 f_light_position;
    vec3 f_light_direction;
    vec3 f_light_diffuse_intensity;
    vec3 f_light_specular_intensity;
    float f_apperture_angle;
    float f_attenuation;
};
layout(std140) uniform focalLights{
    FocalLight f_lights[MAX_NUM_TOTAL_LIGHTS];
};

Что ж, положение, направление, диффузная интенсивность и зеркальная интенсивность в порядке, и мой фрагмент правильно получает эти данные из буфера. Но я не могу писать и читать данные для f_apperture_angle и f_attenuation.

Вот код, выполняемый на ЦП, который я использовал для записи данных моего буфера, где focal_lights — это вектор с экземплярами моего класса FocalLight (std::vector<FocalLight> focal_lights), содержимое которого я проверил правильно:

if(block_focal_lights_id != -1) {
    glUniformBlockBinding(programId, block_focal_lights_id, 2);
    //Loading from light vectors
    glGenBuffers(1, &buffer_focal_lights_id);
    glBindBuffer(GL_UNIFORM_BUFFER, buffer_focal_lights_id);
    glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 24 * focal_lights.size(), 0, GL_DYNAMIC_DRAW);
    int offset = 0;
    for (unsigned int i=0; i<focal_lights.size(); i++) {
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].position);
        offset += 16;
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].direction);
        offset += 16;
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].diffuse_intensity);
        offset += 16;
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].specular_intensity);
        offset += 16;
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].apperture_angle);
        offset += 16;
        glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].attenuation);
        offset += 16;
    }
}

Я пытаюсь изменить тип данных для моего f_apperture_angle на vec3, и я могу прочитать их с определенными ранее смещениями, но ничего о работе с простым числом с плавающей запятой. Я уверен, что привязка буфера правильная, и я знаю, что проблема в коде glBufferData или glBufferSubdata.

Кто-нибудь видит проблему?

Наконец-то заработало, спасибо Rabbid76: 2 фокусных, 2 направленных и один точечный

12.04.2018

  • Я сделал это, но я думаю, что более чисто использовать одно число с плавающей запятой для каждой переменной. 12.04.2018
  • Попробуйте другой макет памяти, layout(std430) uniform focalLights вместо std140 12.04.2018

Ответы:


1

Вы должны учитывать особые правила выравнивания при привязке данных к std140 стандартной унифицированной блочной компоновке.

См. Спецификацию профиля совместимости API OpenGL 4.6; 7.6.2.2 Стандартная унифицированная блочная компоновка; стр. 144

Когда указан макет std140, смещение каждого юниформа в юниформ-блоке может быть получено из определения юниформ-блока путем применения набора правил, описанных ниже.

  1. Если элемент является скаляром, потребляющим N базовых машинных единиц, базовое выравнивание равно N

....

  1. Если элемент представляет собой трехкомпонентный вектор с компонентами, потребляющими N базовых машинных единиц, базовое выравнивание равно 4N.

....

  1. Если элемент является структурой, базовое выравнивание структуры равно N, где N — наибольшее значение базового выравнивания любого из ее элементов, округленное до базового выравнивания vec4. Затем отдельным членам этой подструктуры назначаются смещения путем рекурсивного применения этого набора правил, где базовое смещение первого элемента подструктуры равно выровненному смещению структуры. Структура может иметь заполнение в конце; базовое смещение элемента, следующего за подконструкцией, округляется до следующего кратного базового выравнивания конструкции.

  2. Если элемент представляет собой массив из S структур, S элементов массива располагаются по порядку в соответствии с правилом (9).


Когда вы применяете эти правила к своей структуре данных, это приводит к следующим смещениям:

struct FocalLight                    // size 80 (rule 9 and 10)
{
    vec3 f_light_position;           // offset 0  (rule 3 and 10)
    vec3 f_light_direction;          // offset 16 (rule 3)
    vec3 f_light_diffuse_intensity;  // offset 32 (rule 3)
    vec3 f_light_specular_intensity; // offset 48 (rule 3)
    float f_apperture_angle;         // offset 60 (rule 1)
    float f_attenuation;             // offset 64 (rule 1)
};
layout(std140) uniform focalLights{
    FocalLight f_lights[MAX_NUM_TOTAL_LIGHTS];
};

Привязка данных:

int offset = 0;
for (unsigned int i=0; i<focal_lights.size(); i++) {

    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].position);

    offset += 16; // rule 3
    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].direction);

    offset += 16; // rule 3
    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].diffuse_intensity);

    offset += 16; // rule 3
    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float) * 3, focal_lights[i].specular_intensity);

    offset += 12; // rule 1
    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].apperture_angle);

    offset += 4; // rule 1
    glBufferSubData(GL_UNIFORM_BUFFER, offset, sizeof(float), &focal_lights[i].attenuation);

    offset += 16; // rules 9 and 10
}
12.04.2018
  • Я попробую позже, большое спасибо, у меня были сомнения по поводу 4-го приращения смещения, потому что не было смысла отбрасывать эти 4 байта на GPU, когда у вас есть число с плавающей запятой для его заполнения. 12.04.2018

  • 2

    Один вызов для буферизации данных — это все, что вам нужно.

    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(FocalLight)*focal_lights.size(), focal_lights);
    

    Использование нескольких небольших буферных копий данных засоряет API и драйвер, что приводит к очень низкой производительности.

    Чтобы иметь дело с выравниванием std140 (или предпочтительно std430), вам просто нужно добавить дополнение к вашим структурам на стороне С++ или изменить порядок членов.

    struct FocalLight{
      vec3 f_light_position;
      float f_apperture_angle;
      vec3 f_light_direction;
      float f_attenuation;
      vec3 f_light_diffuse_intensity;
      float pad1;
      vec3 f_light_specular_intensity;
      float pad2;
    };
    

    В качестве альтернативы вы можете использовать встроенную директиву компилятора для выравнивания __declspec(align(16))

    16.04.2018
    Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

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

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..