Я программирую рендеринг OpenGL на C++. Я хочу, чтобы он был настолько эффективным, насколько это возможно, и каждая вершина/нормальная/UV tex coord/tangents/etc должна занимать как можно меньше памяти. Я использую индексы, линейные полосы и поклонники. Я думал, что 32-битные плавающие точки не нужны, а 16-битные плавающие точки должны быть точными, по крайней мере для некоторых из них, таких как нормали и УФ. Кажется, я ничего не могу найти. Я могу найти разговор о «GL_HALF_FLOAT», но никаких реальных примеров. Я на правильном пути? Или это не стоит смотреть? Если кто-нибудь знает пример этого, они могут отправить ссылку на исходный код?«GL_HALF_FLOAT» с OpenGL Rendering и GLSL
ответ
Полный 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.
Вы можете упаковать и распаковать 2 полуполя с использованием типа данных 'uint'. Но самый маленький тип данных, который вы собираетесь получить в GLSL, - 32-разрядный. Подробнее см. ['Uint packHalf2x16 (\t vec2 v)'] (https://www.opengl.org/sdk/docs/man4/html/packHalf2x16.xhtml). –
@ AndonM.Coleman У вас могут быть данные HALF_FLOAT в буферах вершин. Разумеется, он будет расширен до 32-битной точности, как только он достигнет шейдера, но вы сохраните пространство памяти и пропускную способность, если для ваших координат достаточно пол-поплавка. –
@RetoKoradi: Я совершенно неправильно понял вопрос, потому что мой разум был где-то в другом месте: - Я видел тег и думал, что он хочет изменить точность 'float' в GLSL. Да, вы абсолютно правы, хотя, поскольку пол-поплавки не являются частью большинства языков, что-то вроде glm (при условии, что это C++) должно будет заполнить эту роль. –