Page 1 of 1

Need help solving a shader issue

Posted: Tue Jan 24, 2023 7:17 pm
by SHiLLySiT
I'm working on a 1bit game (where it only uses two colors) which leverages a custom shader. I recently started working on adding support to the shader so that I can define a pixel pattern for draw calls. The pattern is specified by 8 hex values that defines the states of pixels in each row, and then this 8x8 pattern is tiled. However I've run into an issue with the shader that I can seem to figure out, I'm fairly certain its a floating point rounding error, but I'm not sure how to fix it.

This is what I want to achieve:
correct.png
correct.png (3.71 KiB) Viewed 1675 times
This is what actually happens:
wrong.png
wrong.png (3.3 KiB) Viewed 1675 times
I believe the problem lies here, in the shader code:

Code: Select all

vec4 effect(vec4 color, Image tex, vec2 tex_coords, vec2 screen_coords)
{
  // rounding error somewhere on the next three lines?
  float x = mod(screen_coords.x, 8);
  float y = mod(screen_coords.y, 8);
  if (pattern[int(floor(x + y))] == 1) {
    return WHITE;
  } else {
    return BLACK;
  }
}
I've tried several variations of the above to attempt to round the float, but its still always showing the same artifacting. I'm hoping this is an easy fix that I just can't see with my limited shader experience 😭

I'm working on a rather large project, so I've attached a minimal (but working!) project that reproduces the issue in isolation.
shader-example.zip
(822 Bytes) Downloaded 67 times

Re: Need help solving a shader issue

Posted: Tue Jan 24, 2023 8:30 pm
by Bigfoot71
The problem is mostly how you're trying to iterate through the pixels in the array, you can round the (x,y) coordinates to the integer when you call `mod` and then you should iterate through the array instead like this [x+y*w], here is the corrected shader:

Code: Select all

#pragma language glsl3

extern int pattern[64];

const vec4 WHITE =        vec4(176.0f / 255.0f, 174.0f / 255.0f, 167.0f / 255.0f, 1);
const vec4 BLACK =        vec4( 49.0f / 255.0f,  47.0f / 255.0f,  40.0f / 255.0f, 1);

vec4 effect(vec4 color, Image tex, vec2 tex_coords, vec2 screen_coords)
{
    // Use mod() to get the position of the current pixel within the 8x8 pattern
    int x = int(mod(screen_coords.x, 8.0));
    int y = int(mod(screen_coords.y, 8.0));

    // Use "x" and "y" multiplied by "w" to index into the pattern array
    if (pattern[x + y * 8] == 1) {
        return WHITE;
    } else {
        return BLACK;
    }
}
XbreBAT.png
XbreBAT.png (1.02 KiB) Viewed 717 times
The reason `x+y*8` is used in the indexing calculation is because the pattern array is a one-dimensional array of 64 elements (8x8 pattern), by multiplying the y value by 8, it effectively moves the index to the correct row in the array. Adding x to this value gives you the final index of the element in the array that corresponds to the current pixel. Just remember, when we move in an array a dimension which represents like a pixel buffer we always do it like this "x + y * width".

I hope to be clear, if you have trouble understanding something don't hesitate ^^

Re: Need help solving a shader issue

Posted: Tue Jan 24, 2023 8:41 pm
by SHiLLySiT
Oh derp. This is why I shouldn't be programming so late 😂 Thanks for your help spotting this silly indexing bug.

Re: Need help solving a shader issue

Posted: Tue Jan 31, 2023 2:49 pm
by RNavega
I think you can simplify the shader code by replacing the pattern with an 8x8 Image that's sent to the shader.
It can be created from an ImageData object that you filled yourself with the values from those BLACK / WHITE constants.

There's an example of filling an ImageData with custom pixels in here: https://github.com/RNavega/PixelArt-Ant ... #L122-L144