GLSL 棋盘图案

问题描述 投票:0回答:6

我想用棋子给四边形着色:

f(P)=[下限(Px)+下限(Py)]mod2。

我的四边形是:

glBegin(GL_QUADS);    
  glVertex3f(0,0,0.0);    
  glVertex3f(4,0,0.0);    
  glVertex3f(4,4,0.0);   
  glVertex3f(0,4, 0.0); 
glEnd();

顶点着色器文件:

varying float factor;
float x,y;
void main(){
  x=floor(gl_Position.x);
  y=floor(gl_Position.y);
  factor = mod((x+y),2.0);
}

片段着色器文件是:

varying float factor;
void main(){
  gl_FragColor = vec4(factor,factor,factor,1.0);
}

但我明白了:

alt text

似乎 mod 功能不起作用或者可能是其他原因...... 有什么帮助吗?

glsl
6个回答
18
投票

最好在片段着色器中计算这种效果,类似这样:

顶点程序=>

varying vec2 texCoord;

void main(void)
{
   gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
   gl_Position = sign(gl_Position);
    
   texCoord = (vec2(gl_Position.x, gl_Position.y) 
             + vec2(1.0)) / vec2(2.0);      
}

片段程序=>

#extension GL_EXT_gpu_shader4 : enable
uniform sampler2D Texture0;
varying vec2 texCoord;

void main(void)
{
    ivec2 size = textureSize2D(Texture0, 0);
    float total = floor(texCoord.x * float(size.x)) +
                  floor(texCoord.y * float(size.y));
    bool isEven = mod(total, 2.0) == 0.0;
    vec4 col1 = vec4(0.0, 0.0, 0.0, 1.0);
    vec4 col2 = vec4(1.0, 1.0, 1.0, 1.0);
    gl_FragColor = (isEven) ? col1 : col2;
}

输出=>

alt text

祝你好运!


5
投票

在片段着色器中尝试此功能:

vec3 checker(in float u, in float v)
{
  float checkSize = 2;
  float fmodResult = mod(floor(checkSize * u) + floor(checkSize * v), 2.0);
  float fin = max(sign(fmodResult), 0.0);
  return vec3(fin, fin, fin);
}

然后在 main 中你可以使用以下方式调用它:

vec3 check = checker(fs_vertex_texture.x, fs_vertex_texture.y);

只需传递从顶点着色器获得的 x 和 y 即可。之后您所要做的就是在计算 vFragColor 时将其包含在内。

请记住,您只需修改 checkSize 值即可更改检查大小。


4
投票

您的代码所做的是计算因子 4 次(每个顶点一次,因为它是顶点着色器代码),然后插入这些值(因为它被写入变化的变量中),然后在片段着色器中将该变量输出为颜色。

所以它不是这样工作的。您需要直接在片段着色器中进行该计算。您可以使用片段着色器中的 gl_FragCoord 内置变量来获取片段位置。


4
投票

我可以提出以下建议:

float result = mod(dot(vec2(1.0), step(vec2(0.5), fract(v_uv * u_repeat))), 2.0);
  • v_uv 是 UV 值的 vec2,
  • u_repeat 是每个轴应重复模式次数的 vec2。
  • 结果为0或1,可以在mix函数中使用它来提供颜色,例如:
gl_FragColor = mix(vec4(1.0, 1.0, 1.0, 1.0), vec4(0.0, 0.0, 0.0, 1.0) result);

3
投票

另一种不错的方法是平铺已知图案(缩小)。假设你有一个正方形画布:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;
    uv -= 0.5; // moving the coordinate system to middle of screen
    // Output to screen
    fragColor = vec4(vec3(step(uv.x * uv.y, 0.)), 1.);
}

上面的代码给了你这种模式。 square pattern

下面的代码只需缩放 4.5 倍并取小数部分即可重复该模式 4.5 次,从而每行有 9 个正方形。

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fract(fragCoord/iResolution.xy * 4.5);
    uv -= 0.5; // moving the coordinate system to middle of screen
    // Output to screen
    fragColor = vec4(vec3(step(uv.x * uv.y, 0.)), 1.);
}

square pattern repeated


0
投票

当前的答案都提供了很好的解决方案,但也都依赖于浮点运算,例如

mod
fract
floor
。这种方法将浮点数转换为整数,使用最少的操作,因此有可能更快。至少,它展示了一种替代实现。

片段着色器:

const vec3 white = vec3(1.0F);
const vec3 black = vec3(0.0F);

in vec2 uv; // In range [0, 1]^2
uniform float scale = 8.0F; // The number of squares in one dimension
out vec4 fragColor;

void main()
{
    ivec2 uvInt = ivec2(scale * uv); // Scale and truncate the fractional part
    bool isOdd = bool((uvInt.x + uvInt.y) & 1); // Odd or even check using a bit-wise operation
    fragColor = vec4(isOdd ? white : black, 1.0F);
}

在将四边形的 uv 坐标发送到 GPU 之前将其与

scale
相乘并忽略片段着色器中的缩放,可以提高效率。

最初的问题是在 2011 年提出的,并使用

varying
,这意味着旧的 GLSL 版本的目标是什么。按位运算可能无法在所有/大多数硬件上使用,因为这些运算是在 GLSL 130(2009 年 11 月)中引入的。在这种情况下,奇偶检查可以用
(uvInt.x + uvInt.y) % 2 == 1
代替。如果余数运算符也不可用(例如,在较旧的 WebGL 版本上有时会出现这种情况),则可以使用以下技巧 - 使用整数除法:

int sum = uvInt.x + uvInt.y;
vec3 color = sum / 2 * 2 == sum ? white : black;

输出:

8x8_checkboard

如果四边形是矩形,那么棋盘将包含黑白矩形而不是正方形:

8x8_rectangles

要对此进行调整,需要考虑宽高比。 ShaderToy的示例代码,方便实验,与 WebGL 1 兼容:

const vec3 white = vec3(1.0);
const vec3 black = vec3(0.0);
const float scale = 8.0; // The number of *vertical* squares

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    float aspectRatio = iResolution.x / iResolution.y;

    uv.x *= aspectRatio; // Adjust the horizontal scaling for the aspect ratio
    ivec2 uvInt = ivec2(scale * uv);
    int sum = uvInt.x + uvInt.y;
    vec3 color = sum / 2 * 2 == sum ? white : black; // Odd or even check

    fragColor = vec4(color, 1.0);
}

请注意,在独立应用程序中,缩放比例和纵横比调整的计算可以吸收到 uv 坐标本身中,从而从着色器代码中消除,以获得更好的性能。 结果:

8x8_checkboard_adjusted_for_aspect_ratio

© www.soinside.com 2019 - 2024. All rights reserved.