我在过去一周尝试将来自不同 WebGL 示例的经典隧道演示效果转换为 openFrameroks(使用 OpenGL GLSL 着色器)。经过大量研究、试验和错误,主要是在阅读了 [这个综合教程][1] 和 [这个教程][2] 之后,我仍然不明白为什么转换后的着色器不起作用。至少我认为这可能是纹理坐标的某种问题。
就我对原理的理解而言,您可以通过计算与中心的角度和距离来从纹理中获取像素值,并将它们作为输出传递。但结果却大不相同。 这是 [ShaderToy 示例][3] 的结果,[这里是示例][4] 来 self 开始试验的代码。这是我在 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]
中返回一个 vlue,因此您可以将坐标大致标准化为区间 [-1,1]
。经典的 OpenGL 纹理空间是 [0,1]
,其中 0 表示底行,1 表示顶行。但是,您使用的是 sampler2DRect
,所以您使用的是 rectangle textures .在那种情况下,tex 坐标未被归一化,但像素坐标 [0,width]
在水平方向和 [0,height]
在垂直方向。
实际上,您的纹理坐标确实只在两个 纹理元素的范围内变化。根据您设置的换行(和过滤)模式,您应该只通过拍手访问底行(或在底两行之间过滤),或者使用 访问顶行(或在两行之间过滤) GL_REPEAT
负数部分。
关于c++ - 隧道着色器(从 WebGL 转换为 OpenGL)- 纹理坐标不匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20029702/