Это пересечение алгоритм работы, как это должно быть?


и я могу сделать его более эффективным? Это для проверки столкновения между Лучом и области.

float BoundingSphere::Intersects(Ray ray)
{
D3DXVECTOR3 direction = ray.Direction();
D3DXVECTOR3 vec = D3DXVECTOR3();
D3DXVECTOR3 cToO = ray.Origin() - centre;
float rSquared = radius * radius;
float vSquared = 0;

if(D3DXVec3Dot(&cToO, &cToO) <= rSquared)
{
    return 0;
}
else if(D3DXVec3Dot(&cToO, &direction) <= 0)
{
    vec = cToO - direction * D3DXVec3Dot(&cToO, &direction);
    vSquared = D3DXVec3Dot(&vec, &vec);

    if(vSquared <= rSquared)
    {
        D3DXVECTOR3 normDir = *D3DXVec3Normalize(&direction, &direction);
        float mul = sqrt(rSquared - vSquared);

        return D3DXVec3Length(
            &(ray.Origin() - 
            (centre + vec - D3DXVECTOR3(normDir.x *= mul, normDir.y *= mul, normDir.z *= mul))));
    }
    else
    {
        return -1;
    }
}
else
{
    return -1;
}
}

она должна возвращать -1 , если нет столкновения, 0, если источник луча находится внутри сферы. В противном случае он должен вернуть поплавок на расстояние от источника луча до первой точки столкновения.



244
0
задан 12 декабря 2011 в 03:12 Источник Поделиться
Комментарии
1 ответ

Поскольку нет ответа, я возьму трещину в нем.

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

float BoundingSphere::Intersects(Ray ray)
{
D3DXVECTOR3 cToO = ray.Origin() - centre;
float rSquared = radius * radius;
if(D3DXVec3Dot(&cToO, &cToO) <= rSquared) return 0;

D3DXVECTOR3 direction = ray.Direction();
if(D3DXVec3Dot(&cToO, &direction) > 0) return -1;

D3DXVECTOR3 vec = cToO - direction * D3DXVec3Dot(&cToO, &direction);
float vSquared = D3DXVec3Dot(&vec, &vec);
if(vSquared > rSquared) return -1;
// ...
}

Там должно быть каким-то образом на несколько D3DXVECTOR3 со скалярным значением сразу. Даже если это напрямую не поддерживается это тривиально, чтобы перегрузить оператор *= себе. Возвращение тоже становится довольно длинной. Я сломан, что длинное заявление в более удобоваримый частей:

    float mul = sqrt(rSquared - vSquared);
D3DXVECTOR3 normDir = *D3DXVec3Normalize(&direction, &direction);
normDir *= mul;

return D3DXVec3Length(&(ray.Origin() - centre - vec + normDir));
}

Я не смотрел на столкновение в слишком много деталей, это очевидно с первого взгляда.


она должна возвращать 1, если нет столкновения, 0, если источник луча находится внутри сферы...

Это звучит как у вас есть четкое представление о том, как этот метод должен вести себя. Почему бы не взять основу модульное тестирование, как тестирование в Google, и написать юнит-тестов для каждого из этих случаев? Тестирование BoundingSphere::пересечение может быть как простой, как эта:

TEST(BoundingSphereTest, testRayInsideSphere)
{
BoundingSphere testSphere(D3DXVECTOR3(0, 0, 0), 42);
Ray testRay(0, 0);

EXPECT_EQ(-1, testSphere.Intersects(testRay));
}

Обратите внимание, я просто думаю о том, как эти объекты строятся, но это должно дать вам основную идею. Исправить их по мере необходимости.

2
ответ дан 19 декабря 2011 в 03:12 Источник Поделиться