Атрибуты вершины - использование short вместо float для позиций вершин

В настоящее время у меня есть следующие настройки, которые работают хорошо на данный момент.

struct Vertex {
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoord;
}
std::vector<Vertex> vertices;

Атрибуты вершин:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position)); 
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::texCoord));

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

Рекомендации OpenGL Vertex Specification говорят мне следующее:

Позиции [...] Для этого вы переставляете данные пространства модели так, чтобы все позиции были упакованы в поле [-1, 1] вокруг начала координат. Вы делаете это, находя минимальные / максимальные значения в XYZ среди всех позиций. Затем вы вычитаете центральную точку поля min/max из всех положений вершин; с последующим масштабированием всех позиций на половину ширины / высоты / глубины поля min/max. Вы должны держать центральную точку и коэффициенты масштабирования вокруг. Когда вы строите матрицу модели для просмотра (или матрицу для модели), вам необходимо применить смещение центральной точки и масштаб в верхней части стека преобразования (так в конце, прямо перед рисованием).

Я также читал эту тему.

Вот почему я добавил этот шаг предварительной обработки, отображающий все вершины в [-1,1]

for (auto& v : vertices) {
    v.position = (v.position - center) * halfAxisLengths;
}

и вызвать его в вершинный шейдер

vec4 rescaledPos = vec4(in_pos, 1.0) * vec4(halfAxisLengths, 1.0) + vec4(center, 0.0);
gl_Position = P * V * M * rescaledPos;

Мой атрибут вершины, используя GL_SHORT вместо GL_FLOATи нормализовать установить на GL_TRUE:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_SHORT, GL_TRUE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position));

В результате я просто получаю хаос из треугольников, но не мою модель с увеличенным fps.

Это правильный способ установить атрибуты вершины на короткий?

Или я должен изменить свою полную структуру Vertex? Если да, каков наилучший способ сделать это (векторы glm с шортами?).

Работающий пример был бы великолепен, я не смог его найти.

2 ответа

Решение

Я настроил структуру данных для буфера вершин:

struct newVertex {
    GLshort position[4]; // for GL_SHORT
    GLint normal; // for GL_INT_2_10_10_10_REV
    GLshort texCoord[2]; // for GL_SHORT
};

В результате я получаю ~20% увеличение производительности.

Или я должен изменить свою полную структуру Vertex?

Да, OpenGL волшебным образом не сделает преобразование за вас. Но тогда, если производительность ваша цель...

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

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

Если ваша цель - производительность, придерживайтесь одинарной точности. Если вы мне не верите: сравните это.

Другие вопросы по тегам