На прошлой неделе я пытался преобразовать классический демо-эффект туннеля из различных примеров WebGL в openFrameroks (используя шейдер OpenGL GLSL). После многих исследований, проб и ошибок и, в основном, после прочтения [этого всеобъемлющего урока] [1] и [и этого тоже] [2], я все еще не понимаю, почему не работает конвертированный шейдер. Похоже, это какая-то проблема с текстурными координатами, по крайней мере, я так думаю.
Насколько я понимаю принцип, вы получаете значения пикселей из текстуры, вычисляя угол и расстояние от центра и передавая их в качестве выходных данных. Но результаты сильно отличаются.
Вот результат из [примера ShaderToy] [3] и [вот пример] [4] из кода, с которым я начал экспериментировать. И вот что я получил в openFrameworks:
! [введите описание изображения здесь] [5] с этой текстурой, переданной в шейдер:
! [введите описание изображения здесь] [6]
Похоже, что шейдер просто проходит через верхний ряд пикселей, потому что через некоторое время экран остается одного цвета (это как достижение конца туннеля). Я попытался использовать текстуру только с цветовым шумом, так как пиксели и цвет финальной стадии были ровно желтыми, как последний пиксель в верхней строке. Странный.
Надеюсь, кто-нибудь скажет мне, где проблема.
Вот testApp.cpp
void testApp::setup(){
texture.loadImage("koalaSQ.jpg"); // 512x512px
tunnel.load("tunnel.vert", "tunnel.frag");
projection.set(640, 480);
projection.setPosition(320, 240, 0);
projection.setResolution(2,2);
projection.mapTexCoordsFromTexture(texture.getTextureReference());
}
void testApp::draw(){
ofSetColor(255);
if (ofGetKeyPressed('g')) // used just for testing texture
{
ofBackground(0, 0, 0);
texture.bind();
projection.draw();
texture.unbind();
}else
{
ofBackground(0, 0, 0);
tunnel.begin();
tunnel.setUniform1f("timeE", time/1000);
tunnel.setUniform2f("resolution", 512,512);
tunnel.setUniformTexture("tex", texture.getTextureReference(), 0);
projection.draw();
tunnel.end();}
time = ofGetElapsedTimeMillis();
}
а вот и шейдеры:
// vertex shader - simple pass-though with texcoodrs as output for fragent shader
#version 150
uniform mat4 modelViewProjectionMatrix;
in vec4 position;
in vec2 texcoord;
out vec2 texC;
void main()
{
gl_Position = modelViewProjectionMatrix * position;
texC = texcoord;
}
// ------------------------Fragent shader----------------------
#version 150
precision highp float;
uniform sampler2DRect tex;
uniform float timeE;
uniform vec2 resolution;
in vec2 texC;
out vec4 output;
void main(){
vec2 position = 2.0 * texC.xy / resolution.xy -1.0;
position.x *= resolution.x / resolution.y;
float a = atan(position.y, position.x);
float r = length(position);
vec2 uv = vec2(1/ r + (timeE*5), a/3.1416);
vec3 texSample = texture(tex, uv).xyz;
output = vec4(vec3(texSample), 1);
}
Есть много деталей, которые вы не указали (то есть, какие значения вы используете для texcoord). Тем не менее, я думаю, что я все еще могу объяснить, почему ваш код приводит к доступу только к нижней строке (вы можете думать о ней как о верхней строке, когда используете массив изображений сверху вниз в качестве данных изображения для glTexImage()
, но технически это будет нижний ряд.)
Ты используешь uv
как координаты при извлечении текстуры. И вы определяете uv.y
быть atan(position.y, position.x)/3.1415
, поскольку atan()
вернет водку в [-pi, pi]
Вы нормализуете координаты примерно до интервала [-1,1]
, Классическое пространство текстур OpenGL [0,1]
где 0 будет нижний ряд и 1 верхний ряд. Тем не менее, вы используете sampler2DRect
так что вы используете текстуры прямоугольника. В этом случае координаты текс не нормализуются, а координаты пикселей [0,width]
в горизонтальном направлении и [0,height]
в вертикальном направлении.
По сути, ваши текскорды различаются только в диапазоне два тексели. В зависимости от того, какие режимы обтекания (и фильтрации) вы установили, доступ к нижнему ряду (или фильтрация между двумя нижними рядами) должен выполняться только с помощью хлопка, или дополнительно к верхнему ряду (или фильтрации между двумя верхними рядами) с помощью GL_REPEAT
для отрицательных частей.
Других решений пока нет …