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 может сделать все это для вас, с гораздо меньшими накладными расходами...