Separating Axis Theorem(分离轴理论)

在学习Ray-Box检测之前,首先来学习一些这个分离轴理论!

先说二维情况,一句话

Two convex polygons do not intersect if and only if there exists a line such that the projections of the two polygons onto the line do not intersect.

咳咳,翻译一下

两个凸包多边形,当且仅当存在一条线,这两个多边形在这条线上的投影不相交,则这两个多边形也不相交, 如下图所示

将多边形换成多面体,线变成面,就变成了三维空间中的分离轴了。

对于矩形,假设出现碰撞的情况,则存在分离轴平行矩形的一条边。(这个后面会证明)

Ray - Rect检测

在到三维之前,还是来看二维的情况,也就是Ray-Rect检测。

假定Rect的中心为原点,所以就是下面这样

首先要面对的一个问题就是射线的原点是否在矩形的内部,这里就用到了分离轴的定理。

将矩形投影到对应的轴上,如果没有和射线原点的投影重合,那么就不在矩形里面。

接下来判断是否相交,这里提到了一个简单 slab method,简单说来,首先将矩形的四条边无限延伸,那么整个平面就被矩形分割成了几个部分,用这个”井字“去切割射线,如果得得到的线段在矩形内,那么就相交了。如下图所示,绿色的射线是相交的,红色的没有相交。

简单的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool intersection(box b, ray r) {
    double tmin = -INFINITY, tmax = INFINITY;
  
    if (ray.n.x != 0.0) {
        double tx1 = (b.min.x - r.x0.x)/r.n.x;
        double tx2 = (b.max.x - r.x0.x)/r.n.x;
  
        tmin = max(tmin, min(tx1, tx2));
        tmax = min(tmax, max(tx1, tx2));
    }
  
    if (ray.n.y != 0.0) {
        double ty1 = (b.min.y - r.x0.y)/r.n.y;
        double ty2 = (b.max.y - r.x0.y)/r.n.y;
  
        tmin = max(tmin, min(ty1, ty2));
        tmax = min(tmax, max(ty1, ty2));
    }
  
    return tmax >= tmin;
}

三维空间

直接贴代码了。

