'How to prevent WebGL from clipping outside bounds when drawing a wavy circle?
I have a shader that draws a bunch of instanced circles, and it works great! It works by basically drawing a bunch of rectangles at every given location, and then in the fragment shader it effectively discards pixels that are outside the radius, and this draws a circle.
I'm trying to update the shader now to make it draw "wavy" circles. That is, having a sin curve trace the entire outer edge of the circle. But the issue I'm running into now is that this curve will clip outside the bounds of the rectangle, and as a result, edges will be cut off. I drew a (crude) picture of what I think is happening:
As you can see, making a circle by hollowing out a quad works fine in the easy case. But when you add waves to the circle, portions of it clip outside of the unit space, causing those portions to not be rendered, so the rendered circle gets cut off at those parts. Here is what it looks like in my application (notice it gets cut off on the top, bottom, right, and left edges):
Here is where I believe the clip is occurring:
Here are my current vertex and fragment shaders for drawing these wavy circles. Is there any way I can modify them to prevent this clipping from occurring? Or maybe there is some WebGL setting I could use to fix this?
Vertex Shader:
in vec2 a_unit; // unit quad
in vec4 u_transform; // x, y, r, alpha
uniform mat3 u_projection; // camera
out float v_tint;
out vec2 v_pos;
void main() {
float r = u_transform.z;
float x = u_transform.x - r;
float y = u_transform.y - r;
float w = r * 2.0;
float h = r * 2.0;
mat3 world = mat3(
w, 0, 0,
0, h, 0,
x, y, 1
);
gl_Position = vec4(u_projection * world * vec3(a_unit, 1), 1);
v_tint = u_transform.w;
v_pos = a_unit;
}
Fragment Shader:
in vec2 v_pos;
in float v_tint;
uniform vec4 u_color;
uniform mat3 u_projection;
uniform float u_time;
out vec4 outputColor;
void main() {
vec2 cxy = 2.0 * v_pos - 1.0; // convert to clip space
float r = cxy.x * cxy.x + cxy.y * cxy.y;
float theta = 3.1415926 - atan(cxy.y, cxy.x) * 10.0; // current angle
r += 0.3 * sin(theta); // add waves
float delta = fwidth(r); // anti-aliasing
float alpha = 1.0 - smoothstep(1.0 - delta, 1.0 + delta, r);
outputColor = u_color * alpha * vec4(1, 1, 1, v_tint);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|