NimuraF
@NimuraF

Почему не срабатывает смещение при инстансинге?

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

Код вершинного шейдера:
#version 460 core

layout (location = 0) in vec3 aPos;

uniform vec2 offsets[100];

void main()
{
   vec3 offset = offsets[gl_InstanceID];
   gl_Position = vec4(aPos + offset, 0.0, 1.0);
}


Код фрагментного шейдера:
#version 460 core

out vec4 color;

void main()
{
   color = vec4(1.0f, 1.0f, 0.0f, 1.0f);
}


Перед основным циклом заполняю массив offset из вершинного шейдера.
glm::vec2 translations[100];
    int index = 0;
    float offset = 0.1f;
    for (int y = -10; y < 10; y += 2)
    {
        for (int x = -10; x < 10; x += 2)
        {
            glm::vec2 translation;
            translation.x = (float)x / 10.0f + offset;
            translation.y = (float)y / 10.0f + offset;
            translations[index++] = translation;
        }
    }

    glUseProgram(shaderProgramForRaindrops);
    for (unsigned int i = 0; i < 100; i++)
    {
        stringstream ss;
        string index;
        ss << i;
        index = ss.str();
        GLint offsetArray = glGetUniformLocation(shaderProgramForRaindrops, ("offsets[" + index + "]").c_str());
        glUniform2fv(offsetArray, 0, glm::value_ptr(translations[i]));
    }


Координаты самого квадрата:
GLfloat raindrops[] = {
        -0.05f,  0.05f, 0.0f,
         0.05f, -0.05f, 0.0f,
        -0.05f, -0.05f, 0.0f,

        -0.05f,  0.05f, 0.0f,
         0.05f, -0.05f, 0.0f,
         0.05f,  0.05f, 0.0f
    };


Привязываю к VAO:
glBindVertexArray(VAOs[2]);

        glBindBuffer(GL_ARRAY_BUFFER, VBOs[2]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(raindrops), raindrops, GL_STATIC_DRAW);

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

    glBindVertexArray(0);


Ну и в основном цикле через DrawArrayInstances пытаюсь отрисовать эти самые квадраты.
/* Третья программа */
        glUseProgram(shaderProgramForRaindrops);
        glBindVertexArray(VAOs[2]);
        glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100);
        glBindVertexArray(0);


В результате я получаю один квадрат по центру (что, в общем-то, логично, базовые координаты), и никаких квадратов по смещению, в чём может быть проблема?
  • Вопрос задан
  • 100 просмотров
Решения вопроса 1
@MarkusD Куратор тега C++
все время мелю чепуху :)
Что такое инстансинг по своей сути?
Вот у нас есть геометрия и параметры ее обработки. Речь только о стадии обработки вершин.
Самая суть инстансинга в том, что геометрия у нас как бы находится в состоянии суперпозиции. Примитив у нас один, DIP тоже один, но в атрибутах примитива заложено что-то особенное, что заставляет увидеть его сразу во многих местах.
Это самое особенное - это атрибуты инстанса.

По умолчанию все атрибуты вершины являются атрибутами примитива. Когда работает DIP, вершинный шейдер запускается для обработки каждой отдельной вершины примитива. Когда инстансинг отключен, можно считать что все вершины примитива принадлежат ровно одному инстансу, для которого атрибутов не задано.
Но если примитив требуется отрисовать с использованием инстансинга, в его атрибутах должны находиться и атрибуты инстанса. Тогда во время работы уже DIPI вершинный шейдер будет запущен для каждой вершины примитива каждого инстанса.

Поэтому самым первым этапом включения инстансинга будет именно новый буфер атрибутов в шейдере.
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aOffset;


aOffset не должен быть uniform-ом. Это должен быть именно атрибут инстанса.
Uniform-ами стоит делать другие вещи, не уникальные между инстансами. Uniform-ы для инстанса имеются сразу и все. Поэтому рационально в них держать только то, что разные инстансы используют совместно.
Например - это могут быть цвета фракций или параметры костей скелетов в разных позах.
Примерный код вершинного шейдера
#version 460 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aOffset;

void main()
{
   gl_Position = vec4(aPos + aOffset, 0.0, 1.0);
}


Для указания того, что в буфере находятся атрибуты инстанса, следует использовать glVertexAttribDivisor[?].
У тебя, скорее всего, это будет выглядеть так: glVertexAttribDivisor( 1, 6 );.
А внутри буфера у тебя должно быть то, что сейчас записывается в glm::vec2 translations[100].
Как примерно может заполняться буфер атрибутов инстанса
glm::vec2 translations[100];
int index = 0;
float offset = 0.1f;
for (int y = -10; y < 10; y += 2)
{
	for (int x = -10; x < 10; x += 2)
	{
		glm::vec2 translation;
		translation.x = (float)x / 10.0f + offset;
		translation.y = (float)y / 10.0f + offset;
		translations[index++] = translation;
	}
}

glBindBuffer(GL_ARRAY_BUFFER, VBOs[3]);
glBufferData(GL_ARRAY_BUFFER, sizeof(translations), translations, GL_STATIC_DRAW);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), (GLvoid*)0);
glVertexAttribDivisor(1, 6);
glEnableVertexAttribArray(1);


С этого момента инстансинг заведется как положено. Просто убираем uniform, меняем подготовку его значений на подготовку еще одного буфера вершин, добавляем код установки этого нового буфера, задействуем его значения в шейдере и все. Эту теорию тебе остается только адаптировать для своего кода.
Чтобы разобраться почему у тебя конкретно сейчас рисуется неправильно, тебе нужно установить графический отладчик и проанализировать через него презентацию одного кадра. Советую поставить Renderdoc и научиться полноценно работать с ним. Без запуска твоего кода и анализа кадра выяснить причину неправильной работы практически невозможно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы