How can I add a uniform width outline to WebGL shader drawn circles/ellipses (drawn using edge/distance antialiasing)

笑着哭i 提交于 2019-12-12 05:26:55

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!