射线与椭球相交
Ray vs ellipsoid intersection
我正在尝试通过 "squishing" space 实现射线与椭球相交,并执行射线与球体:
创建 mat3 S,对角线处为椭圆体半径
通过将开始和方向乘以 S
的倒数来压缩光线
在局部 space
中将射线与半径为 1.0 的球体相交
将 hitPoint 乘以 S 以消除它。
这是射线与球体的对比:
float P = glm::dot(dir, sphereCenter-start);
float L = glm::distance(start, sphereCenter);
float d = sqrt(L*L - P*P);
if (d < radius) {
float x0 = sqrt(1.f - d*d);
hitPoint = start + dir*(P - x0);
hitNormal = glm::normalize(hitPoint - sphereCenter);
}
else if (d == radius) {
hitPoint = start + dir*P;
hitNormal = glm::normalize(hitPoint - sphereCenter);
}
else {
return false;
}
if (glm::distance(start, hitPoint) > dist) return false;
return true;
下面是压缩部分:
glm::vec3 S = start;
glm::vec3 Dir = dir;
auto sphereCenter = thisEntity()->transform()->getPosition();
auto scale = thisEntity()->transform()->getScale();
glm::mat3 q = glm::mat3(0);
float x = _radius.x * scale.x;
float y = _radius.y * scale.y;
float z = _radius.z * scale.z;
q[0][0] = x;
q[1][1] = y;
q[2][2] = z;
glm::mat3 qI = glm::inverse(q);
S = qI * S;
Dir = qI * Dir;
//calculate hit point in world space squished
glm::vec3 hitPoint, hitNormal;
if (!IntersectionsMath::instance()->segmentVsSphere(sphereCenter, S, Dir, dist, 1.f, hitPoint, hitNormal)) return;
hitPoint = q * hitPoint;
hit.pushHit(hitPoint, hitNormal, this);
当前的光线球体代码是针对世界位置的,我正试图让它在原点工作,所以它应该无关紧要。 Ray vs regular sphere 工作正常,椭圆体是问题所在。
我在这上面花了很多时间,但有些地方出了问题。
问题:
The center of scaling matters.
解决方案:
Perform the scaling about the center of the ellipsoid.
... 而不是您现在正在做的原点。这是因为,尽管光线的方向相同(它只是一个方向向量),scaled 源和球体中心之间的相对位移将不同:
原点缩放(当前代码):
来源S' = qI * S
,中心C' = qI * C
--- S' - C' = qI * (S - C)
关于椭球中心的缩放(正确程序):
来源S" = qI * (S - C)
,中心C" = C
--- S" - C" = qI * (S - C) - C
两个位移的不同之处在于原始椭球的位置;因此您当前的射线可能会错过/给出误报。
更正后的代码:
// scale about the ellipsoid's position by subtracting before multiplying
// more appropriate name would be "ellipseCenter" to avoid confusion
S_ = qI * (S - sphereCenter);
// this ::normalize should really be in the intersection function
Dir_ = glm::normalize(qI * Dir);
// calculate hit point in world space squished
// ... but around the origin in the squashed coordinate system
glm::vec3 hitPoint, hitNormal;
if (!IntersectionsMath::instance()->segmentVsSphere(
glm::vec3::ZERO, S_, Dir_,
dist, 1.f,
hitPoint, hitNormal)) return;
// re-apply the offset
hitPoint = q * hitPoint + sphereCenter
// problem: hitNormal will not be correct for the ellipsoid when scaled
// solution: divide through each component by square of respective semi-axis
// (will provide proof upon request)
hitNormal.x /= (x * x); hitNormal.y /= (y * y); hitNormal.z /= (z * z);
我正在尝试通过 "squishing" space 实现射线与椭球相交,并执行射线与球体:
创建 mat3 S,对角线处为椭圆体半径
通过将开始和方向乘以 S
的倒数来压缩光线
在局部 space
中将射线与半径为 1.0 的球体相交
将 hitPoint 乘以 S 以消除它。
这是射线与球体的对比:
float P = glm::dot(dir, sphereCenter-start);
float L = glm::distance(start, sphereCenter);
float d = sqrt(L*L - P*P);
if (d < radius) {
float x0 = sqrt(1.f - d*d);
hitPoint = start + dir*(P - x0);
hitNormal = glm::normalize(hitPoint - sphereCenter);
}
else if (d == radius) {
hitPoint = start + dir*P;
hitNormal = glm::normalize(hitPoint - sphereCenter);
}
else {
return false;
}
if (glm::distance(start, hitPoint) > dist) return false;
return true;
下面是压缩部分:
glm::vec3 S = start;
glm::vec3 Dir = dir;
auto sphereCenter = thisEntity()->transform()->getPosition();
auto scale = thisEntity()->transform()->getScale();
glm::mat3 q = glm::mat3(0);
float x = _radius.x * scale.x;
float y = _radius.y * scale.y;
float z = _radius.z * scale.z;
q[0][0] = x;
q[1][1] = y;
q[2][2] = z;
glm::mat3 qI = glm::inverse(q);
S = qI * S;
Dir = qI * Dir;
//calculate hit point in world space squished
glm::vec3 hitPoint, hitNormal;
if (!IntersectionsMath::instance()->segmentVsSphere(sphereCenter, S, Dir, dist, 1.f, hitPoint, hitNormal)) return;
hitPoint = q * hitPoint;
hit.pushHit(hitPoint, hitNormal, this);
当前的光线球体代码是针对世界位置的,我正试图让它在原点工作,所以它应该无关紧要。 Ray vs regular sphere 工作正常,椭圆体是问题所在。 我在这上面花了很多时间,但有些地方出了问题。
问题:
The center of scaling matters.
解决方案:
Perform the scaling about the center of the ellipsoid.
... 而不是您现在正在做的原点。这是因为,尽管光线的方向相同(它只是一个方向向量),scaled 源和球体中心之间的相对位移将不同:
原点缩放(当前代码):
来源
S' = qI * S
,中心C' = qI * C
---S' - C' = qI * (S - C)
关于椭球中心的缩放(正确程序):
来源
S" = qI * (S - C)
,中心C" = C
---S" - C" = qI * (S - C) - C
两个位移的不同之处在于原始椭球的位置;因此您当前的射线可能会错过/给出误报。
更正后的代码:
// scale about the ellipsoid's position by subtracting before multiplying
// more appropriate name would be "ellipseCenter" to avoid confusion
S_ = qI * (S - sphereCenter);
// this ::normalize should really be in the intersection function
Dir_ = glm::normalize(qI * Dir);
// calculate hit point in world space squished
// ... but around the origin in the squashed coordinate system
glm::vec3 hitPoint, hitNormal;
if (!IntersectionsMath::instance()->segmentVsSphere(
glm::vec3::ZERO, S_, Dir_,
dist, 1.f,
hitPoint, hitNormal)) return;
// re-apply the offset
hitPoint = q * hitPoint + sphereCenter
// problem: hitNormal will not be correct for the ellipsoid when scaled
// solution: divide through each component by square of respective semi-axis
// (will provide proof upon request)
hitNormal.x /= (x * x); hitNormal.y /= (y * y); hitNormal.z /= (z * z);