How to solve this shader pattern?

Hi there,

I am trying to create a shader pattern, where the uv is split into 7 equally big rows. They should be split by 6 small lines. Almost like in this image of my implementation:

My code is here:
https://codesandbox.io/p/sandbox/starterr3f-forked-c42dnv

My thought was splitting the uv into equally sized chunks with modulo, doing this with the small lines too and mixing it but its not quite right…

Greetings, Tom

Hi, your approach so far seems correct. Now you can downscale the uv inside the fragment shader so the top horizontal line is not rendered.

You can do this by assigning the uv to a variable and multiplying only the y axis by 0.99. Also you have to replace every reference to vUv with the new variable. Here’s the code:

varying vec2 vUv;

void main() {
            
  vec2 uv = vUv * vec2(1.,0.99);

  float mixVal = step(mod(uv.x * 1.0, 1.0), 0.5);
  float pattern = step(1.0 - (mod(uv.y * 7.0, 1.0)), 0.04) - 0.05;
  float pattern2 = step(mod(uv.y * 7.0, 1.0), 0.96) - 0.05;

  float result = mix(pattern, pattern2, mixVal);

  csm_DiffuseColor = vec4(vec3(0.8), result);
}
2 Likes

That works as expected, why tho? :thinking:
Another question, what if i want to set the small lines to a fixed scale like 5 mm?

Edit:

I got it working with different line heights. Still dont get why your fix worked honestly
https://codesandbox.io/p/sandbox/shaderpatterntest-c42dnv

Because everything that’s rendered from the fragment shader’s output is being controlled by the uv map.

The uv values are 0 left and 1 right for the x axis, and 0 bottom and 1 top for the y axis. In this case when you downscale the uv, you’re cutting out from the view anything that goes higher than 0.99 in the y axis of the texture’s output.

If you want to have more control over the width of the lines, i would recommend creating a new variable at the beginning of the main function that controls the width, and using it as a parameter of the step functions:

varying vec2 vUv;

void main() {

  float lineWidth = 0.05;

  vec2 uv = (vUv) * vec2(1.,(1. - lineWidth / 7.));
              
  float mixVal = step(mod(uv.x * 1.0, 1.0), 0.5);
  float pattern = step(1.0 - (mod(uv.y * 7.0, 1.0)), lineWidth) - 0.05;
  float pattern2 = step(mod(uv.y * 7.0, 1.0), 1. - lineWidth) - 0.05;

  float result = mix(pattern, pattern2, mixVal);

  csm_DiffuseColor = vec4(vec3(0.8), result);
}

In this case the lineWidth is 0.05. It is the third parameter in the step of the pattern 1, and it is used to calculate the step of the pattern 2 (1.0 - lineWidth).

Also the scale of the uv now it’s controlled by subtracting the lineWidth divided by the number of segments of the big rows. This is necessary so the uv displacement reflects the changes in lineWidth size.

2 Likes

@kalabedo
Just out of curiousity, why not fract(uv.y * 7.)?

I would also use fract, i was just adapting kalabedo’s approach.

1 Like

I know that, but why the value 0.99 for me it seams kinda random to cut off the top part of the pattern by this value. If i have a uLineHeight of 0.3 for example it would be visible again at the top:

https://codesandbox.io/p/sandbox/shaderpatterntest-c42dnv

@prisoner849 i changed it to fract as you mentioned, is it more performant?

Try with the lineWidth implementation in my second reply, there it’s an adapted version so the uv becomes responsive to the lineWidth variable and it’s not dependent on a magic number.

2 Likes

oops, sorry i missed that part!!
Thank you so much for helping

1 Like

Nope, but a bit less code :slight_smile:
mod(value, 1.0) = fract(value)

2 Likes

well, i’ll take that! :sunglasses:

1 Like