Esempio n. 1
0
        /**
         * Initialize a new qe_Mesh with @InGameObject.  Must have a valid meshfilter and mesh.
         * GameObject will have it's MeshFilter.sharedMesh property set to the clone mesh for editing.
         * Call qe_Mesh.Revert() to undo this change (and destroy the cloned mesh in the process).
         */
        public static qe_Mesh Create(GameObject InGameObject)
        {
            qe_Mesh qmesh = ScriptableObject.CreateInstance <qe_Mesh>();

            qmesh.hideFlags = HideFlags.DontSave;

            qmesh.gameObject = InGameObject;
            qmesh.transform  = qmesh.gameObject.transform;

            qmesh.originalMesh = InGameObject.GetComponent <MeshFilter>().sharedMesh;
            qmesh.source       = qe_Editor_Utility.GetMeshGUID(qmesh.originalMesh, ref qmesh.originalMeshGUID);

            // Copy mesh from InMesh.
            qmesh.cloneMesh = qe_Mesh_Utility.Clone(InGameObject.GetComponent <MeshFilter>().sharedMesh);
            Undo.RegisterCreatedObjectUndo(qmesh.cloneMesh, "Open Quick Edit");

            Undo.RecordObject(qmesh, "Open Quick Edit");
            qmesh.Apply();

            qmesh.handlesRenderer           = (qe_HandleRenderer)Undo.AddComponent(InGameObject, typeof(qe_HandleRenderer));
            qmesh.handlesRenderer.hideFlags = HideFlags.HideAndDontSave;

            qmesh.handlesRenderer.mesh           = new Mesh();
            qmesh.handlesRenderer.mesh.hideFlags = HideFlags.HideAndDontSave;
            qmesh.handlesRenderer.material       = null;

            qmesh.CacheElements();

            return(qmesh);
        }
Esempio n. 2
0
        public static void RebuildUV2(qe_Mesh mesh)
        {
            Unwrapping.GenerateSecondaryUVSet(mesh.cloneMesh);

            // GenerateSecondaryUVSet may add vertices, so rebuild the
            // internal stores.
            mesh.CacheElements();
        }
Esempio n. 3
0
        /**
         * Remove @triangles from this mesh.
         */
        public static bool DeleteTriangles(qe_Mesh mesh, List <qe_Triangle> triangles)
        {
            List <qe_Triangle> trianglesToRemove = new List <qe_Triangle>(triangles);

            trianglesToRemove.Distinct();

            if (trianglesToRemove.Count == mesh.faces.Length)
            {
                Debug.LogWarning("Cannot delete every triangle on a mesh!");
                return(false);
            }

            int subMeshCount = mesh.cloneMesh.subMeshCount;

            for (int i = 0; i < subMeshCount; i++)
            {
                List <int> remove = new List <int>();
                List <int> tris   = mesh.GetIndices(i).ToList();

                for (int n = 0; n < tris.Count; n += 3)
                {
                    int index = trianglesToRemove.IndexOf(tris[n], tris[n + 1], tris[n + 2]);

                    if (index > -1)
                    {
                        remove.Add(n + 0);
                        remove.Add(n + 1);
                        remove.Add(n + 2);

                        trianglesToRemove.RemoveAt(index);
                    }
                }

                remove.Sort();

                List <int> rebuilt     = new List <int>();
                int        removeIndex = 0;

                for (int n = 0; n < tris.Count; n++)
                {
                    if (removeIndex < remove.Count && n == remove[removeIndex])
                    {
                        removeIndex++;
                        continue;
                    }

                    rebuilt.Add(tris[n]);
                }

                mesh.SetIndices(i, rebuilt.ToArray());
            }

            RemoveUnusedVertices(ref mesh.cloneMesh);

            mesh.CacheElements();
            return(true);
        }
Esempio n. 4
0
        /**
         * Translate all @triangles by @offset.  @offset is in local coordinates.
         */
        public static void TranslateVertices(this qe_Mesh mesh, int[] triangles, Vector3 offset)
        {
            Vector3[] verts = mesh.vertices;

            for (int i = 0; i < triangles.Length; i++)
            {
                verts[triangles[i]] += offset;
            }

            mesh.vertices = verts;
        }
Esempio n. 5
0
        /**
         * Returns true if this point in world space is occluded by a triangle on this object.
         */
        public static bool PointIsOccluded(qe_Mesh mesh, Vector3 worldPoint)
        {
            Camera  cam = SceneView.lastActiveSceneView.camera;
            Vector3 dir = (cam.transform.position - worldPoint).normalized;

            // move the point slightly towards the camera to avoid colliding with its own triangle
            Ray ray = new Ray(worldPoint + dir * .0001f, dir);

            qe_RaycastHit hit;

            return(MeshRaycast(ray, mesh, out hit, Vector3.Distance(cam.transform.position, worldPoint), Culling.Back));
        }
