I'm developing a GLSL shader that draws out a circle based on a given center position and radius. For some reason I don't understand, the circle's radius does not match what I am passing. That is, when I pass in 100
for u_radius
, the radius is instead 56
. I tried just doubling the value in the shader, and while it's close with that, it's still slightly inaccurate. Does anyone have any clue what could be causing the discrepancy?
precision mediump float;
varying vec4 v_pos;
uniform mat3 u_matrix;
uniform vec2 u_center; // the center of the circle in world coordinates
uniform float u_aspect; // aspect ratio. 1.7778 for my monitor (1920x1080)
uniform float u_radius; // radius. passing in 100
uniform vec2 u_canvasSize; // [ 1920, 1080 ]
void main() {
vec4 c = vec4((u_matrix * vec3(u_center, 1)).xy, 0, 1); // center
vec2 onePix = vec2(1.0, 1.0) / u_canvasSize; // the size of one pixel in clip-space
float onePixLength = sqrt(onePix.x * onePix.x + onePix.y * onePix.y); // magnitude of one pixel
float r = onePixLength * u_radius; // radius converted to clip-space
vec2 dist = (v_pos.xy - c.xy) * vec2(u_aspect, 1.0); // distance from center to current shader point
if (dist.x * dist.x + dist.y * dist.y > r * r) {
discard;
}
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
It is because normalized device space coordinates are in range [-1.0, 1.0]. Therefore a factor of 2 is missing when calculating the pixel size:
vec2 onePix = vec2(1.0, 1.0) / u_canvasSize;
vec2 onePix = vec2(2.0) / u_canvasSize;
Additionally, you need to calculate the side length of a pixel instead of the diagonal length. The width (x-dimension) is scaled by the aspect ratio. Therefore, you need to calculate the height of a pixel:
float onePixLength = sqrt(onePix.x * onePix.x + onePix.y * onePix.y);
float onePixLength = onePix.y;
Note, onePix.x * u_aspect
is equal to onePix.y
.