问题
I am drawing circles/ellipses in WebGL
using a single Quad and a fragment shader, in order to draw them in a resolution independent manner (Edge distance anti-aliasing)
Here is my fragment shader currently:
'#extension GL_OES_standard_derivatives : enable',
'precision mediump float;',
'varying vec2 coord;',
'vec4 circleColor = vec4(1.0, 0.5, 0.0, 1.0);',
'vec4 outlineColor = vec4(0.0, 0.0, 0.0, 1.0);',
'uniform float strokeWidth;',
'float outerEdgeCenter = 0.5 - strokeWidth;',
'void main(void){',
'float dx = 0.5 - coord.x;',
'float dy = 0.5 - coord.y;',
'float distance = sqrt(dx*dx + dy*dy);',
'float delta = fwidth(distance);',
'float alpha = 1.0 - smoothstep(0.45 - delta, 0.45, distance);',
'float stroke = 1.0 - smoothstep(outerEdgeCenter - delta, outerEdgeCenter + delta, distance);',
'gl_FragColor = vec4( mix(outlineColor.rgb, circleColor.rgb, stroke), alpha );',
'}'
This creates an orange circle with a black outline that is perfectly antialiased whatever the size.
However, as soon as I transform the quad (scale it) in order to turn the circle into an ellipse, the distance
calculation transforms along with it, causing the outline to also scale. My understanding is that I would somehow need to account for the quad's transform by inverting it.
What I would like is for the distance
to remain uniform even when the quad is transformed, in effect producing a constant width outline around the whole circle/ellipse.
Any Help would be greatly appreciated.
回答1:
The problem is, your fragment shader (FS) is kind of blackbox now (becausethe the code is lack of information).
Your FS is written to work within square space. So it always render circle in space where x
and y
are same size ( -1.0; 1.0 interval).
While quad is transformed outside (in VS or anywhere else) and there is no way how to reflect that transformation in FS yet.
To solve the problem, I suggest to push an additional information into FS about the scaling. Something like Shadertoy provides in shader inputs:
uniform vec3 iResolution; // viewport resolution (in pixels)
except this wont be the resolution of the screen size, but the information about quad transformation, so something like:
varying vec2 trans;
// where value (1.0, 1.0) mean no transformation
Then you can use this value to calculate different stroke. Instead of inverting the transformation for the current stroke, I would rather calculate unique dx and dy values for it.
There are more ways to achieve the working solution and it depends on how do you want to use it later (what kinds of transformations should be possible etc.). So I present only the basic but the easiest solution.
来源:https://stackoverflow.com/questions/36142039/how-can-i-add-a-uniform-width-outline-to-webgl-shader-drawn-circles-ellipses-dr