Esempio n. 6
0
        /**
         *	\brief Given a triangle index, locate buddy indices and move all vertices to this new position
         */
        public static void SetSharedVertexPosition(this qe_Mesh mesh, int index, Vector3 position)
        {
            List <int> all = mesh.sharedTriangles[mesh.triangleLookup[index]];

            Vector3[] v = mesh.vertices;

            for (int i = 0; i < all.Count; i++)
            {
                v[all[i]] = position;
            }

            mesh.vertices = v;
        }
Esempio n. 7
0
        /**
         * Iterate all collider components on this mesh and recalculate their size.
         */
        public static void RebuildColliders(qe_Mesh mesh)
        {
            Mesh m = mesh.cloneMesh;

            foreach (Collider c in mesh.gameObject.GetComponents <Collider>())
            {
                System.Type t = c.GetType();

                if (t == typeof(BoxCollider))
                {
                    ((BoxCollider)c).center = m.bounds.center;
                    ((BoxCollider)c).size   = m.bounds.size;
                }
                else
                if (t == typeof(SphereCollider))
                {
                    ((SphereCollider)c).center = m.bounds.center;
                    ((SphereCollider)c).radius = Mathf.Max(Mathf.Max(m.bounds.extents.x,
                                                                     m.bounds.extents.y),
                                                           m.bounds.extents.z);
                }
                else
                if (t == typeof(CapsuleCollider))
                {
                    ((CapsuleCollider)c).center = m.bounds.center;
                    Vector2 xy = new Vector2(m.bounds.extents.x, m.bounds.extents.z);
                    ((CapsuleCollider)c).radius = Mathf.Max(xy.x, xy.y);
                    ((CapsuleCollider)c).height = m.bounds.size.y;
                }
                else
                if (t == typeof(WheelCollider))
                {
                    ((WheelCollider)c).center = m.bounds.center;
                    ((WheelCollider)c).radius = Mathf.Max(Mathf.Max(m.bounds.extents.x,
                                                                    m.bounds.extents.y),
                                                          m.bounds.extents.z);
                }
                else
                if (t == typeof(MeshCollider))
                {
                    mesh.gameObject.GetComponent <MeshCollider>().sharedMesh = null;                    // this is stupid.
                    mesh.gameObject.GetComponent <MeshCollider>().sharedMesh = m;
                }
            }
        }
Esempio n. 8
0
        /**
         *
         */
        public static bool SnapVertices(qe_Mesh mesh, List <int> selected)
        {
            /*
             * Vector3 v = mesh.cloneMesh.vertices[selected[0]];
             *
             * Vector3[] verts = mesh.cloneMesh.vertices;
             * for (int a = 1; a < selected.Count; a++)
             * {
             *  for (int b = 0; b < verts.Length;b++)
             *      if (verts[selected[a]] == verts[b])
             *          verts[b] = v;
             * }
             */
            Vector3[]  verts        = mesh.cloneMesh.vertices;
            List <int> trueSelected = new List <int>();
            Vector3    v            = mesh.cloneMesh.vertices[selected[0]];

            for (int b = 0; b < verts.Length; b++)
            {
                for (int a = 1; a < selected.Count; a++)
                {
                    if (verts[selected[a]] == verts[b])
                    {
                        trueSelected.Add(b);
                    }
                }
            }

            foreach (int i in trueSelected)
            {
                verts[i] = v;
            }

            mesh.cloneMesh.vertices = verts;

            mesh.CacheElements();

            // float d = Vector3.Distance(v,verts[selected[0]]);

            //Debug.Log(">>> " + selected.Count+" / "+c+"/"+d);

            return(true);
        }
Esempio n. 9
0
        /**
         * Do this crazy undo dance because calling Undo.RecordObject(UnityEngine.mesh, "") is insanely slow.
         */
        public static void RecordMeshUndo(qe_Mesh mesh, string message)
        {
            Mesh m = qe_Mesh_Utility.Clone(mesh.cloneMesh);

            Undo.RegisterCreatedObjectUndo(m, message);

            Mesh old = mesh.cloneMesh;

            Undo.RecordObject(mesh, message);
            {
                mesh.cloneMesh = m;
                mesh.Apply();
            }

            Undo.DestroyObjectImmediate(old);

                        #if UNITY_5
            Undo.SetCurrentGroupName(message);
                        #endif
        }
