opengl-es - 使用数据纹理

标签 opengl-es glsl webgl

我问this question在关于如何将数据数组传递给片段着色器以对地形进行着色之前,有人建议我可以使用纹理的 RGBA 值。

我现在正试图弄清楚如何使用 yzw 值。这是我的片段着色器代码:

vec4 data = texture2D(texture, vec2(verpos.x / 32.0, verpos.z / 32.0));
float blockID = data.x;
vec4 color;

if (blockID == 1.0) {
    color = vec4(0.28, 0.52, 0.05, 1.0);
}
else if (blockID == 2.0) {
    color = vec4(0.25, 0.46, 0.05, 1.0);
}
else if (blockID == 3.0) {
    color = vec4(0.27, 0.49, 0.05, 1.0);
}

gl_FragColor = color;

这工作正常,但是正如您所看到的,它仅使用 x 坐标中的 float 。如果还使用 yzw 坐标,纹理大小可以减小到 16x16,而不是 32x32(小四倍)。

这样做的目的是创建一个体素类型的地形,其中每个“ block ”的空间坐标为 1x1,并根据 block ID 进行着色。看起来像这样: enter image description here

在 GLSL 之外,这很简单,但是由于无法存储已计算的 block ,我发现这很困难。毫无疑问,我想得太多了,这可以通过一些简单的数学来完成。


编辑:
基于 Wagner Patriota 答案的代码:

vec2 pixel_of_target = vec2( verpos.xz * 32.0 - 0.5 ); // Assuming verpos.xz == uv_of_target ?

// For some reason mod() doesn't support integers so I have to convert it using int()
int X = int(mod(pixel_of_target.y, 2.0) * 2.0 + mod(pixel_of_target.x, 2.0));

// Gives the error "Index expression must be constant"
float blockID = data[ X ];

关于错误,我asked a question之前的那件事实际上导致我问了这个。 :P
有任何想法吗?谢谢! :)

最佳答案

这个想法是替换:

float blockID = data.x;

float blockID = data[ X ];

其中 X 是一个整数,允许您从 16x16 数据图像中选择 R、G、B 或 A。

问题是如何根据 UV 计算 X

好的,您有一个目标图像 (32x32) 和数据图像 (16x16)。那么让我们这样做:

ivec pixel_of_target = ivec( uv_of_target * 32.0 - vec2( 0.5 ) ); // a trick!

将 UV 与纹理尺寸(本例中为 32)相乘,即可找到精确的像素。 -0.5 是必要的,因为您正在尝试“从纹理中查找像素”。当然,纹理在“像素中心”之间插入了值。您需要像素的精确中心...

您的pixel_of_target是一个ivec(整数),您可以准确地识别您正在绘制的位置!所以现在的事情是确定(基于您正在绘制的像素)您应该从 16x16 纹理获取哪个 channel 。

int X = ( pixel_of_target.y % 2 ) * 2 + pixel_of_target.x % 2;
float blockID = data[ X ]; // party on!

上面的表达式允许您根据目标像素选取正确的索引X!在你的“数据纹理”16x16上将你的(R,G,B,A)映射到目标上每组4个像素的(左上,右上,左下,右下)(或者可能是上侧-如果你愿意的话,可以下来...你可以弄清楚)

更新:

因为您使用的是 WebGL,所以一些细节应该更改。我这样做了并且成功了。

vec2 pixel_of_target = vTextureCoord * 32.0 + vec2( 0.5 ); // the signal changed!
int _x = int( pixel_of_target.x );
int _y = int( pixel_of_target.y );
int X = mod( _y, 2 ) * 2 + mod( _x, 2 );

我用它来进行测试:

if ( X == 0 )
    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
else if ( X == 1 )
    gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
else if ( X == 2 )
    gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
else if ( X == 3 )
    gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );

我的图像效果非常好:

Zoom

这里我用 Photoshop 进行缩放来查看像素的细节。

PS1:因为我对WebGL不熟悉,所以我无法在Chrome中运行WebGL,我尝试使用Firefox,但我也没有找到mod()函数...所以我这样做了:

int mod( int a, int b )
{
    return a - int( floor( float( a ) / float( b ) ) * float( b ) );
}

PS2:我不知道为什么我必须对 vec2( 0.5 ) 求和而不是相减。 WebGL 有点不同。大概有这样的转变。我不知道...它只是有效。

关于opengl-es - 使用数据纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19672386/

相关文章:

ios - iOS:设备定向事件在启动后永远不会到来

c++ - glsl - 获取像素颜色 [像素着色器]

three.js - GLSL:具有自定义着色器的 ShaderMaterial 不透明

webgl - 如何使用 WebGL 制作短片

opengl - 使用 std430 限定符进行内存分配

javascript - WebGL 无效操作缓冲区大小不足

android - 了解 Android 中的 android.graphics.Camera 对象

android - opengl ES OES 与 EXT?

iphone - OpenGL + 相机 View (iPhone)

c++ - 将具有浮点值的纹理传递给着色器