GLSL: имитация 3D текстуры с 2D текстурой

Я придумал код, который имитирует 3D-текстуру, используя большую 2D-текстуру, которая содержит плитки. 3D-текстура имеет размер 128x128x64, а большая 2D-текстура имеет размер 1024x1024 и разделена на 64 фрагмента размером 128x128.

Код поиска в фрагментном шейдере выглядит следующим образом:

#extension GL_EXT_gpu_shader4 : enable

varying float LightIntensity;
varying vec3 pos;

uniform sampler2D noisef;
vec4 flat_texture3D()
{
    vec3 p = pos;
    vec2 inimg = p.xy;

    int d = int(p.z*128.0);
    float ix = (d % 8); 
    float iy = (d / 8);
    vec2 oc = inimg + vec2(ix, iy);
    oc *= 0.125;

    return texture2D(noisef, oc);
}

void main (void)
{
    vec4 noisevec = flat_texture3D();
    gl_FragColor = noisevec;
}

Логика листов работает нормально, и с этим кодом есть только одна проблема. Это выглядит так:

На что это похоже

Между слоями вокселей имеются странные полосы шириной от 1 до 2 пикселей. Полосы появляются только на границе, когда d изменения.
Я работаю над этим уже 2 дня и до сих пор не знаю, что здесь происходит.

1 ответ

Решение

Это похоже на проблему с текстурным фильтром. Подумайте об этом: когда вы приблизитесь к границе, билинейный фильтр будет рассматривать соседний тексель, в вашем случае: из другого "глубинного слоя".

Чтобы избежать этого, вы можете ограничить текстурные координаты так, чтобы они никогда не выходили за пределы прямоугольника, определенного вне центров текселей мозаичного элемента (аналогично GL_CLAMP_TO_EDGE, но для каждого элемента мозаичного изображения). Но вы должны знать, что проблемы станут хуже при использовании mipmapping. Вы также должны знать, что в настоящее время вы не можете фильтровать в направлении z, как это делает настоящая 3D-текстура. Конечно, вы можете смоделировать это вручную в шейдере.

Но на самом деле: почему бы просто не использовать 3D текстуры? HW может сделать все это для вас, с гораздо меньшими накладными расходами...

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