У меня есть 2+ прохода рендеринга, где первый этап генерирует положения вершин прямоугольной сетки и сохраняет их в 2D-текстуре с плавающей точкой. Шейдеры выглядят так:
вершина:
#version 330 core
out vec2 vfTexCoords;
const float halfSide = 1.0f;
const vec2[] pos = vec2[ 4 ]
(
vec2( -halfSide, -halfSide ),
vec2( halfSide, -halfSide ),
vec2( halfSide, halfSide ),
vec2( -halfSide, halfSide )
);
const vec2[] tex = vec2[ 4 ]
(
vec2( 0.0f, 0.0f ),
vec2( 1.0f, 0.0f ),
vec2( 1.0f, 1.0f ),
vec2( 0.0f, 1.0f )
);
void main()
{
vfTexCoords = tex[ gl_VertexID ];
gl_Position = vec4( pos[ gl_VertexID ], 0.0f, 1.0f );
}
фрагмент:
in vec2 vfTexCoords;
layout (location = 0) out vec3 pos;
void main()
{
pos = vec3( vfTexCoords, 0.0f );
}
Размер выходной 2D плавающей текстуры изменяется в соответствии с размерами прямоугольной сетки вершин и привязывается к одному из цветовых вложений FBO. Таким образом, размер FBO наследуется от размера текстуры.
Окно просмотра настроено так, чтобы иметь те же размеры, что и размер прямоугольной сетки:
glViewport( 0, 0, horizontalVerticesCount, verticalVerticesCount );
Итак, теперь и область просмотра, и текстура имеют одинаковый размер и после:
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
… положения выходных вершин должны варьироваться от vec3 (0,0, 0,0, 0,0) до vec3 (1,0, 1,0, 0,0), поскольку координаты текстуры варьируются от 0,0, 0,0 до 1,0, 1,0.
Что странно, так это то, что значения x и y выходных позиций вершин из фрагментного шейдера начинаются с ненулевого значения, а их максимальное значение ниже 1,0.
Для сетки 2 х 2:
внизу слева: vec3 (0,25, 0,25, 0,0) (0,5 / mesh_side = 0,5 / 2 = 0,25)
вверху справа: vec3 (0,75, 0,75, 0,0)
Для сетки 16 х 16:
внизу слева: vec3 (0,03125, 0,03125, 0,0) (0,5 / mesh_side = 0,5 / 16 = 0,03125)
вверху справа: vec3 (0,96875, 0,96875, 0,0)
Если положение вершинного шейдера установлено от vec3 (-1,0, -1,0, 0,0) до vec3 (1,0, 1,0, 0,0), это должно означать, что я «рисую» по всему окну просмотра.
Изменение позиций вершинного шейдера приводит к различным выходным значениям из фрагментного шейдера.
Что не так с кодом выше и почему рисование начинается с 0.5 / rect_mesh_side_length?
Вот изначально опубликовано вопрос.
Какие-либо предложения?
Входные данные фрагмента шейдера интерполируются в центрах пикселей. Раздел 15.2.2 спецификации OpenGL 4.5 (https://www.opengl.org/registry/doc/glspec45.core.pdf) «Входы шейдеров» предоставляет подробное описание этого поведения и того, как им можно управлять.
Вот схема, которую я быстро нарисовал только для иллюстрации.
Поскольку у вас уже есть известные размеры сетки, вы можете передать их как однородные переменные и использовать следующий код в своем фрагментном шейдере. Это даст вам координаты от 0,0 до 1,0 включительно.
vec2 coord = floor(gl_FragCoord.xy) / vec2(horizontalVerticesCount - 1.0, verticalVerticesCount - 1.0);