我问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 进行着色。看起来像这样:
在 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 );
我的图像效果非常好:
这里我用 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/