I’m diving into a project where I want to recreate a cool 3D pixel art water effect, similar to what I found in a blog post by David Hollanda. Basically, I want to draw these white horizontal lines across the water’s surface that pulse in and out of existence. It’s a simple idea, but I can’t figure out how to get the actual lines right, especially making sure they look pixel-perfect.
In the video, it seems like the lines are always exactly 1 pixel wide, which is crucial for maintaining that retro pixel art vibe. Since I’m using orthographic projection, I know that perspective isn’t messing with my dimensions, but I’m stuck on how to actually create these lines in a shader. I want them to be sharp and not anti-aliased at all – that smooth blending just ruins the whole pixel art feel.
I’ve seen some hints about using textures to control the positioning and size of these lines. There’s a voronoi texture mentioned that supposedly helps with this too, but I’m not entirely clear on how to go about using it effectively. My guess is that the texture’s alpha channel has some sort of distance information, and I might even be using the RG channels for UV mapping, but how exactly does this all tie together?
I’m thinking of drawing the grid procedural in view-space coordinates, so even if the camera moves, the grid still remains consistent – but how do I ensure the lines always stay 1 pixel wide, regardless of the resolution? Plus, I want to avoid any anti-aliasing magic that could muddle up those clean edges.
If anyone has tips or guidance on how to implement this, especially focusing on the shader side of things, that would be incredible! I really want to nail down that pixel art aesthetic while having dynamic, animated lines on the water surface. Any advice or pointers to similar examples would be super appreciated. Thanks!
To achieve pixel-perfect horizontal lines that stay exactly 1 pixel wide and avoid anti-aliasing artifacts, it’s essential to design your shader around pixel-space coordinates rather than world-space. In your fragment shader, transform the fragment positions into screen-space by multiplying with the resolution, then use a modulus operation to isolate each pixel row. Specifically, calculate
floor(gl_FragCoord.y)
to determine the exact pixel row you’re working on. By testing this against your procedural line logic, you can ensure that lines always occupy a precise pixel line, with no in-between blending. Disabling any texture filtering (setting your texture sampler to “nearest neighbor”) is also crucial to prevent smoothing and maintain crisp edges.If integrating a Voronoi texture, leverage its alpha channel as distance data, mapping it onto screen-space UV coordinates generated from your RG channels or directly derived from fragment coordinates. By thresholding this distance data at an exact pixel width, you’ll achieve the pulsing, dynamic effect you’re describing. Ensure this threshold check aligns strictly with integer pixel boundaries by measuring distances in exact pixel increments, thereby making certain lines remain precisely one pixel wide at all resolutions. Keeping calculations strictly in view-space or fragment position coordinates ensures consistency even if the camera moves, retaining your careful pixel-art aesthetic throughout.
3D Pixel Art Water Effect with Pulsing Lines
Okay, so you’re diving into this cool water effect and wanna keep those lines nice and sharp, right? So here’s a few ideas to get started:
1. Render with a Shader
To create those white horizontal lines in your shader, you might wanna use a simple sine wave function to control their opacity. Something like this:
2. Keep It Pixel-Perfect
To ensure those lines are always 1 pixel wide, you might use screen space coordinates. A simple trick is to calculate the desired width in relation to the screen’s resolution:
3. Avoid Anti-Aliasing
You’ll want to set the filters on your textures to nearest neighbor, and if you’re using something like WebGL or OpenGL, turn off antialiasing in your setup.
4. Use Textures for Positioning
If you’re exploring the voronoi texture, it’s really cool for random patterns! You could map this texture’s RG channels to UVs, using the alpha for opacity manipulation. Kinda like:
5. Stay in View-Space
Yeah, doing it in view-space makes sense! Just make sure your UV coordinates get updated with the camera movement, but keep everything relative to your viewport size. That way the lines stay consistent as you move.
6. Experiment!
Lastly, don’t be shy about tweaking numbers. Mess around with frequencies in the sine function or the pulse speed; you’ll find a rhythm that feels right. And for a bit of flair, try adding some randomness to the line position!
Hope this helps you out! Good luck nailing that pixel art vibe!