首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >射线与椭球相交

射线与椭球相交
EN

Stack Overflow用户
提问于 2018-09-01 18:15:10
回答 1查看 2K关注 0票数 0

我试图通过“挤压”空间来实现射线与椭球的交集,并做射线对球面:

  1. 在对角线上创建椭球半径的mat3 S
  2. 用S的逆乘积起始方向来压缩射线
  3. 局部空间中半径为1.0的球面相交射线
  4. 将hitPoint乘以S来解压它。

这是射线对球体:

代码语言:javascript
复制
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;

以下是挤压部分:

代码语言:javascript
复制
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);

目前的射线球体代码是为世界位置,我试图使它在原点工作,所以它应该不重要。射线和规则球体工作得很好,椭球是问题所在。我花了很多时间在这件事上,有些地方出了问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-01 19:09:40

问题:

缩放的中心很重要。

解决方案:

在椭球体中心执行缩放。

..。而不是你现在所做的起源。这是因为,虽然射线的方向是相同的(它只是一个方向向量),但在球体的标度源和中心之间的相对位移是不同的:

  • 关于起源的缩放(当前代码): 源S' = qI * S,中心C' = qI * C - S' - C' = qI * (S - C)
  • 椭球中心的缩放(正确的程序): 源S" = qI * (S - C),中心C" = C - S" - C" = qI * (S - C) - C

这两种位移因原始椭球体的位置不同而不同;因此,你当前的射线很可能会误/给出假阳性。

修正代码:

代码语言:javascript
复制
// 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);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52130939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档