gradientspace / geometry3Sharp

C# library for 2D/3D geometric computation, mesh algorithms, and so on. Boost license.
http://www.gradientspace.com
Boost Software License 1.0
1.72k stars 390 forks source link

Tri Tri Intersection of Unity spheres #81

Closed hassanyawar closed 5 years ago

hassanyawar commented 5 years ago

I'm using Unity to test the triangle intersection of two Unity sphere meshes. I converted the Unity mesh data to built DMesh3 using Build method of DMesh3Builder and provided vertices and triangles from Unity's Mesh data structure. I intend to generate spheres on the intersection points. Here is a chunk of my code to give you an idea.

DMesh3 meshA = DMesh3Builder.Build(verticesA, trianglesA, normalsA);
DMesh3 meshB = DMesh3Builder.Build(verticesB, trianglesB, normalsB);

DMeshAABBTree3 spatialA = new DMeshAABBTree3(meshA, true);
DMeshAABBTree3 spatialB = new DMeshAABBTree3(meshB, true);

DMeshAABBTree3.IntersectionsQueryResult iqr = spatialA.FindAllIntersections(spatialB);
List<DMeshAABBTree3.PointIntersection> pointIntersection = iqr.Points;

for (int i = 0; i < pointIntersection.Count; i++)
{
    GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    sphere.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);
    sphere.transform.position = (Vector3) pointIntersection[i].point;
}

intersectionballs

In the screenshot there is no apparent intersection but spheres are still being generated as if there is intersection. Need some help.

rms80 commented 5 years ago

You need to transform the vertices of each mesh into world coordinates. You can use this function: https://docs.unity3d.com/ScriptReference/Transform.TransformPoint.html

hassanyawar commented 5 years ago

Alright, so I need to convert each mesh's vertices in to world coordinates and then assign them into Build method of DMesh3Builder. Thanks. I'll let you know how that turns out.

hassanyawar commented 5 years ago

Converting them into world space was success in a way but I'm still facing some issue. I'm going to paste my whole code to give you an idea and some more screenshots to let you know the issue.

public MeshFilter mf1;
public MeshFilter mf2;

void Start ()
{
        // Caching meshes
    Mesh mesh1 = mf1.sharedMesh;
    Mesh mesh2 = mf2.sharedMesh;

        // Caching transforms
    Transform t1 = mf1.transform;
    Transform t2 = mf2.transform;

    // Creating Vector3f lists for converted data
    List<Vector3f> newVerticesA = new List<Vector3f>();
    List<Vector3f> newVerticesB = new List<Vector3f>();
    List<Vector3f> newNormalsA = new List<Vector3f>();
    List<Vector3f> newNormalsB = new List<Vector3f>();

        // Getting vertices, triangles and normals for mesh 1
    Vector3[] oldVerticesA = mesh1.vertices;
    Vector3[] oldNormalsA = mesh1.normals;
    int[] trianglesA = mesh1.triangles;

    // Getting vertices, triangles and normals for mesh 2
    Vector3[] oldVerticesB = mesh2.vertices;
    Vector3[] oldNormalsB = mesh2.normals;
    int[] trianglesB = mesh2.triangles;

    // Converting Vector3 to Vector3f and local positions/directions to world positions/directions for mesh 1
    for (int i = 0; i < oldVerticesA.Length; i++)
    {
        newVerticesA.Add(t1.TransformPoint(oldVerticesA[i]));
        newNormalsA.Add(t1.TransformDirection(oldNormalsA[i]));
    }

    // Converting Vector3 to Vector3f and local positions/directions to world positions/directions for mesh 2
    for (int i = 0; i < oldVerticesB.Length; i++)
    {
        newVerticesB.Add(t2.TransformPoint(oldVerticesB[i]));
        newNormalsB.Add(t2.TransformDirection(oldNormalsB[i]));
    }

    // Building g3 meshes       
    DMesh3 meshA = DMesh3Builder.Build(newVerticesA, trianglesA, newNormalsA);
    DMesh3 meshB = DMesh3Builder.Build(newVerticesB, trianglesB, newNormalsB);

    // Building AABB trees
    DMeshAABBTree3 treeA = new DMeshAABBTree3(meshA, true);
    DMeshAABBTree3 treeB = new DMeshAABBTree3(meshB, true);

    // Getting all intersection points
    DMeshAABBTree3.IntersectionsQueryResult iqr = treeA.FindAllIntersections(treeB);
    List<DMeshAABBTree3.PointIntersection> pointIntersection = iqr.Points;

    // Instantiating small spheres on intersection points
    for (int i = 0; i < pointIntersection.Count; i++)
    {
        GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);
        sphere.transform.position = (Vector3) pointIntersection[i].point;
    }
}

intersectiontest1 intersectiontest2

I have attached fade material to both spheres and reduced alpha to around half to intersection spheres can be observed. I have taken 2 screenshots. One is from front and other is kind of cross-section. Clearly both spheres are overlapping but the intersection spheres are not enough to cover the intersection triangles. I've also tried to change the position of the spheres but I never get all intersection points. Maybe I'm doing something wrong. Can you guide me?

rms80 commented 5 years ago

I can't see anything in these images they are just black.

The Point intersections are where two triangles touch exactly at an edge or vertex. This hardly ever happens, it is basically a degenerate case. Use the segment intersections.

hassanyawar commented 5 years ago

Hey, its working. You are right, segment intersections are what I needed. Thanks a lot. Now before I close this issue I need to ask you that if I change the position of my sphere do I have restart from rebuilding DMesh3 and then DMeshAABBTree3 to get appropriate intersections according to the new position?

rms80 commented 5 years ago

That's what the TransformF argument to FindAllIntersections is for. You can use that to transform the meshes into a consistent coordinate space, instead of updating the vertices in dmesh3 and rebuilding the tree.

hassanyawar commented 5 years ago

Can you give me an example of TransformF? I mean I need example code of using System.Func with meshes because I'm not well versed in its usage. I would really appreciate your help in it.

rms80 commented 5 years ago

it's not specific to meshes, it is just a function that transforms Vector3d, it can be a lambda for example. Passing "(x) => {return x + new Vector3d(10,0,0);}" would result in the mesh vertices being translated by 10 along X axis. You have to write your own transform function as it it depends entirely on your usage/context.

hassanyawar commented 5 years ago

Sorry for the delayed reply!!! And thank you for your help. I'm closing this issue now.