gpt4 book ai didi

java - 为什么我的着色器中的 GLSL 纹理坐标不是线性的?

转载 作者:行者123 更新时间:2023-11-30 04:20:32 25 4
gpt4 key购买 nike

我的 Android 2.3.4 Tegra 2 设备上的 glsl 着色器有问题。

我想做一些计算以在 glsl 着色器的 fragment 着色器中创建纹理坐标,并注意到一个问题并试图缩小它的范围,因此制作了一个测试程序。我在屏幕上渲染了一个宽度为 256 像素到恰好 256 像素的纹理,保存帧缓冲区并逐个像素地检查它(与源代码比较)并且它正确渲染。根据 opengl 规范,当我使用从 0.0 到 1.0 的纹理坐标时,它应该对中心的每个像素进行采样(0.5/256、1.5/256、2.5/256 等),这似乎是正确的。

然后我将 x 纹理坐标本身写入纹理并进行检查。结果有点不对劲,我不知道为什么。我没有得到 0..255 的梯度,而是得到了 1..128,128..255。这意味着值 0 被跳过,值 128 出现两次,这意味着它们不是完全线性的。如果该值以任何方式四舍五入,那么对我来说不是显而易见的方式。我还检查了纹理坐标的子像素值,它们是我所期望的。它们的值始终为 0.5/256,应该是半个像素,并确保纹理在像素内正确采样。

同样,用这些坐标渲染的纹理正是我想要的,但坐标本身并不是我所期望的。这对我来说是个问题,因为我想用计算出的纹理坐标进行渲染,虽然我以正确的方式计算它们,但结果纹理是错误的。我需要这些坐标在像素级别上是正确的,但我不知道为什么它们会关闭。

有谁知道是什么导致了这种行为以及我该如何纠正它?

这是正确渲染纹理的 fragment 着色器:

precision mediump   float;
varying vec2 vtex;
uniform sampler2D samp0;
void main() {
gl_FragColor = texture2D(samp0, vtex);
};

这是 fragment 着色器,它创建一个纹理坐标为 1..128,128..255 而不是我预期的 0..255 的渐变:

precision mediump   float;
varying vec2 vtex;
uniform sampler2D samp0;
void main() {
gl_FragColor = vec4(vtex.x, 0, 0, 1.0);
};

这是 fragment 着色器,它为纹理坐标的子像素值创建颜色,并按我的预期提供所有值为 127 的纹理,它应该是像素的中心:

precision mediump   float;
varying vec2 vtex;
uniform sampler2D samp0;
void main() {
gl_FragColor = vec4(fract(vtex.x * 256.0), 0, 0, 1.0);
};

其余的测试程序完全相同。我只更改着色器。这些是一些重要的代码 fragment :

String vertexshader =
"attribute vec4 a_pos; \n" + // in position
"attribute vec2 a_tex; \n" + // in Texture coordinates
"varying vec2 vtex; \n" + // out Texture coordinates
"void main(void) { \n" +
" gl_Position = vec4(a_pos); \n" +
" vtex = a_tex; \n" +
"}";


// Initialization

GLES20.glUseProgram(shader);
// Vertex
vdata.position(0);
GLES20.glVertexAttribPointer(handlepos, 2, GLES20.GL_FLOAT, false, 4*4, vdata);
GLES20.glEnableVertexAttribArray(handlepos);
vdata.position(2);
GLES20.glVertexAttribPointer(handletex, 2, GLES20.GL_FLOAT, false, 4*4, vdata);
GLES20.glEnableVertexAttribArray(handletex);
// Texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, maplookupid[1]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST );
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST );
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT );
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT );
GLES20.glUniform1i(handlesampler0, 0);
GLES20.glDisable(GLES20.GL_DITHER);

// Rendering

GLES20.glViewport(0, 0, screenx, screeny);
//
vdata.put(0*4+0, 0.0f * (2.0f/screenx));
vdata.put(0*4+1, 256.0f * (2.0f/screeny));
vdata.put(0*4+2, 0.0f * (1.0f/256.0f));
vdata.put(0*4+3, 256.0f * (1.0f/256.0f));
//
vdata.put(1*4+0, 0.0f * (2.0f/screenx));
vdata.put(1*4+1, 0.0f * (2.0f/screeny));
vdata.put(1*4+2, 0.0f * (1.0f/256.0f));
vdata.put(1*4+3, 0.0f * (1.0f/256.0f));
//
vdata.put(2*4+0, 256.0f * (2.0f/screenx));
vdata.put(2*4+1, 256.0f * (2.0f/screeny));
vdata.put(2*4+2, 256.0f * (1.0f/256.0f));
vdata.put(2*4+3, 256.0f * (1.0f/256.0f));
//
vdata.put(3*4+0, 256.0f * (2.0f/screenx));
vdata.put(3*4+1, 0.0f * (2.0f/screeny));
vdata.put(3*4+2, 256.0f * (1.0f/256.0f));
vdata.put(3*4+3, 0.0f * (1.0f/256.0f));

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

最佳答案

看起来您遇到了舍入问题。由于您显然使用的是 8 位颜色缓冲区,因此通过将颜色乘以 255 将颜色转换为像素值。因此您的纹理值 0.5/256 将乘以 255 以产生 0.498 的像素值,这在理想世界中(在 GPU 上进行无限精度计算并四舍五入到最接近的值)将转换为 0 字节值。

事实上,从您得到 1..128,128..255(128 是重复值)的事实来看,它看起来像是向上舍入转换(因为 (127.5/256)*255 是 127.002 和 (128.5/256 )*255 是 127.998——它们是转换为 128 的两个像素)。如果这是正在发生的事情,我希望您的第 3 个测试程序在每个像素中产生 128,而不是 127(因为 0.5*255 == 127.5)

结果是您不能指望 GPU 进行极其精确的计算——舍入误差的来源有很多。

关于java - 为什么我的着色器中的 GLSL 纹理坐标不是线性的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9322507/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com