首页 > 解决方案 > 在片段着色器中绘制椭圆曲线

问题描述

我想要 webgl 中的平滑曲线,所以我尝试在顶点着色器中绘制一个矩形,并将位置发送到片段着色器中的标准化大小和大小参数,这是正方形的实际大小

in  vec2 Position;
in  vec2 Size;

out vec2 vPosition;
out vec2 vSize;
void main() {
    vSize = Size;
    vPosition = Position
    gl_Position = Position * Size


}

当 size = [width, height] of square 并且对于每个顶点都相等时,position = [ -1 , -1 , -1 , 1 , 1 , -1 , 1 , 1 , ] 因此我的矩形将在 [2 * width , 2 * height] 中绘制,但我可以在片段着色器中使用 2 * 2 正方形进行几何操作,即归一化,但是当我想用厚度参数制作空心圆时,我在片段着色器中绘制椭圆(或具有这种大小的圆)时遇到问题,它在水平方向的厚度与垂直方向的厚度不同,我知道这是因为我' m 对水平和垂直方向(2,2)使用相同的尺寸,但在显示时它们是不同的,这是导致这个图片您看到的所有厚度都不相同的问题。

我想要一个几何公式来计算每个方向的厚度,然后我可以画一个空心椭圆。

提前致谢。抱歉英语不好

标签: webglshaderfragment-shaderdrawellipse

解决方案


如果你在片段着色器中投入大量的数学计算,它会很慢。诀窍可以是使用视觉上可以接受的近似值。

您的问题是垂直轴和水平轴上的厚度不同。如果当前点的半径大于 1 且小于radiusMin ,您需要丢弃片段。让uniWidthuniHeight成为矩形的大小。* 当y为空时,在水平轴上,radiusMin = 1.0 - BORDER / uniWidth。* 当x为空时,在垂直轴上,radiusMin = 1.0 - BORDER / uniHeight

诀窍是使用mix()函数在这两个半径之间进行插值。看看我下面的例子,让你相信结果还不错。

这是进行此类计算的片段着色器:

precision mediump float;
uniform float uniWidth;
uniform float uniHeight;
varying vec2 varCoords;

const float BORDER = 32.0;

void main() {
  float x = varCoords.x;
  float y = varCoords.y;
  float radius = x * x + y * y;
  if( radius > 1.0 ) discard;

  radius = sqrt( radius );

  float radiusH = 1.0 - BORDER / uniWidth;
  float radiusV = 1.0 - BORDER / uniHeight;
  float radiusAverage = (radiusH + radiusV) * 0.5;

  float minRadius = 0.0;
  x = abs( x );
  y = abs( y );
  if( x > y ) {
    minRadius = mix( radiusH, radiusAverage, y / x );
  }
  else {
    minRadius = mix( radiusV, radiusAverage, x / y );
  }

  if( radius < minRadius ) discard;

  gl_FragColor = vec4(1, .5, 0, 1);
}

这是一个活生生的例子:https ://jsfiddle.net/7rh2eog1/5/


推荐阅读