You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

射线与椭球碰撞检测及法线计算原理探究(含非原点场景)

射线与椭球的碰撞检测及法线计算原理解析

一、原点处椭球的实现原理

碰撞检测逻辑

标准椭球(中心在原点,三个轴半径为 ra=(rx, ry, rz))的方程是:

(x/rx)² + (y/ry)² + (z/rz)² = 1

射线的参数方程为 ro + t*rd,其中 ro 是射线起点,rd 是单位方向向量,t 是射线前进的参数(正数表示射线前方)。

把射线方程代入椭球方程后,会得到一个关于 t 的二次方程。为了简化计算,代码里先做了坐标缩放变换:将椭球沿三个轴缩放成单位球——把射线起点和方向向量分别除以对应轴的半径,得到 ocn = ro/ra、rdn = rd/ra。此时原方程转化为单位球的方程:

dot(ocn + trdn, ocn + trdn) = 1

展开后整理为标准二次方程 a*t² + 2b*t + (c-1) = 0,其中:

  • a = dot(rdn, rdn):二次项系数
  • b = dot(ocn, rdn):一次项系数的一半
  • c = dot(ocn, ocn):常数项的一部分

接下来计算判别式 h = b² - a*(c-1):

  • 若 h < 0:二次方程无实根,射线与椭球无交点,返回 vec2(-1.0)
  • 若 h ≥ 0:计算两个实根 t = (-b ± √h)/a,返回的两个值分别是射线与椭球的近交点参数和远交点参数(t值越小,距离射线起点越近)

法线计算逻辑

椭球表面某点的法线可以通过方程的梯度求得。标准椭球方程的梯度为 (2x/rx², 2y/ry², 2z/rz²),归一化后就得到单位法线向量。代码中直接用 pos/(ra*ra) 再归一化,和梯度计算的结果一致(常数因子不影响方向)。

二、椭球不位于原点时的处理

只需要对射线起点做平移变换,把椭球中心移到原点即可,方向向量不受平移影响:

修改后的碰撞检测函数

// 椭球中心为center,半径为ra
vec2 eliIntersectAtCenter( in vec3 ro, in vec3 rd, in vec3 center, in vec3 ra )
{
    vec3 ro_shifted = ro - center; // 将射线起点平移到椭球中心为原点的坐标系
    vec3 ocn = ro_shifted / ra;
    vec3 rdn = rd / ra;
    float a = dot( rdn, rdn );
    float b = dot( ocn, rdn );
    float c = dot( ocn, ocn );
    float h = b*b - a*(c-1.0);
    if( h<0.0 ) return vec2(-1.0); // 无交点
    h = sqrt(h);
    return vec2(-b-h,-b+h)/a;
}

修改后的法线计算函数

vec3 eliNormalAtCenter( in vec3 pos, in vec3 center, in vec3 ra )
{
    vec3 pos_shifted = pos - center; // 将碰撞点平移到椭球中心为原点的坐标系
    return normalize( pos_shifted/(ra*ra) );
}

核心逻辑和原点处的实现完全一致,只是多了一步坐标系平移,把非原点的椭球转化为原点处的椭球来计算。

内容的提问来源于stack exchange,提问作者ChaoSXDemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:33:00