2D空间中比较两三角形相交与包含

在处理UV重叠、CPU的ZFighting检测时会遇到2D空间中的三角形相交问题,

网上普遍是3D空间的相交解法,因此写本文研究下,不过虽然实现了需求,

但解法较为暴力。

 

效果如图:


(鼠标拖动区域处有一小三角形,与外部大三角形进行相交包含演示)

 

若两三角形存在线段相交,则两三角形相交,但三点都包含的情况下则无法囊括在内。

所以还需额外判断一次三点都包含的情况。

 

2D空间的三角形相交得从线段与线段相交做起,这里用之前的叉乘方法来检测:

https://www.cnblogs.com/hont/p/6106043.html

 

点是否在多边形内用的是单双数检测法:

https://www.cnblogs.com/hont/p/6105997.html

 

方法还是比较朴素的方法,但离线情况下使用无问题。

代码如下(Unity XZ空间):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayVsTriangle : MonoBehaviour
{
    public Transform a0;
    public Transform b0;
    public Transform c0;

    public Transform a1;
    public Transform b1;
    public Transform c1;


    private bool TriangleVsTriangle(Vector3 a0, Vector3 b0, Vector3 c0, Vector3 a1, Vector3 b1, Vector3 c1)
    {
        bool IsIntersect(Vector3 a, Vector3 b, Vector3 c, Vector3 d)
        {
            float crossA = Vector3.Cross(d - c, a - c).y;
            float crossB = Vector3.Cross(d - c, b - c).y;

            if (!(crossA > 0f ^ crossB > 0f)) return false;

            float crossC = Vector3.Cross(b - a, c - a).y;
            float crossD = Vector3.Cross(b - a, d - a).y;

            if (!(crossC > 0f ^ crossD > 0f)) return false;

            return true;
        }

        bool IsContain(Vector3 a, Vector3 b, Vector3 c, Vector3 p0)
        {
            const float kRaycastLen = 100000f;

            Vector3 comparePoint = (c + b) * 0.5f;
            Vector3 originPoint = p0;
            comparePoint += (comparePoint - originPoint).normalized * kRaycastLen;

            int count = 0;
            if (IsIntersect(a, b, originPoint, comparePoint)) ++count;
            if (IsIntersect(b, c, originPoint, comparePoint)) ++count;
            if (IsIntersect(c, a, originPoint, comparePoint)) ++count;

            return count % 2 == 1;
        }

        if (IsIntersect(a0, b0, a1, b1)) return true;
        if (IsIntersect(a0, b0, b1, c1)) return true;
        if (IsIntersect(a0, b0, c1, a1)) return true;

        if (IsIntersect(b0, c0, a1, b1)) return true;
        if (IsIntersect(b0, c0, b1, c1)) return true;
        if (IsIntersect(b0, c0, c1, a1)) return true;

        if (IsIntersect(c0, a0, a1, b1)) return true;
        if (IsIntersect(c0, a0, b1, c1)) return true;
        if (IsIntersect(c0, a0, c1, a1)) return true;

        if (IsContain(a1, b1, c1, a0) && IsContain(a1, b1, c1, b0) && IsContain(a1, b1, c1, c0))
            return true;

        return false;
    }

    private void OnDrawGizmos()
    {
        bool isRed = TriangleVsTriangle(a0.position, b0.position, c0.position, a1.position, b1.position, c1.position);

        Gizmos.color = isRed ? Color.red : Color.white;

        Gizmos.DrawLine(a0.position, b0.position);
        Gizmos.DrawLine(b0.position, c0.position);
        Gizmos.DrawLine(c0.position, a0.position);

        Gizmos.DrawLine(a1.position, b1.position);
        Gizmos.DrawLine(b1.position, c1.position);
        Gizmos.DrawLine(c1.position, a1.position);
    }
}

 

posted @ 2022-08-13 09:31  HONT  阅读(229)  评论(0编辑  收藏  举报