OpenGL / GLSL - написание умного текстурного шейдера - PullRequest
4 голосов
/ 08 октября 2011

Допустим, моя текстура имеет размер 256x256 пикселей.Он содержит 16 субтекстур размером 64x64 пикселей.Субтекстуры должны быть визуализированы в квадраторы.Чтобы повысить производительность, я хочу передать дискретные значения шейдеру, который кодирует координаты текстуры каждой вершины.Например, значения 0, 1, 2, 3 должны соответствовать (0,64), (64,64), (64,0), (0,0) на координаты текстуры вершины и т. Д.

Здесьэто то, что у меня есть.

Я загружаю и связываю текстуру mipmap:

glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D,3,TextureImage[0]->w,TextureImage[0]->h,GL_RGB,GL_UNSIGNED_BYTE,TextureImage[0]->pixels);

Затем я загружаю свои данные:

glGenVertexArrays(1, &VecArrObj);
glBindVertexArray(VecArrObj);

glGenBuffers(1, &VertexBO);
glBindBuffer(GL_ARRAY_BUFFER, VertexBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertAndTex), VertAndTex, GL_STREAM_DRAW);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_SHORT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 1, GL_SHORT, GL_FALSE, 0, (void*)TexOffset);

glGenBuffers(1, &IndexBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indx), Indx, GL_STREAM_DRAW);

Здесь атрибуты ранееправильно назначен myProgram с помощью glBindAttribLocation.Вот как я отображаю свои четырехугольники:

glUseProgram(myProgram);
glBindVertexArray(VecArrObj);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glUseProgram(0);

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

Вершинный шейдер:

#version 130

in vec4 posit;  //attr=0
in short textu; //attr=1
uniform mat4 trafoMat;

void main()
{
gl_Position = trafoMat * posit;
gl_TexCoord[0] = gl_MultiTexCoord0;
}

Фрагментный шейдер:

#version 130

uniform sampler2D tex;
out vec4 outColor;

void main()
{
outColor = texture2D(tex,gl_TexCoord[0].st);
}

Где текс равен нулю.Эти шейдеры даже не получают всю текстуру, а устанавливают только один квадрат на один цвет из текстуры (я думаю, это пиксель в верхнем левом углу).Очевидно, у меня нет большого опыта работы с шейдерами.По сути, мой вопрос: как мне изменить мои шейдеры для целей, описанных в начале?(Я способен выполнить математику для текстурных координат для каждой вершины - мне прежде всего нужен совет, как обрабатывать текстуры в шейдерах. Обратите внимание: мое оборудование не поддерживает glGenSamplers ()).

1 Ответ

3 голосов
/ 09 октября 2011

Прежде всего, если вы не используете простое отображение (то есть f (x) -> (u, v), где f - некоторая простая функция), вы должны создать текстуру косвенного обращения, которая выполняет отображение. В вашем случае это будет 1D текстура с 16 (двухкомпонентными) записями.

Во-вторых, вам нужно point-sample в текстуру косвенного направления, чтобы узнать, где взять образец из фактической текстуры. Предполагая, что ваши квады имеют 0,1 UV-координаты, полученный шейдер будет выглядеть примерно так:

// gl_TexCoord[0].st is 0..1, per quad
void main ()
{
    gl_Position = trafoMat * posit;
    // 0..1 UV coordinate
    gl_TexCoord[0] = gl_MultiTexCoord0;
    // Rescale into sub-tile
    gl_TexCoord[0] *= (1/4.0);
    // Add the offset, if your hardware does not support
    // texture fetches in the vertex shader, move this into the
    // fragment shader.
    // gl_MultiTexCoord1 is the 1D offset into the indirection
    // texture
    gl_TexCoord[0] += texture2D(offsetTexture,gl_MultiTexCoord1);
}

// This is the fragment shader!
void main ()
{
    outColor = texture2D(tex,gl_TexCoord[0]);
}

Текстура tex, скорее всего, должна быть линейно отфильтрована, а offsetTexture нужна точка - вы можете установить их вручную без использования сэмплеров, используя glTexParameter .

...