为了实现this idea,我编写了以下两个版本的顶点和片段着色器:
// Vertex:
precision highp int;
precision highp float;
uniform vec4 r_info;
attribute vec2 s_coords;
attribute vec2 r_coords;
varying vec2 t_coords;
void main (void) {
int w = int(r_info.w);
int x = int(r_coords.x) + int(r_coords.y) * int(r_info.y);
int y = x / w;
x = x - y * w;
y = y + int(r_info.x);
t_coords = vec2(x, y) * r_info.z;
gl_Position = vec4(s_coords, 0.0, 1.0);
}
// Fragment:
precision highp float;
uniform sampler2D sampler;
uniform vec4 color;
varying vec2 t_coords;
void main (void) {
gl_FragColor = vec4(color.rgb, color.a * texture2D(sampler, t_coords).a);
}
VS
// Vertex:
precision highp float;
attribute vec2 s_coords;
attribute vec2 r_coords;
varying vec2 t_coords;
void main (void) {
t_coords = r_coords;
gl_Position = vec4(s_coords, 0.0, 1.0);
}
// Fragment:
precision highp float;
precision highp int;
uniform vec4 r_info;
uniform sampler2D sampler;
uniform vec4 color;
varying vec2 t_coords;
void main (void) {
int w = int(r_info.w);
int x = int(t_coords.x) + int(t_coords.y) * int(r_info.y);
int y = x / w;
x = x - y * w;
y = y + int(r_info.x);
gl_FragColor = vec4(color.rgb, color.a * texture2D(sampler, vec2(x, y) * r_info.z).a);
}
它们之间的唯一区别(我希望)是纹理坐标转换的位置。在第一个版本中,数学发生在顶点着色器中,第二个发生在片段着色器中。
现在,官方OpenGL ES SL 1.0 Specifications声明“顶点语言必须提供至少16位的整数精度,加上符号位”和“[t]他片段语言必须提供至少10位的整数精度,加上符号位“(第4.5.1章)。如果我理解正确,这意味着只给出一个最小的实现,我应该能够在顶点着色器中获得的精度应该优于片段着色器中的精度,对吗?但是,由于某些原因,代码的第二版本正常工作,而第一个版本导致一堆舍入错误。我错过了什么吗?
答案 0 :(得分:0)
原来我从根本上误解了事情的运作方式......也许我仍然这样做,但让我根据目前的理解回答我的问题:
我认为对于每个渲染的像素,首先执行顶点着色器然后执行片段着色器。但是,如果我现在理解正确的话,顶点着色器只针对三角形图元的每个顶点调用一次(这样,它的名称也是有意义的)。
所以,我上面代码的第一个版本只计算我绘制的三角形的实际角点(顶点)的正确纹理坐标。对于三角形中的所有其他像素,纹理坐标只是这些角坐标之间的线性插值。当然,由于我的公式不是线性的(包括舍入和模运算),这会导致每个像素的纹理坐标错误。
第二个版本将非线性变换应用于每个像素位置的纹理坐标,在任何地方给出正确的纹理坐标。
所以,广义学习(以及我没有删除问题的原因):
必须在片段着色器中完成所有非线性纹理坐标转换。