加了坐标系的转换,代码是参考PhysX里优化过的代码,但原理基本不变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public static bool Raycast(Ray ray, float distance, Box box, out RaycastHitInfo hitInfo)
      {
          Quaternion inverRot = Quaternion.Inverse(box.rotation);
          Vector3 origin = ray.origin - box.center;
          Vector3 localOrigin = inverRot * origin;
          Vector3 localDir = inverRot * ray.direction;
          Ray localRay = new Ray(localOrigin, localDir);
          if (!IntersectRayAABB(localRay, distance, 0.5f * box.extents, out hitInfo))
          {
              return false;
          }
          hitInfo.normal = box.rotation * hitInfo.normal;
          hitInfo.point = box.rotation * hitInfo.point + box.center;
          return true;
      }
      public static bool IntersectRayAABB(Ray ray, float distance, Vector3 dimension, out RaycastHitInfo hitInfo)
      {
          float RAYAABB_EPSILON = 0.00001f;
          hitInfo = new RaycastHitInfo();
          Vector3 minPos = -dimension;
          Vector3 maxPos = dimension;
          Vector3 maxT = -Vector3.one;
          bool isInside = true;
          for (int i = 0; i < 3; i++)
          {
              if (ray.origin[i] < minPos[i])
              {
                  hitInfo.point[i] = minPos[i];
                  isInside = false;
                  if (ray.direction[i] != 0)
                      maxT[i] = (minPos[i] - ray.origin[i]) / ray.direction[i];
              }
              else if (ray.origin[i] > maxPos[i])
              {
                  hitInfo.point[i] = maxPos[i];
                  isInside = false;
                  if (ray.direction[i] != 0)
                      maxT[i] = (maxPos[i] - ray.origin[i]) / ray.direction[i];
              }
          }
          // Ray origin inside bounding box
          if (isInside)
          {
              hitInfo.point = ray.origin;
              hitInfo.distance = 0;
              hitInfo.normal = -ray.direction;
              return true;
          }
          // Get largest of the maxT's for final choice of intersection
          int whichPlane = 0;
          if (maxT[1] > maxT[whichPlane]) whichPlane = 1;
          if (maxT[2] > maxT[whichPlane]) whichPlane = 2;
          //Ray distance large than ray cast ditance
          if (maxT[whichPlane] > distance)
          { return false; }
          // Check final candidate actually inside box
          for (int i = 0; i < 3; i++)
          {
              if (i != whichPlane)
              {
                  hitInfo.point[i] = ray.origin[i] + maxT[whichPlane] * ray.direction[i];
                  if (hitInfo.point[i] < minPos[i] - RAYAABB_EPSILON || hitInfo.point[i] > maxPos[i] + RAYAABB_EPSILON)
                      return false;
                  //  if (hitInfo.point[i] < minPos[i] || hitInfo.point[i] > maxPos[i])
                  //  return false;
              }
          }
          hitInfo.distance = maxT[whichPlane];
          Vector3 normal = Vector3.zero;
          normal[whichPlane] = (hitInfo.point[whichPlane] > 0) ? 1 : -1;
          hitInfo.normal = normal;
          return true;
      }

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class RayBoxTester : MonoBehaviour {
    public GameObject box;
    Box _box;
    // Use this for initialization
    void Start () {
        _box = new Box(Vector3.zero, Vector3.one, Quaternion.identity);
    }
     
    // Update is called once per frame
    void Update () {
        //Ray OBB test.
        Ray ray2 = new Ray(Vector3.zero, new Vector3(1, 1, 1));
        RaycastHitInfo hitinfo2;
        //ray2.origin = rayOrigin.transform.position;
        float castDistance = 10f;
        _box.center = box.transform.position;
        _box.extents = box.transform.localScale;
        _box.rotation = box.transform.rotation;
        if (NRaycastTests.Raycast(ray2, castDistance, _box, out hitinfo2))
        {
            Debug.DrawLine(ray2.origin, ray2.origin + ray2.direction * hitinfo2.distance, Color.red, 0, false);
            Debug.DrawLine(hitinfo2.point, hitinfo2.point + hitinfo2.normal, Color.green, 0, false);
        }
        else
        {
            Debug.DrawLine(ray2.origin, ray2.origin + ray2.direction * castDistance, Color.blue, 0, false);
        }
    }
}

结果

收工。

参考

FAST, BRANCHLESS RAY/BOUNDING BOX INTERSECTIONS  - https://tavianator.com/fast-branchless-raybounding-box-intersections/

Hyperplane_separation_theorem - https://en.wikipedia.org/wiki/Hyperplane_separation_theorem

Ray - Box Intersection  - http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm

PhysX 3.3  source code

碰撞检测之Ray-Box检测

