Туннельный шейдер (преобразованный из WebGL в OpenGL) - координаты текстуры не совпадают?

На прошлой неделе я пытался преобразовать классический демонстрационный эффект туннеля из различных примеров 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);
}

person sphere42    schedule 17.11.2013    source источник
comment
Извините за ссылки внизу. Похоже, StackOverflow дает вам очень умные подсказки, когда вы создаете свой вопрос, но, возможно, было бы неплохо сказать вам, что вы не можете публиковать изображения и более двух ссылок, если ваша репутация ниже 10 ДО того, как вы нажмете вопрос Опубликовать.   -  person sphere42    schedule 17.11.2013
comment
Вы говорите, что изначально это был шейдер WebGL? Вы совершили серьезную ошибку, если это было скопировано дословно, WebGL (технически OpenGL ES 2.0) не требуется для обеспечения точности highp во фрагментном шейдере. Вам необходимо проверить наличие определения препроцессора: GL_FRAGMENT_PRECISION_HIGH перед объявлением чего-либо highp во фрагментном шейдере. В противном случае этот шейдер не сможет скомпилировать на некоторых аппаратных / программных реализациях.   -  person Andon M. Coleman    schedule 17.11.2013
comment
Нет, это не вызывает проблем. Я почистил код, он был очень беспорядочным после многих проб и ошибок, и эта строка осталась. Конечно, я попробовал и удалил, но ничего существенного не изменилось.   -  person sphere42    schedule 18.11.2013
comment
Я не предполагал, что это решит вашу проблему. Я указывал, что на самом деле это проблема сама по себе;)   -  person Andon M. Coleman    schedule 18.11.2013
comment
Извините, я неправильно это понял. Я искал прямое решение, но вы правы, я рассмотрю GL_FRAGMENT_PRECISION_HIGH и остальные различия между WebGL и OpenGL, так как это может пригодиться позже :)   -  person sphere42    schedule 18.11.2013


Ответы (1)


Вы не указали множество деталей (например, какие значения вы используете для texcoord). Тем не менее, я думаю, что все еще могу объяснить, почему ваш код приводит к доступу только к нижней строке (вы можете думать об этом как о верхней строке, когда используете массив изображений сверху вниз в качестве данных изображения для glTexImage(), но технически это будет нижний ряд.)

Вы используете uv в качестве координат при получении текстуры. И вы определяете uv.y как atan(position.y, position.x)/3.1415. Поскольку atan() вернет vlue в [-pi, pi], вы нормализуете координату примерно до интервала [-1,1]. Классическое пространство текстур OpenGL - это [0,1], где 0 - это нижняя строка, а 1 - верхняя строка. Однако вы используете sampler2DRect, поэтому вы используете текстуры прямоугольника. В этом случае координаты текс не нормализуются, а координаты пикселей [0,width] по горизонтали и [0,height] в вертикальном направлении.

Фактически, ваши текстовые координаты различаются только в диапазоне двух текселей. В зависимости от того, какие режимы переноса (и фильтрации) вы установили, вы должны получить доступ только к нижней строке (или фильтрации между двумя нижними строками) с хлопком или дополнительно к верхней строке (или фильтрации между двумя верхними строками) с GL_REPEAT для отрицательные части.

person derhass    schedule 17.11.2013
comment
Вот и все! Я не ожидал такой радикальной разницы между sampler2d и sampler2dRect. Похоже, что координаты текстуры 0,0,512,512, а не от 0 до 1, как я ожидал. Единственное, что меня беспокоит, это то, что я не могу использовать sampler2d в openFrameworks, поскольку он мне ничего не показывает. Но умножение полученных координат на размеры текстуры вроде как решает проблему. Кроме того, мне нужно написать некоторую функцию повтора, потому что GL_REAPEAT тоже не работает. - person sphere42; 18.11.2013
comment
Рад сообщить, что шейдер работает , как и должно быть!. Кроме того, репозиторий для всего проекта доступен на github для просмотра другими пользователями - person sphere42; 18.11.2013