Esempio n. 10
0
        public static void Facetize(qe_Mesh qmesh)
        {
            Mesh mesh = qmesh.cloneMesh;

            int triangleCount = mesh.triangles.Length;

            bool boneWeights_isNull = mesh.boneWeights.NullOrEmpty();
            bool colors_isNull      = mesh.colors.NullOrEmpty();
            bool colors32_isNull    = mesh.colors32.NullOrEmpty();
            bool normals_isNull     = mesh.normals.NullOrEmpty();
            bool tangents_isNull    = mesh.tangents.NullOrEmpty();
            bool uv_isNull          = mesh.uv.NullOrEmpty();
            bool uv2_isNull         = mesh.uv2.NullOrEmpty();

#if UNITY_5
            bool uv3_isNull = mesh.uv3.NullOrEmpty();
            bool uv4_isNull = mesh.uv4.NullOrEmpty();
#endif
            bool vertices_isNull = mesh.vertices.NullOrEmpty();

            BoneWeight[] boneWeights = boneWeights_isNull ? null : new BoneWeight[triangleCount];
            Color[]      colors      = colors_isNull ? null : new Color[triangleCount];
            Color32[]    colors32    = colors32_isNull ? null : new Color32[triangleCount];
            Vector3[]    normals     = normals_isNull ? null : new Vector3[triangleCount];
            Vector4[]    tangents    = tangents_isNull ? null : new Vector4[triangleCount];
            Vector2[]    uv          = uv_isNull ? null : new Vector2[triangleCount];
            Vector2[]    uv2         = uv2_isNull ? null : new Vector2[triangleCount];
#if UNITY_5
            Vector2[] uv3 = uv3_isNull ? null : new Vector2[triangleCount];
            Vector2[] uv4 = uv4_isNull ? null : new Vector2[triangleCount];
#endif
            Vector3[] vertices = new Vector3[triangleCount];

            // cache mesh arrays because accessing them through the reference is slooooow
            Vector3[]    mVertices    = mesh.vertices;
            BoneWeight[] mBoneWeights = mesh.boneWeights;
            Color[]      mColors      = mesh.colors;
            Color32[]    mColors32    = mesh.colors32;
            Vector3[]    mNormals     = mesh.normals;
            Vector4[]    mTangents    = mesh.tangents;
            Vector2[]    mUv          = mesh.uv;
            Vector2[]    mUv2         = mesh.uv2;
#if UNITY_5
            Vector2[] mUv3 = mesh.uv3;
            Vector2[] mUv4 = mesh.uv4;
#endif

            int     index     = 0;
            int[][] triangles = new int[mesh.subMeshCount][];

            for (int i = 0; i < mesh.subMeshCount; i++)
            {
                triangles[i] = qmesh.GetIndices(i);

                for (int t = 0; t < triangles[i].Length; t++)
                {
                    int n = triangles[i][t];

                    if (!boneWeights_isNull)
                    {
                        boneWeights[index] = mBoneWeights[n];
                    }

                    if (!colors_isNull)
                    {
                        colors[index] = mColors[n];
                    }

                    if (!colors32_isNull)
                    {
                        colors32[index] = mColors32[n];
                    }

                    if (!normals_isNull)
                    {
                        normals[index] = mNormals[n];
                    }

                    if (!tangents_isNull)
                    {
                        tangents[index] = mTangents[n];
                    }

                    if (!uv_isNull)
                    {
                        uv[index] = mUv[n];
                    }

                    if (!uv2_isNull)
                    {
                        uv2[index] = mUv2[n];
                    }

#if UNITY_5
                    if (!uv3_isNull)
                    {
                        uv3[index] = mUv3[n];
                    }

                    if (!uv4_isNull)
                    {
                        uv4[index] = mUv4[n];
                    }
#endif
                    if (!vertices_isNull)
                    {
                        vertices[index] = mVertices[n];
                    }


                    triangles[i][t] = index;
                    index++;
                }
            }

            mesh.vertices    = vertices;
            mesh.boneWeights = boneWeights;
            mesh.colors      = colors;
            mesh.colors32    = colors32;
            mesh.normals     = normals;
            mesh.tangents    = tangents;
            mesh.uv          = uv;
            mesh.uv2         = uv2;
#if UNITY_5
            mesh.uv3 = uv3;
            mesh.uv4 = uv4;
#endif

            for (int i = 0; i < mesh.subMeshCount; i++)
            {
                qmesh.SetIndices(i, triangles[i]);
            }

            mesh.RecalculateNormals();

            qmesh.CacheElements();
        }
