Нарисовать кривую эллипса во фрагментном шейдере

Я хочу плавную кривую в webgl, поэтому я попытался нарисовать прямоугольник в вершинном шейдере и отправить позиции фрагментному шейдеру в параметре нормализации размера и размера, который является реальным размером квадрата

in  vec2 Position;
in  vec2 Size;

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


}

когда размер = [ширина, высота] квадрата и равен для каждой вершины и position = [ -1 , -1 , -1 , 1 , 1 , -1 , 1 , 1 , ]поэтому мой прямоугольник будет нарисован в [2 * ширина, 2 * высота], но я могу выполнять геометрические операции в фрагментном шейдере с квадратом 2 * 2, который нормализован, но у меня есть проблема с рисованием эллипса (или круга с этими размерами) в фрагментный шейдер, когда я хочу сделать полый круг с параметром толщины, его толщина в горизонтальном направлении отличается от вертикального, и я знаю, что из-за этого я использую одинаковый размер для горизонтального и вертикального направлений (2,2), но на дисплее они разные, и это проблема, которая делает это изображение как вы видите толщина во всем это не то же самое.

Я хочу, чтобы геометрическая формула рассчитывала толщину в каждом направлении, тогда я могу нарисовать полый эллипс.

заранее спасибо. Извините за плохой английский

2 ответа

Если вы поместите тяжелые математические вычисления в ваш фрагментный шейдер, это будет медленно. Хитрость заключается в том, чтобы использовать приближение, которое может быть визуально приемлемым.

Ваша проблема в том, что толщина отличается на вертикальной и горизонтальной оси. Вам нужно отбросить фрагменты, если радиус текущей точки больше 1 и меньше radiusMin. Пусть uniWidth и uniHeight будут размером вашего прямоугольника. * Когда 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/

Существует неявная формула для x и y, которые находятся в синей области в полом эллипсе с параметром толщины. Поскольку мы знаем толщину и имеем размер нашего представления, мы можем сделать два эллипса с size1 = Size - vec2(толщина) и size2 = размер + vec2(толщина), а затем длина (позиция / размер1) < 1,0 <длина (позиция / размер2)

Другие вопросы по тегам