Separating Axis Theorem(分离轴理论)Raycast相关推荐

  1. 碰撞检测—分离轴理论

    最近在用opengl写一个小游戏,动画和人机交互都很简单,逻辑控制,边界问题都是目前的一个难题,正好找了几篇碰撞检测的资料,看着挺不错的 http://www.cppblog.com/mybios/a ...

  2. Separating axis theorem Polygon Collision

     Separating axis theorem: http://en.wikipedia.org/wiki/Separating_axis_theorem Polygon Collision: ht ...

  3. 第6-8课:分离轴算法(SAT)与碰撞检测(图文篇)

    物体的碰撞检测是游戏软件中的关键算法之一,两个角色是否能够对话.子弹是否击中了物体,以及是否出现人物穿墙的 bug,都依赖于一套可靠的碰撞检测算法.有很多算法可以实现碰撞检测,基于算法几何的方法有轴对 ...

  4. egret判断两个多边形是否相交(分离轴定律)

    参考原文:原文 预备知识:向量的点积:  关于向量的知识这里不再赘述 分离轴定理(Separating Axis Theorem) 概念:通过判断任意两个 凸多边形 在任意角度下的投影是否均存在重叠, ...

  5. R语言使用epiDisplay包的tabpct函数生成二维列联表并使用马赛克图可视化列联表(二维列联表、边际频数、以及按行、按列的比例)、自定义设置cex.axis参数改变轴标签数值的大小

    R语言使用epiDisplay包的tabpct函数生成二维列联表并使用马赛克图可视化列联表(二维列联表.边际频数.以及按行.按列的比例).自定义设置cex.axis参数改变轴标签数值的大小 目录

  6. 主轴定理(Principal axis theorem)

    1,补充知识 1.1 欧式空间(Euclidean space) 直观感受:二维平面,三维立体,拓展到高维空间就对应着超平面.我们在初高中以及大学中的高等数学.线性代数遇到的都是欧几里得空间. 为了在 ...

  7. 分离轴定理SAT凸多边形精确碰撞检测

    分离轴定理SAT凸多边形精确碰撞检测 定理 Separating Axis Theorem,缩写SAT,中文为分离轴理论或分离轴定理,通过判断凸多边形在分离轴上的投影是否重叠来判断是否发生碰撞. 所谓 ...

  8. 碰撞检测之分离轴定理算法讲解

    本文翻译自@sevenson的文章Separating Axis Theorem (SAT) Explanation .原文作者用的是ActionScript 3来编写算法,不过文中主要讲述的还是算法 ...

  9. 碰撞检测之分离轴定理算法

    本文转载自 https://blog.csdn.net/yorhomwang/article/details/54869018,感谢博主分享 本文翻译自@sevenson的文章Separating A ...

  10. 分离轴定理及向量应用

    分离轴定理及向量应用 通过判断任意两个 凸多边形 在任意角度下的投影是否均存在重叠,来判断是否发生碰撞.若在某一角度光源下,两物体的投影存在间隙,则为不碰撞,否则为发生碰撞. 算法简述1 从根本上来讲 ...

最新文章

  1. 最新最全国内外架构开源技术干货资料
  2. python读法1002python读法-Python教程之绘制Mandelbrot集合
  3. PyTorch nn.Module 一些疑问
  4. 【Python】全国气温骤降,Python一键生成御寒指南,助你温暖过冬!!
  5. jzoj1264,P2866-乱头发节,糟糕的一天Bad Hair Day【单调栈】
  6. 自注意力机制Self-attention(1)
  7. CAutoupdater通用 自动升级组件用户手册
  8. 王思聪5亿投资神话破灭?旗下普思资本股权遭冻结,冻结期3年
  9. mql 查询多结果_一篇文章带你全面掌握Excel中的各种数据查询知识与技巧
  10. Gitlab项目迁移
  11. redis基础知识——菜鸟教程
  12. 荧光和明场图像融合 matlab,一种用于明场显微成像的多层图像融合算法
  13. Google 镜像站搜集
  14. Kotlin 笔记 纯属娱乐萌新大佬绕道
  15. 题目:某班的成绩出来了,现在老师要把班级的成绩打印出来。 效果图: XXXX年XX月X日 星期X 班级总分为:xx 班级平均分:xx
  16. 使用R读取并查看数据
  17. 有趣的python typosquatting不赚钱
  18. 服务器上用U盘安装Linux系统详细步骤
  19. 基于OpenCV 的手指骨骨龄计算
  20. 牛客第三场 F Popping Balloons —— 思维 + 搞题

热门文章

  1. html背景颜色代码格式,html常用背景颜色代码.docx
  2. 把MSGF变成SPLF 把SPLF变成MEMBER(源文件)-转载
  3. shell机器人企业微信通知
  4. Air720模块Linux USB驱动以及PPP拨号说明
  5. iOS 最新AppStore申请加急审核 以及 apple联系方式大全
  6. win10相机计算机无法使用,Win10相机打不开 报错“0xa00f4244”要怎么解决?
  7. c++经典小游戏,源码奉上(免费复制)
  8. 微信小程序报错 40125 已解决
  9. 一元非线性方程求根的算法——二分法/牛顿迭代法
  10. 朱生豪先生的情书 ---- 醒来觉得甚是爱你