Esempio n. 11
0
        /**
         *
         */
        public static bool SmoothTriangles(qe_Mesh mesh, List <qe_Triangle> triangles)
        {
            List <Vector3> distinctVerts = new List <Vector3>();

            List <int> tris = new List <int>();
            int        i    = 0;

            foreach (var t in triangles)
            {
                for (int a = 0; a < 3; a++)
                {
                    Vector3 v = mesh.vertices[t.indices[a]];

                    int oldIdx = -1;
                    for (int b = 0; b < distinctVerts.Count; b++)
                    {
                        if (v == distinctVerts[b])
                        {
                            oldIdx = b;
                            break;
                        }
                    }

                    if (oldIdx == -1)
                    {
                        oldIdx = distinctVerts.Count;
                        distinctVerts.Add(v);
                    }

                    tris.Add(oldIdx);
                    i++;
                }
            }

            Debug.Log("Distict verts: " + distinctVerts.Count);

            Mesh tmpMesh = new Mesh();

            tmpMesh.SetVertices(distinctVerts);
            tmpMesh.SetTriangles(tris, 0);

            tmpMesh.RecalculateNormals();

            Debug.Log("New normals: " + tmpMesh.normals.Length);

            Vector3[] norms = mesh.cloneMesh.normals;

            i = 0;
            foreach (var t in triangles)
            {
                for (int a = 0; a < 3; a++)
                {
                    int di = tris[i];

                    Vector3 n = tmpMesh.normals[di];

                    norms[t.indices[a]] = n;

                    i++;
                }
            }

            mesh.cloneMesh.normals = norms;
            mesh.CacheElements();

            return(true);
            //mesh.cloneMesh.RecalculateNormals();
        }
Esempio n. 12
0
 public static void RebuildNormals(qe_Mesh mesh)
 {
     mesh.cloneMesh.RecalculateNormals();
 }
        /**
         * Find the nearest triangle intersected by InWorldRay on this pb_Object.  InWorldRay is in world space.
         * @hit contains information about the hit point.  @distance limits how far from @InWorldRay.origin the hit
         * point may be.  @cullingMode determines what face orientations are tested (Culling.Front only tests front
         * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
         */
        public static bool MeshRaycast(Ray InWorldRay, qe_Mesh mesh, out qe_RaycastHit hit, float distance, Culling cullingMode)
        {
            /**
             * Transform ray into model space
             */

            InWorldRay.origin 		-= mesh.transform.position;  // Why doesn't worldToLocalMatrix apply translation?
            InWorldRay.origin 		= mesh.transform.worldToLocalMatrix * InWorldRay.origin;
            InWorldRay.direction 	= mesh.transform.worldToLocalMatrix * InWorldRay.direction;

            Vector3[] vertices = mesh.vertices;

            float dist = 0f;
            Vector3 point = Vector3.zero;

            float OutHitPoint = Mathf.Infinity;
            float dot; // vars used in loop
            Vector3 nrm;	// vars used in loop
            int OutHitFace = -1;
            Vector3 OutNrm = Vector3.zero;

            /**
             * Iterate faces, testing for nearest hit to ray origin.  Optionally ignores backfaces.
             */
            for(int CurFace = 0; CurFace < mesh.faces.Length; ++CurFace)
            {
                int[] Indices = mesh.faces[CurFace].indices;

                for(int CurTriangle = 0; CurTriangle < Indices.Length; CurTriangle += 3)
                {
                    Vector3 a = vertices[Indices[CurTriangle+0]];
                    Vector3 b = vertices[Indices[CurTriangle+1]];
                    Vector3 c = vertices[Indices[CurTriangle+2]];

                    nrm = Vector3.Cross(b-a, c-a);
                    dot = Vector3.Dot(InWorldRay.direction, nrm);

                    bool ignore = false;

                    switch(cullingMode)
                    {
                        case Culling.Front:
                            if(dot > 0f) ignore = true;
                            break;

                        case Culling.Back:
                            if(dot < 0f) ignore = true;
                            break;
                    }

                    if(!ignore && qe_Math.RayIntersectsTriangle(InWorldRay, a, b, c, out dist, out point))
                    {
                        if(dist > OutHitPoint || dist > distance)
                            continue;

                        OutNrm = nrm;
                        OutHitFace = CurFace;
                        OutHitPoint = dist;

                        continue;
                    }
                }
            }

            hit = new qe_RaycastHit(OutHitPoint,
                                    InWorldRay.GetPoint(OutHitPoint),
                                    OutNrm,
                                    OutHitFace);

            return OutHitFace > -1;
        }
        /**
         * Returns true if this point in world space is occluded by a triangle on this object.
         */
        public static bool PointIsOccluded(qe_Mesh mesh, Vector3 worldPoint)
        {
            Camera cam = SceneView.lastActiveSceneView.camera;
            Vector3 dir = (cam.transform.position - worldPoint).normalized;

            // move the point slightly towards the camera to avoid colliding with its own triangle
            Ray ray = new Ray(worldPoint + dir * .0001f, dir);

            qe_RaycastHit hit;

            return MeshRaycast(ray, mesh, out hit, Vector3.Distance(cam.transform.position, worldPoint), Culling.Back);
        }
Esempio n. 15
0
 public static Vector3 Normal(this qe_Mesh mesh, qe_Triangle tri)
 {
     return(Normal(mesh.vertices[tri.x], mesh.vertices[tri.y], mesh.vertices[tri.z]));
 }
