Вычислить точечную проекцию в шейдере GLSL - PullRequest
0 голосов
/ 23 февраля 2019

Мне нужно рассчитать проекцию точки на определенный отрезок линии в шейдере (OpenGL ES 2).
Вот как я тестирую алгоритм:
Я рисую простой треугольник с точками A (0, 0.5), B(1, -0,5), C (-1, -0,5).
Я вычисляю проекцию каждой точки на отрезке AC.
Я рисую точки с проекцией в середине отрезка AC синим цветом.А оставшиеся точки зеленого цвета.
Я ожидаю получить зеленый треугольник с синей линией, перпендикулярной стороне AC.Но синяя линия не перпендикулярна переменному току.
Я проверяю формулу проекции в коде с рисованием на холсте и получаю ожидаемый результат.
В чем моя ошибка?

Результат шейдера: enter image description here

Вершинный шейдер:

uniform mat4 matrix;
attribute vec4 position;
varying vec4 vPosition;

void main()
{
    vPosition = matrix * position;
    gl_Position = matrix * position;
}

Фрагмент шейдера:

precision mediump float;

varying vec4 vPosition;

void main()
{

    vec2 P = vPosition.xy;
    vec2 A = vec2(0.0, 0.5);
    vec2 B = vec2(-1.0, -0.5);
    vec2 AP = P - A;
    vec2 AB = B - A;
    vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;

    if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
        gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
    } else {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }
}

1 Ответ

0 голосов
/ 23 февраля 2019

Вы не учли прямоугольный аспект окна.Когда нормализованные координаты устройства в диапазоне [-1, 1] сопоставляются с прямоугольником области просмотра (см. glViewport), треугольник растягивается.Это приводит к тому, что углы в 90 градусов не поддерживаются.

Добавьте равномерную переменную к фрагментному шейдеру, который содержит ширину и высоту области просмотра:

uniform vec2 u_resolution;

Вычислите соотношение сторон:

float aspect = u_resolution.x / u_resolution.y;

Конечно, вы можете инициализировать переменную float aspect также постоянным значением.
Например, float aspect = 16.0/9.0;

Исправить координатыточки A, B и P в соответствии с соотношением сторон:

vec2 P = vPosition.xy;
vec2 A = vec2(0.0, 0.5);
vec2 B = vec2(-1.0, -0.5);

A.x *= aspect;
B.x *= aspect;
P.x *= aspect;

И учитывайте соотношение сторон при оценке результата projection:

vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB;
projection.x /= aspect;

Конечный фрагмент шейдера может выглядеть так:

precision mediump float;

varying vec4 vPosition;

uniform vec2 u_resolution;

void main()
{
    float aspect = u_resolution.x / u_resolution.y;
    vec2  as = vec2(aspect, 1.0);

    vec2 P = as * vPosition.xy;
    vec2 A = as * vec2(0.0, 0.5);
    vec2 B = as * vec2(-1.0, -0.5);

    vec2 AP = P - A;
    vec2 AB = B - A;

    vec2 projection = A + dot(AP, AB) / dot(AB, AB) * AB / as;

    if(projection.x > -0.51 && projection.x < -0.49 && projection.y > -0.01 && projection.y < 0.01) {
        gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
    } else {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }
}

...