Что не так с моим кодом при попытке вычислить, находится ли точка «точка» в треугольнике или нет? - PullRequest
0 голосов
/ 21 декабря 2018

Кто-нибудь может увидеть, что не так с моим кодом?

float intersect(Ray ray, Triangle triangle) {
    float scalar = (0 - dot(triangle.normal, ray.origin)) / dot(triangle.normal, ray.dir);
    vec3 point = ray.origin + scalar * ray.dir;

Беррицентрические координаты

    vec3 A = vec3(1, 0, 0);
    vec3 B = vec3(0, 1, 0);
    vec3 C = vec3(0, 0, 1);

Использование Беррицентрических координат для вычисления tby матрицы tby = [A-точка] ==> tby = обратный (матрица) [точка A]

    mat3 matrix = mat3(point, A - B, A - C);
    vec3 tby = transpose(matrix) * vec3(A - point);

    float t = tby.x;
    float beta = tby.y;
    float gamma = tby.z;
    if (beta + gamma < 1 && beta > 0 && gamma > 0 && t > 0)
        return scalar;
    return -1.0;
}

То, что я создал до сих пор TriangleStruct

    struct Triangle
    {
     vec3 p1;
     vec3 p2;
     vec3 p3;
     vec3 normal;
     Material material;
    };

Точки

    vec3 p1 = vec3(-0.3,0.2,0.5);
    vec3 p2 = vec3(0.3,0.2,0.5);
    vec3 p3 = vec3(0.15,0.0,0.0);
    vec3 p4 = vec3(0.15,0.2,0.5);

Треугольники

    {

Треугольник 1

    scene.triangles[0].p1 = p1;
    scene.triangles[0].p2 = p4;
    scene.triangles[0].p3 = p3;
    scene.triangles[0].normal = normalize(cross((p4-p1), (p3-p1)));

Треугольник 2

    scene.triangles[1].p1 = p3;
    scene.triangles[1].p2 = p2;
    scene.triangles[1].p3 = p1;
    scene.triangles[1].normal = normalize(cross((p2-p3), (p1-p3)));

Треугольник 3

    scene.triangles[2].p1 =p3;
    scene.triangles[2].p2 = p4;
    scene.triangles[2].p3 = p2;
    scene.triangles[2].normal = normalize(cross((p4-p3), (p2-p3)));

...

    }

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Я рекомендую переписать ваш код следующим образом:

bool PointInOrOn( vec3 P1, vec3 P2, vec3 A, vec3 B )
{
    vec3 CP1 = cross( B - A, P1 - A )
    vec3 CP2 = cross( B - A, P2 - A )
    return step(0.0, dot( CP1, CP2 ));
}

float intersect(Ray ray, Triangle triangle)
{
    vec3 D = normalize(ray.dir);         // skip normalize, if ray.dir is normalized
    vec3 N = normalize(triangle.normal); // skip normalize, if triangle.normal is normalized

    float d = dot(triangle.p1 - ray.origin, N) / dot(D, N)
    vec3  X = ray.origin + D * d;

    float isIn = PointInOrOn( X, triangle.p1, triangle.p2, triangle.p3 ) *
                 PointInOrOn( X, triangle.p2, triangle.p3, triangle.p1 ) *
                 PointInOrOn( X, triangle.p3, triangle.p1, triangle.p2 );

    if ( isIn > 0.01 )
        return d;
    return -1.0;
}

См. Следующее объяснение.


Пересечение луча и примитива треугольника

Луч определяется точкой R0 и нормализованным направлением D.
Плоскость определяется треугольником стри точки PA, PB и PC.

. Вектор нормали к плоскости можно рассчитать по перекрестному произведению двух ветвей треугольника:

N  =  normalize( cross(PC-PA, PB-PA)

Обычное расстояние n от точки R0 до плоскости равно:

n  =  | R0 - PA | * cos(alpha)  =  dot(PA - R0, N)

Из этого следует, что расстояние d от точки пересечения X до начала луча R0 равно:

d  =  n / cos(beta)  =  n / dot(D, N)

Точка пересечения X:

X  =  R0 + D * d  =  R0 + D * dot(PA - R0, N) / dot(D, N)

Чтобы выяснить, находится ли точка внутри треугольника, необходимо проверить, если линия отугловая точка к точке пересечения находится между ногами, которые соединяются с угловой точкой.Треугольник определяется точками A, B, C, а проверяемая точка - P:

bool PointInOrOn( P1, P2, A, B )
{
    CP1 = cross( B - A, P1 - A )
    CP2 = cross( B - A, P2 - A )
    return dot( CP1, CP2 ) >= 0
}

bool PointInOrOnTriangle( P, A, B, C )
{
    return PointInOrOn( P, A, B, C ) &&
           PointInOrOn( P, B, C, A ) &&
           PointInOrOn( P, C, A, B )
} 
0 голосов
/ 21 декабря 2018

Из того, что я понял, вы пытаетесь проверить, проходит ли ray triangle.Самая первая ошибка, которую я вижу, состоит в том, что point:

vec3 point = ray.origin + scalar * ray.dir;

имеет бессмысленное определение.Вы вычисляете пересечение ray с параллельной плоскостью к triangle, проходящей через начало координат.Если эта плоскость по какой-то чудесной причине не совпадает с плоскостью triangle, все последующие вычисления с этим point не имеют никакого значения.

Чтобы исправить это, вам нужно определить scalar следующим образом:

float scalar = dot(triangle.normal,triangle.x) - dot(triangle.normal,ray.origin); 
scalar /= dot(triangle.normal,ray.dir);

, где triangle.x - любая точка triangle.

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

Также, пожалуйста, предоставьте больше информации о деталях кода, т. Е. Соответствующих частях реализации.


Теперь о том, как проверить, пересекает ли луч треугольник.Метод пересечения луча с плоскостью треугольника, а затем проверки, находится ли точка внутри треугольника в двумерной постановке, - не очень хорош с точки зрения устойчивости.Поэтому избегайте этого.

Более простой и прямой метод состоит в том, чтобы вычислить разностные векторы:

vec3 dvec1 = tringle.p1 - ray.origin;
vec3 dvec2 = tringle.p2 - ray.origin;
vec3 dvec3 = tringle.p3 - ray.origin;

и затем проверить, можно ли выразить ray.dir в виде линейной суммы dvec1dvec2 и dvec3 с положительными коэффициентами.Это может быть достигнуто путем вычисления обратной матрицы mat3(dvec1,dvec2,dvec3) и умножения ее на ray.dir (таким образом, вы получите коэффициенты, необходимые для выражения ray.dir линейной суммы dvec1, dvec2 и dvec3).

Однако матричный метод не является абсолютно стабильным из-за делений.Это может быть улучшено путем реализации логически эквивалентного кода без делений.

vec3 dvec12 = cross_product(dvec1, dvec2);
if(dot(dvec12,dvec3)*dot(dvec12,ray.dir) < 0.) return false;

vec3 dvec23 = cross_product(dvec2, dvec3);
if(dot(dvec23,dvec1)*dot(dvec23,ray.dir) < 0.) return false;

vec3 dvec31 = cross_product(dvec3, dvec1);
if(dot(dvec31,dvec2)*dot(dvec31,ray.dir) < 0.) return false;

return true;

В первом if мы проверяем, находится ли ray.dir в той же полуплоскости, что и dvec3 относительносамолет натянут на {dvec1,dvec2}.Если это не так, ray не будет пересекать треугольник.

Затем мы повторим эту проверку для других векторов.

...