Esempio n. 16
0
        public static bool VertexRaycast(Vector2 mousePosition, int rectSize, ElementCache selection, out int index)
        {
            qe_Mesh mesh = selection.mesh;

            float bestDistance = Mathf.Infinity;
            float distance     = 0f;

            index = -1;

            GameObject go = HandleUtility.PickGameObject(mousePosition, false);

            if (go == null || go != selection.transform.gameObject)
            {
                Camera cam    = SceneView.lastActiveSceneView.camera;
                int    width  = Screen.width;
                int    height = Screen.height;

                Rect       mouseRect = new Rect(mousePosition.x - (rectSize / 2f), mousePosition.y - (rectSize / 2f), rectSize, rectSize);
                List <int> user      = (List <int>)selection.mesh.GetUserIndices();

                for (int i = 0; i < user.Count; i++)
                {
                    if (mouseRect.Contains(HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[user[i]])))
                    {
                        Vector3 v = cam.WorldToScreenPoint(selection.verticesInWorldSpace[user[i]]);

                        distance = Vector2.Distance(mousePosition, v);

                        if (distance < bestDistance)
                        {
                            if (v.z <= 0 || v.x < 0 || v.y < 0 || v.x > width || v.y > height)
                            {
                                continue;
                            }

                            if (PointIsOccluded(mesh, selection.verticesInWorldSpace[user[i]]))
                            {
                                continue;
                            }

                            index        = user[i];
                            bestDistance = Vector2.Distance(v, mousePosition);
                        }
                    }
                }
            }
            else
            {
                // Test culling
                List <qe_RaycastHit> hits;
                Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition);

                if (MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack))
                {
                    // Sort from nearest hit to farthest
                    hits.Sort((x, y) => x.Distance.CompareTo(y.Distance));

                    // Find the nearest edge in the hit faces
                    Vector3[] v = mesh.vertices;

                    for (int i = 0; i < hits.Count; i++)
                    {
                        if (PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point)))
                        {
                            continue;
                        }

                        foreach (int tri in mesh.faces[hits[i].FaceIndex].indices)
                        {
                            float d = Vector3.Distance(hits[i].Point, v[tri]);

                            if (d < bestDistance)
                            {
                                bestDistance = d;
                                index        = tri;
                            }
                        }

                        if (Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f)
                        {
                            break;
                        }
                    }

                    if (index > -1 && Vector2.Distance(mousePosition, HandleUtility.WorldToGUIPoint(selection.verticesInWorldSpace[index])) > rectSize * 1.3f)
                    {
                        index = -1;
                    }
                }
            }

            if (index > -1)
            {
                index = mesh.ToUserIndex(index);
            }

            return(index > -1);
        }
Esempio n. 17
0
        /**
         * Checks if mouse is over an edge, and if so, returns true setting @edge.
         */
        public static bool EdgeRaycast(Vector2 mousePosition, ElementCache selection, out qe_Edge edge)
        {
            qe_Mesh mesh = selection.mesh;

            Vector3 v0, v1;
            float   bestDistance = Mathf.Infinity;
            float   distance     = 0f;

            edge = null;

            GameObject go = HandleUtility.PickGameObject(mousePosition, false);

            if (go == null || go != selection.transform.gameObject)
            {
                qe_Edge[] edges = mesh.userEdges;

                int width  = Screen.width;
                int height = Screen.height;

                for (int i = 0; i < edges.Length; i++)
                {
                    v0 = selection.verticesInWorldSpace[edges[i].x];
                    v1 = selection.verticesInWorldSpace[edges[i].y];

                    distance = HandleUtility.DistanceToLine(v0, v1);

                    if (distance < bestDistance && distance < MAX_EDGE_SELECT_DISTANCE)                      // && !PointIsOccluded(mesh, (v0+v1)*.5f) )
                    {
                        Vector3 vs0 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v0);

                        // really simple frustum check (will fail on edges that have vertices outside the frustum but is visible)
                        if (vs0.z <= 0 || vs0.x < 0 || vs0.y < 0 || vs0.x > width || vs0.y > height)
                        {
                            continue;
                        }

                        Vector3 vs1 = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(v1);

                        if (vs1.z <= 0 || vs1.x < 0 || vs1.y < 0 || vs1.x > width || vs1.y > height)
                        {
                            continue;
                        }


                        bestDistance = distance;
                        edge         = edges[i];
                    }
                }
            }
            else
            {
                // Test culling
                List <qe_RaycastHit> hits;
                Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition);

                if (MeshRaycast(ray, mesh, out hits, Mathf.Infinity, Culling.FrontBack))
                {
                    // Sort from nearest hit to farthest
                    hits.Sort((x, y) => x.Distance.CompareTo(y.Distance));

                    // Find the nearest edge in the hit faces
                    Vector3[] v = mesh.vertices;

                    for (int i = 0; i < hits.Count; i++)
                    {
                        if (PointIsOccluded(mesh, mesh.transform.TransformPoint(hits[i].Point)))
                        {
                            continue;
                        }

                        foreach (qe_Edge e in mesh.faces[hits[i].FaceIndex].GetEdges())
                        {
                            float d = HandleUtility.DistancePointLine(hits[i].Point, v[e.x], v[e.y]);

                            if (d < bestDistance)
                            {
                                bestDistance = d;
                                edge         = e;
                            }
                        }

                        if (Vector3.Dot(ray.direction, mesh.transform.TransformDirection(hits[i].Normal)) < 0f)
                        {
                            break;
                        }
                    }

                    if (edge != null && HandleUtility.DistanceToLine(mesh.transform.TransformPoint(v[edge.x]), mesh.transform.TransformPoint(v[edge.y])) > MAX_EDGE_SELECT_DISTANCE)
                    {
                        edge = null;
                    }
                    else
                    {
                        edge.x = mesh.ToUserIndex(edge.x);
                        edge.y = mesh.ToUserIndex(edge.y);
                    }
                }
            }

            return(edge != null);
        }
