2015-02-06 5 views
2

Я программирую рендеринг OpenGL на C++. Я хочу, чтобы он был настолько эффективным, насколько это возможно, и каждая вершина/нормальная/UV tex coord/tangents/etc должна занимать как можно меньше памяти. Я использую индексы, линейные полосы и поклонники. Я думал, что 32-битные плавающие точки не нужны, а 16-битные плавающие точки должны быть точными, по крайней мере для некоторых из них, таких как нормали и УФ. Кажется, я ничего не могу найти. Я могу найти разговор о «GL_HALF_FLOAT», но никаких реальных примеров. Я на правильном пути? Или это не стоит смотреть? Если кто-нибудь знает пример этого, они могут отправить ссылку на исходный код?«GL_HALF_FLOAT» с OpenGL Rendering и GLSL

+1

Вы можете упаковать и распаковать 2 полуполя с использованием типа данных 'uint'. Но самый маленький тип данных, который вы собираетесь получить в GLSL, - 32-разрядный. Подробнее см. ['Uint packHalf2x16 (\t vec2 v)'] (https://www.opengl.org/sdk/docs/man4/html/packHalf2x16.xhtml). –

+0

@ AndonM.Coleman У вас могут быть данные HALF_FLOAT в буферах вершин. Разумеется, он будет расширен до 32-битной точности, как только он достигнет шейдера, но вы сохраните пространство памяти и пропускную способность, если для ваших координат достаточно пол-поплавка. –

+0

@RetoKoradi: Я совершенно неправильно понял вопрос, потому что мой разум был где-то в другом месте: - Я видел тег и думал, что он хочет изменить точность 'float' в GLSL. Да, вы абсолютно правы, хотя, поскольку пол-поплавки не являются частью большинства языков, что-то вроде glm (при условии, что это C++) должно будет заполнить эту роль. –

ответ

4

Полный OpenGL (в отличие от OpenGL ES), шейдерный код всегда работает с 32-битными поплавками. Однако, начиная с OpenGL 3.0, указывать данные вершин как полупоплавки. Если точность достаточна для ваших нужд, это может уменьшить использование памяти для ваших данных вершин и уменьшить пропускную способность, необходимую для получения вершин.

Имейте в виду, что точность полуполя составляет всего 3-4 знака после запятой. Таким образом, точность действительно серьезно ограничена.

Как использовать их, это довольно просто. Если у вас есть указатель на значения с половинным поплавком, вы храните их в VBO, используя glBufferData() или glBufferSubData(), как и для любого другого типа. glVertexAttribPointer() вызов будет выглядеть следующим образом, используя атрибут с 3-х компонентов в качестве примера:

glVertexAttribPointer(loc, 3, GL_HALF_FLOAT, GL_FALSE, 0); 

формат самих данных определяется расширением ARB_texture_float. Хотя он официально не назван, он выглядит, по крайней мере, очень похож на формат IEEE 754-2008. Я написал код преобразования на основе этого описания в формате Википедии раньше, и он отлично работал для использования OpenGL.

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

Следующие ресурсы по полуполяному преобразованию - это быстрый поиск. У меня нет личного опыта с любым из них, и вы должны сделать свой собственный поиск, чтобы найти наиболее подходящий для ваших нужд:

  • Интересная статья от Intel, объясняя возможные преимущества по производительности: https://software.intel.com/en-us/articles/performance-benefits-of-half-precision-floats. Это также говорит о том, что процессоры Intel имеют инструкции для преобразования (например, есть встроенный _mm256_cvtps_ph для преобразования из float в float).
  • Библиотека с открытым исходным кодом для операций с пол-поплавком и конверсий: http://half.sourceforge.net/.
  • Документация gcc о том, что она поддерживает полупоплавкий тип (__fp16) для целей ARM.