Нарисовать кривую эллипса во фрагментном шейдере
Я хочу плавную кривую в 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)