Esempio n. 18
0
        /**
         * Find the all triangles intersected by InWorldRay on this pb_Object.  InWorldRay is in world space.
         * @hit contains information about the hit point.  @distance limits how far from @InWorldRay.origin the hit
         * point may be.  @cullingMode determines what face orientations are tested (Culling.Front only tests front
         * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
         */
        public static bool MeshRaycast(Ray InWorldRay, qe_Mesh qe, out List <qe_RaycastHit> hits, float distance, Culling cullingMode)
        {
            /**
             * Transform ray into model space
             */
            InWorldRay.origin -= qe.transform.position;              // Why doesn't worldToLocalMatrix apply translation?

            InWorldRay.origin    = qe.transform.worldToLocalMatrix * InWorldRay.origin;
            InWorldRay.direction = qe.transform.worldToLocalMatrix * InWorldRay.direction;

            Vector3[] vertices = qe.vertices;

            float   dist  = 0f;
            Vector3 point = Vector3.zero;

            float   dot;           // vars used in loop
            Vector3 nrm;           // vars used in loop

            hits = new List <qe_RaycastHit>();

            /**
             * Iterate faces, testing for nearest hit to ray origin.  Optionally ignores backfaces.
             */
            for (int CurFace = 0; CurFace < qe.faces.Length; ++CurFace)
            {
                int[] Indices = qe.faces[CurFace].indices;

                for (int CurTriangle = 0; CurTriangle < Indices.Length; CurTriangle += 3)
                {
                    Vector3 a = vertices[Indices[CurTriangle + 0]];
                    Vector3 b = vertices[Indices[CurTriangle + 1]];
                    Vector3 c = vertices[Indices[CurTriangle + 2]];

                    if (qe_Math.RayIntersectsTriangle(InWorldRay, a, b, c, out dist, out point))
                    {
                        nrm = Vector3.Cross(b - a, c - a);

                        switch (cullingMode)
                        {
                        case Culling.Front:
                            dot = Vector3.Dot(InWorldRay.direction, -nrm);

                            if (dot > 0f)
                            {
                                goto case Culling.FrontBack;
                            }
                            break;

                        case Culling.Back:
                            dot = Vector3.Dot(InWorldRay.direction, nrm);

                            if (dot > 0f)
                            {
                                goto case Culling.FrontBack;
                            }
                            break;

                        case Culling.FrontBack:
                            hits.Add(new qe_RaycastHit(dist,
                                                       InWorldRay.GetPoint(dist),
                                                       nrm,
                                                       CurFace));
                            break;
                        }

                        continue;
                    }
                }
            }

            return(hits.Count > 0);
        }
Esempio n. 19
0
        /**
         * Find the nearest triangle intersected by InWorldRay on this pb_Object.  InWorldRay is in world space.
         * @hit contains information about the hit point.  @distance limits how far from @InWorldRay.origin the hit
         * point may be.  @cullingMode determines what face orientations are tested (Culling.Front only tests front
         * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
         */
        public static bool MeshRaycast(Ray InWorldRay, qe_Mesh mesh, out qe_RaycastHit hit, float distance, Culling cullingMode)
        {
            /**
             * Transform ray into model space
             */

            InWorldRay.origin   -= mesh.transform.position;                          // Why doesn't worldToLocalMatrix apply translation?
            InWorldRay.origin    = mesh.transform.worldToLocalMatrix * InWorldRay.origin;
            InWorldRay.direction = mesh.transform.worldToLocalMatrix * InWorldRay.direction;

            Vector3[] vertices = mesh.vertices;

            float   dist  = 0f;
            Vector3 point = Vector3.zero;

            float   OutHitPoint = Mathf.Infinity;
            float   dot;           // vars used in loop
            Vector3 nrm;           // vars used in loop
            int     OutHitFace = -1;
            Vector3 OutNrm     = Vector3.zero;

            /**
             * Iterate faces, testing for nearest hit to ray origin.  Optionally ignores backfaces.
             */
            for (int CurFace = 0; CurFace < mesh.faces.Length; ++CurFace)
            {
                int[] Indices = mesh.faces[CurFace].indices;

                for (int CurTriangle = 0; CurTriangle < Indices.Length; CurTriangle += 3)
                {
                    Vector3 a = vertices[Indices[CurTriangle + 0]];
                    Vector3 b = vertices[Indices[CurTriangle + 1]];
                    Vector3 c = vertices[Indices[CurTriangle + 2]];

                    nrm = Vector3.Cross(b - a, c - a);
                    dot = Vector3.Dot(InWorldRay.direction, nrm);

                    bool ignore = false;

                    switch (cullingMode)
                    {
                    case Culling.Front:
                        if (dot > 0f)
                        {
                            ignore = true;
                        }
                        break;

                    case Culling.Back:
                        if (dot < 0f)
                        {
                            ignore = true;
                        }
                        break;
                    }

                    if (!ignore && qe_Math.RayIntersectsTriangle(InWorldRay, a, b, c, out dist, out point))
                    {
                        if (dist > OutHitPoint || dist > distance)
                        {
                            continue;
                        }

                        OutNrm      = nrm;
                        OutHitFace  = CurFace;
                        OutHitPoint = dist;

                        continue;
                    }
                }
            }

            hit = new qe_RaycastHit(OutHitPoint,
                                    InWorldRay.GetPoint(OutHitPoint),
                                    OutNrm,
                                    OutHitFace);

            return(OutHitFace > -1);
        }
 /**
  * Find a triangle intersected by InRay on InMesh.  InRay is in world space.
  * Returns the index in mesh.faces of the hit face, or -1.  Optionally can ignore
  * backfaces.
  */
 public static bool MeshRaycast(Ray InWorldRay, qe_Mesh mesh, out qe_RaycastHit hit)
 {
     return MeshRaycast(InWorldRay, mesh, out hit, Mathf.Infinity, Culling.Front);
 }
Esempio n. 21
0
        /**
         * Returns true if save was successfull, false if user-cancelled or otherwise failed.
         */
        public static bool SaveMeshAssetIfNecessary(qe_Mesh mesh)
        {
            string save_path = DO_NOT_SAVE;

            switch (mesh.source)
            {
            case ModelSource.Asset:

                int saveChanges = EditorUtility.DisplayDialogComplex(
                    "Save Changes",
                    "Save changes to edited mesh?",
                    "Save",                                                     // DIALOG_OK
                    "Cancel",                                                   // DIALOG_CANCEL
                    "Save As");                                                 // DIALOG_ALT

                if (saveChanges == DIALOG_OK)
                {
                    save_path = AssetDatabase.GetAssetPath(mesh.originalMesh);
                }
                else if (saveChanges == DIALOG_ALT)
                {
                    save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.cloneMesh.name + ".asset", "asset", "Save edited mesh to");
                }
                else
                {
                    return(false);
                }

                break;

            case ModelSource.Imported:
            case ModelSource.Scene:
            default:
                // @todo make sure path is in Assets/
                save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.cloneMesh.name + ".asset", "asset", "Save edited mesh to");
                break;
            }

            if (!save_path.Equals(DO_NOT_SAVE) && !string.IsNullOrEmpty(save_path))
            {
                Object existing = AssetDatabase.LoadMainAssetAtPath(save_path);

                if (existing != null)
                {
                    qe_Mesh_Utility.Copy((Mesh)existing, mesh.cloneMesh);
                    GameObject.DestroyImmediate(mesh.cloneMesh);
                }
                else
                {
                    AssetDatabase.CreateAsset(mesh.cloneMesh, save_path);
                }

                AssetDatabase.Refresh();

                MeshFilter          mf = mesh.gameObject.GetComponent <MeshFilter>();
                SkinnedMeshRenderer mr = mesh.gameObject.GetComponent <SkinnedMeshRenderer>();

                if (mf != null)
                {
                    mf.sharedMesh = (Mesh)AssetDatabase.LoadAssetAtPath(save_path, typeof(Mesh));
                }
                else if (mr != null)
                {
                    mr.sharedMesh = (Mesh)AssetDatabase.LoadAssetAtPath(save_path, typeof(Mesh));
                }

                return(true);
            }

            // Save was canceled
            return(false);
        }
        /**
         * Find the all triangles intersected by InWorldRay on this pb_Object.  InWorldRay is in world space.
         * @hit contains information about the hit point.  @distance limits how far from @InWorldRay.origin the hit
         * point may be.  @cullingMode determines what face orientations are tested (Culling.Front only tests front
         * faces, Culling.Back only tests back faces, and Culling.FrontBack tests both).
         */
        public static bool MeshRaycast(Ray InWorldRay, qe_Mesh qe, out List<qe_RaycastHit> hits, float distance, Culling cullingMode)
        {
            /**
             * Transform ray into model space
             */
            InWorldRay.origin -= qe.transform.position;  // Why doesn't worldToLocalMatrix apply translation?

            InWorldRay.origin 		= qe.transform.worldToLocalMatrix * InWorldRay.origin;
            InWorldRay.direction 	= qe.transform.worldToLocalMatrix * InWorldRay.direction;

            Vector3[] vertices = qe.vertices;

            float dist = 0f;
            Vector3 point = Vector3.zero;

            float dot; // vars used in loop
            Vector3 nrm;	// vars used in loop
            hits = new List<qe_RaycastHit>();

            /**
             * Iterate faces, testing for nearest hit to ray origin.  Optionally ignores backfaces.
             */
            for(int CurFace = 0; CurFace < qe.faces.Length; ++CurFace)
            {
                int[] Indices = qe.faces[CurFace].indices;

                for(int CurTriangle = 0; CurTriangle < Indices.Length; CurTriangle += 3)
                {
                    Vector3 a = vertices[Indices[CurTriangle+0]];
                    Vector3 b = vertices[Indices[CurTriangle+1]];
                    Vector3 c = vertices[Indices[CurTriangle+2]];

                    if(qe_Math.RayIntersectsTriangle(InWorldRay, a, b, c, out dist, out point))
                    {
                        nrm = Vector3.Cross(b-a, c-a);

                        switch(cullingMode)
                        {
                            case Culling.Front:
                                dot = Vector3.Dot(InWorldRay.direction, -nrm);

                                if(dot > 0f)
                                    goto case Culling.FrontBack;
                                break;

                            case Culling.Back:
                                dot = Vector3.Dot(InWorldRay.direction, nrm);

                                if(dot > 0f)
                                    goto case Culling.FrontBack;
                                break;

                            case Culling.FrontBack:
                                hits.Add( new qe_RaycastHit(dist,
                                                            InWorldRay.GetPoint(dist),
                                                            nrm,
                                                            CurFace));
                                break;
                        }

                        continue;
                    }
                }
            }

            return hits.Count > 0;
        }
Esempio n. 23
0
 /**
  * Find a triangle intersected by InRay on InMesh.  InRay is in world space.
  * Returns the index in mesh.faces of the hit face, or -1.  Optionally can ignore
  * backfaces.
  */
 public static bool MeshRaycast(Ray InWorldRay, qe_Mesh mesh, out qe_RaycastHit hit)
 {
     return(MeshRaycast(InWorldRay, mesh, out hit, Mathf.Infinity, Culling.Front));
 }
        /**
         * Returns true if save was successfull, false if user-cancelled or otherwise failed.
         */
        public static bool SaveMeshAssetIfNecessary(qe_Mesh mesh)
        {
            string save_path = DO_NOT_SAVE;

            switch( mesh.source )
            {
                case ModelSource.Asset:

                    int saveChanges = EditorUtility.DisplayDialogComplex(
                        "Save Changes",
                        "Save changes to edited mesh?",
                        "Save",				// DIALOG_OK
                        "Cancel",			// DIALOG_CANCEL
                        "Save As");			// DIALOG_ALT

                    if( saveChanges == DIALOG_OK )
                        save_path = AssetDatabase.GetAssetPath(mesh.originalMesh);
                    else if( saveChanges == DIALOG_ALT )
                        save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.cloneMesh.name + ".asset", "asset", "Save edited mesh to");
                    else
                        return false;

                    break;

                case ModelSource.Imported:
                case ModelSource.Scene:
                default:
                    // @todo make sure path is in Assets/
                    save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.cloneMesh.name + ".asset", "asset", "Save edited mesh to");
                break;
            }

            if( !save_path.Equals(DO_NOT_SAVE) && !string.IsNullOrEmpty(save_path) )
            {
                Object existing = AssetDatabase.LoadMainAssetAtPath(save_path);

                if( existing != null )
                {
                    qe_Mesh_Utility.Copy( (Mesh)existing, mesh.cloneMesh);
                    GameObject.DestroyImmediate(mesh.cloneMesh);
                }
                else
                {
                    AssetDatabase.CreateAsset(mesh.cloneMesh, save_path );
                }

                AssetDatabase.Refresh();

                mesh.gameObject.GetComponent<MeshFilter>().sharedMesh = (Mesh)AssetDatabase.LoadAssetAtPath(save_path, typeof(Mesh));
                return true;
            }

            // Save was canceled
            return false;
        }
Esempio n. 25
0
 /**
  * Translates @offset into local space and moves all vertices pointed to by triangles that amount.
  */
 public static void TranslateVertices_World(this qe_Mesh mesh, int[] triangles, Vector3 offset)
 {
     mesh.TranslateVertices(triangles, mesh.transform.worldToLocalMatrix * offset);
 }