Esempio n. 1
0
        void DrawSelectionToolUI()
        {
            GUILayout.Label(selectedCount + " particle(s) selected");

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Invert", GUILayout.Width(88)))
            {
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    if (actor.active[i])
                    {
                        selectionStatus[i] = !selectionStatus[i];
                    }
                }
                SelectionChanged();
            }
            GUI.enabled = selectedCount > 0;
            if (GUILayout.Button("Clear", GUILayout.Width(88)))
            {
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    selectionStatus[i] = false;
                }
                SelectionChanged();
            }
            GUI.enabled = true;
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Select fixed", GUILayout.Width(88)))
            {
                for (int i = 0; i < actor.invMasses.Length; i++)
                {
                    if (actor.active[i] && actor.invMasses[i] == 0)
                    {
                        selectionStatus[i] = true;
                    }
                }
                SelectionChanged();
            }
            GUI.enabled = selectedCount > 0;
            if (GUILayout.Button("Unselect fixed", GUILayout.Width(88)))
            {
                for (int i = 0; i < actor.invMasses.Length; i++)
                {
                    if (actor.active[i] && actor.invMasses[i] == 0)
                    {
                        selectionStatus[i] = false;
                    }
                }
                SelectionChanged();
            }
            GUI.enabled = true;
            GUILayout.EndHorizontal();

            GUI.enabled = selectedCount > 0;
            GUILayout.BeginHorizontal();

            if (GUILayout.Button(new GUIContent("Fix", EditorGUIUtility.Load("PinIcon.psd") as Texture2D), GUILayout.MaxHeight(18), GUILayout.Width(88)))
            {
                Undo.RecordObject(actor, "Fix particles");
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    if (selectionStatus[i])
                    {
                        if (actor.invMasses[i] != 0)
                        {
                            SetPropertyValue(ParticleProperty.MASS, i, Mathf.Infinity);
                            newProperty         = GetPropertyValue(ParticleProperty.MASS, i);
                            actor.velocities[i] = Vector3.zero;
                        }
                    }
                }
                actor.PushDataToSolver(new ObiSolverData(ObiSolverData.ParticleData.INV_MASSES | ObiSolverData.ParticleData.VELOCITIES));
                EditorUtility.SetDirty(actor);
            }

            if (GUILayout.Button(new GUIContent("Unfix", EditorGUIUtility.Load("UnpinIcon.psd") as Texture2D), GUILayout.MaxHeight(18), GUILayout.Width(88)))
            {
                Undo.RecordObject(actor, "Unfix particles");
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    if (selectionStatus[i])
                    {
                        if (actor.invMasses[i] == 0)
                        {
                            SetPropertyValue(ParticleProperty.MASS, i, 1);
                        }
                    }
                }
                actor.PushDataToSolver(new ObiSolverData(ObiSolverData.ParticleData.INV_MASSES));
                EditorUtility.SetDirty(actor);
            }

            if (GUILayout.Button("CUT"))
            {
                ObiCloth mesh = ((ObiCloth)actor);
                mesh.DistanceConstraints.RemoveFromSolver(null);
                mesh.AerodynamicConstraints.RemoveFromSolver(null);
                MeshBuffer buf = new MeshBuffer(mesh.clothMesh);

                int[] sel = new int[2];
                int   k   = 0;
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    if (selectionStatus[i])
                    {
                        sel[k] = i;
                        k++;
                        if (k == 2)
                        {
                            break;
                        }
                    }
                }

                int cindex = -1;
                for (int j = 0; j < mesh.DistanceConstraints.restLengths.Count; j++)
                {
                    if ((mesh.DistanceConstraints.springIndices[j * 2] == sel[0] && mesh.DistanceConstraints.springIndices[j * 2 + 1] == sel[1]) ||
                        (mesh.DistanceConstraints.springIndices[j * 2] == sel[1] && mesh.DistanceConstraints.springIndices[j * 2 + 1] == sel[0]))
                    {
                        cindex = j;
                        break;
                    }
                }
                if (cindex >= 0)
                {
                    mesh.Tear(cindex, buf);
                }


                mesh.DistanceConstraints.AddToSolver(mesh);
                mesh.AerodynamicConstraints.AddToSolver(mesh);
                buf.Apply();

                mesh.GetMeshDataArrays(mesh.clothMesh);
            }

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();

            EditorGUI.showMixedValue = false;
            for (int i = 0; i < selectionStatus.Length; i++)
            {
                if (selectionStatus[i] && !Mathf.Approximately(GetPropertyValue(currentProperty, i), selectionProperty))
                {
                    EditorGUI.showMixedValue = true;
                }
            }

            newProperty = EditorGUILayout.FloatField(newProperty, GUILayout.Width(88));
            EditorGUI.showMixedValue = false;

            if (GUILayout.Button("Set " + GetPropertyName(), GUILayout.Width(88)))
            {
                Undo.RecordObject(actor, "Set particle property");
                selectionProperty = newProperty;
                for (int i = 0; i < selectionStatus.Length; i++)
                {
                    if (selectionStatus[i])
                    {
                        SetPropertyValue(currentProperty, i, selectionProperty);
                    }
                }
                ParticlePropertyChanged();
                EditorUtility.SetDirty(actor);
            }

            GUILayout.EndHorizontal();
            GUI.enabled = true;
        }
        void DrawSelectionToolUI()
        {
            GUILayout.Label(selectedCount+" particle(s) selected");

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Invert",GUILayout.Width(88))){
                for(int i = 0; i < selectionStatus.Length; i++){
                    if (actor.active[i])
                        selectionStatus[i] = !selectionStatus[i];
                }
                SelectionChanged();
            }
            GUI.enabled = selectedCount > 0;
            if (GUILayout.Button("Clear",GUILayout.Width(88))){
                for(int i = 0; i < selectionStatus.Length; i++)
                    selectionStatus[i] = false;
                SelectionChanged();
            }
            GUI.enabled = true;
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Select fixed",GUILayout.Width(88))){
                for(int i = 0; i < actor.invMasses.Length; i++){
                    if (actor.active[i] && actor.invMasses[i] == 0)
                        selectionStatus[i] = true;
                }
                SelectionChanged();
            }
            GUI.enabled = selectedCount > 0;
            if (GUILayout.Button("Unselect fixed",GUILayout.Width(88))){
                for(int i = 0; i < actor.invMasses.Length; i++){
                    if (actor.active[i] && actor.invMasses[i] == 0)
                        selectionStatus[i] = false;
                }
                SelectionChanged();
            }
            GUI.enabled = true;
            GUILayout.EndHorizontal();

            GUI.enabled = selectedCount > 0;
            GUILayout.BeginHorizontal();

            if (GUILayout.Button(new GUIContent("Fix",EditorGUIUtility.Load("PinIcon.psd") as Texture2D),GUILayout.MaxHeight(18),GUILayout.Width(88))){
                Undo.RecordObject(actor, "Fix particles");
                for(int i = 0; i < selectionStatus.Length; i++){
                    if (selectionStatus[i]){
                        if (actor.invMasses[i] != 0){
                            SetPropertyValue(ParticleProperty.MASS,i,Mathf.Infinity);
                            newProperty = GetPropertyValue(ParticleProperty.MASS,i);
                            actor.velocities[i] = Vector3.zero;
                        }
                    }
                }
                actor.PushDataToSolver(new ObiSolverData(ObiSolverData.ParticleData.INV_MASSES | ObiSolverData.ParticleData.VELOCITIES));
                EditorUtility.SetDirty(actor);
            }

            if (GUILayout.Button(new GUIContent("Unfix",EditorGUIUtility.Load("UnpinIcon.psd") as Texture2D),GUILayout.MaxHeight(18),GUILayout.Width(88))){
                Undo.RecordObject(actor, "Unfix particles");
                for(int i = 0; i < selectionStatus.Length; i++){
                    if (selectionStatus[i]){
                        if (actor.invMasses[i] == 0){
                            SetPropertyValue(ParticleProperty.MASS,i,1);
                        }
                    }
                }
                actor.PushDataToSolver(new ObiSolverData(ObiSolverData.ParticleData.INV_MASSES));
                EditorUtility.SetDirty(actor);
            }

            if (GUILayout.Button("CUT")){
                ObiCloth mesh = ((ObiCloth)actor);
                mesh.DistanceConstraints.RemoveFromSolver(null);
                mesh.AerodynamicConstraints.RemoveFromSolver(null);
                MeshBuffer buf = new MeshBuffer(mesh.clothMesh);

                int[] sel = new int[2];
                int k = 0;
                for(int i = 0; i < selectionStatus.Length; i++){
                    if (selectionStatus[i]){
                        sel[k] = i;
                        k++;
                        if (k == 2) break;
                    }
                }

                int cindex = -1;
                for (int j = 0; j < mesh.DistanceConstraints.restLengths.Count; j++){
                    if ((mesh.DistanceConstraints.springIndices[j*2] == sel[0] && mesh.DistanceConstraints.springIndices[j*2+1] == sel[1]) ||
                        (mesh.DistanceConstraints.springIndices[j*2] == sel[1] && mesh.DistanceConstraints.springIndices[j*2+1] == sel[0])){
                        cindex = j;
                        break;
                    }
                }
                if (cindex >= 0)
                    mesh.Tear(cindex,buf);

                mesh.DistanceConstraints.AddToSolver(mesh);
                mesh.AerodynamicConstraints.AddToSolver(mesh);
                buf.Apply();

                mesh.GetMeshDataArrays(mesh.clothMesh);
            }

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();

            EditorGUI.showMixedValue = false;
            for(int i = 0; i < selectionStatus.Length; i++){
                if (selectionStatus[i] && !Mathf.Approximately(GetPropertyValue(currentProperty,i), selectionProperty)){
                    EditorGUI.showMixedValue = true;
                }
            }

            newProperty = EditorGUILayout.FloatField(newProperty,GUILayout.Width(88));
            EditorGUI.showMixedValue = false;

            if (GUILayout.Button("Set "+GetPropertyName(),GUILayout.Width(88))){
                Undo.RecordObject(actor, "Set particle property");
                selectionProperty = newProperty;
                for(int i = 0; i < selectionStatus.Length; i++){
                    if (selectionStatus[i]){
                        SetPropertyValue(currentProperty,i,selectionProperty);
                    }
                }
                ParticlePropertyChanged();
                EditorUtility.SetDirty(actor);
            }

            GUILayout.EndHorizontal();
            GUI.enabled = true;
        }
Esempio n. 3
0
        /**
         * Calculates angle-weighted normals for the input mesh, taking into account shared vertices.
         */
        /*public Vector3[] AngleWeightedNormals(){
         *
         *      if (input == null) return null;
         *
         *      Vector3[] normals = input.normals;
         *      Vector3[] vertices = input.vertices;
         *
         *      for(int i = 0; i < normals.Length; i++)
         *              normals[i] = Vector3.zero;
         *
         *      int i1,i2,i3;
         *      Vector3 e1, e2;
         *      foreach(HEFace face in heFaces){
         *
         *              HEVertex hv1 = heVertices[heHalfEdges[face.edges[0]].endVertex];
         *              HEVertex hv2 = heVertices[heHalfEdges[face.edges[1]].endVertex];
         *              HEVertex hv3 = heVertices[heHalfEdges[face.edges[2]].endVertex];
         *
         *              i1 = hv1.physicalIDs[0];
         *              i2 = hv2.physicalIDs[0];
         *              i3 = hv3.physicalIDs[0];
         *
         *              e1 = vertices[i2]-vertices[i1];
         *              e2 = vertices[i3]-vertices[i1];
         *              foreach(int pi in hv1.physicalIDs)
         *                      normals[pi] += Vector3.Cross(e1,e2) * Mathf.Acos(Vector3.Dot(e1.normalized,e2.normalized));
         *
         *              e1 = vertices[i3]-vertices[i2];
         *              e2 = vertices[i1]-vertices[i2];
         *              foreach(int pi in hv2.physicalIDs)
         *                      normals[pi] += Vector3.Cross(e1,e2) * Mathf.Acos(Vector3.Dot(e1.normalized,e2.normalized));
         *
         *              e1 = vertices[i1]-vertices[i3];
         *              e2 = vertices[i2]-vertices[i3];
         *              foreach(int pi in hv3.physicalIDs)
         *                      normals[pi] += Vector3.Cross(e1,e2) * Mathf.Acos(Vector3.Dot(e1.normalized,e2.normalized));
         *
         *      }
         *
         *      for(int i = 0; i < normals.Length; i++)
         *              normals[i].Normalize();
         *
         *      return normals;
         * }*/

        /**
         * Splits a vertex in two along a plane. Returns true if the vertex can be split, false otherwise.
         * \param vertex the vertex to split.
         * \param splitPlane plane to split the vertex at.
         * \param newVertex the newly created vertex after the split operation has been performed.
         * \param vertices new mesh vertices list after the split operation.
         * \param updatedEdges indices of half-edges that need some kind of constraint update.
         */
        public bool SplitVertex(Oni.Vertex vertex, Plane splitPlane, MeshBuffer meshBuffer, Vector4[] positions, List <int> particleIndices, out Oni.Vertex newVertex, out HashSet <int> updatedEdges, out HashSet <int> addedEdges)
        {
            // initialize return values:
            updatedEdges = new HashSet <int>();
            addedEdges   = new HashSet <int>();
            newVertex    = new Oni.Vertex();

            // initialize face lists for each side of the split plane.
            List <Oni.Face> side1Faces = new List <Oni.Face>();
            List <Oni.Face> side2Faces = new List <Oni.Face>();
            HashSet <int>   side2Edges = new HashSet <int>();

            // classify adjacent faces depending on which side of the cut plane they reside in:
            foreach (Oni.Face face in GetNeighbourFacesEnumerator(vertex))
            {
                Oni.HalfEdge e1 = heHalfEdges[face.halfEdge];
                Oni.HalfEdge e2 = heHalfEdges[e1.nextHalfEdge];
                Oni.HalfEdge e3 = heHalfEdges[e2.nextHalfEdge];

                // Skip this face if it doesnt contain the splitted vertex.
                // This can happen because edge pair links are not updated, and so a vertex in the cut stil "sees"
                // the faces at the other side like neighbour faces.
                if (e1.endVertex != vertex.index && e2.endVertex != vertex.index && e3.endVertex != vertex.index)
                {
                    continue;
                }

                // Average positions to get the center of the face:
                Vector3 faceCenter = (positions[particleIndices[e1.endVertex]] +
                                      positions[particleIndices[e2.endVertex]] +
                                      positions[particleIndices[e3.endVertex]]) / 3.0f;

                if (splitPlane.GetSide(faceCenter))
                {
                    side1Faces.Add(face);
                }
                else
                {
                    side2Faces.Add(face);
                    side2Edges.Add(e1.index);
                    side2Edges.Add(e2.index);
                    side2Edges.Add(e3.index);
                }
            }

            // If the vertex cant be split, return false.
            if (side1Faces.Count == 0 || side2Faces.Count == 0)
            {
                return(false);
            }

            // create a new vertex:
            newVertex = new Oni.Vertex(vertex.position, heVertices.Count, vertex.halfEdge);

            // add a new vertex to the mesh too, if needed.
            if (meshBuffer != null)
            {
                visualVertexBuffer.Add(new List <int>()
                {
                    meshBuffer.vertexCount
                });
                meshBuffer.AddVertex(visualVertexBuffer[vertex.index][0]);
            }

            // rearrange edges at side 1:
            foreach (Oni.Face face in side1Faces)
            {
                // find half edges that start or end at the split vertex:
                int[]        faceEdges = GetFaceEdges(face);
                Oni.HalfEdge edgeIn    = heHalfEdges[Array.Find <int>(faceEdges, e => heHalfEdges[e].endVertex == vertex.index)];
                Oni.HalfEdge edgeOut   = heHalfEdges[Array.Find <int>(faceEdges, e => this.GetHalfEdgeStartVertex(heHalfEdges[e]) == vertex.index)];

                // Edges whose pair is on the other side of the cut and share the same vertices, will spawn a new constraint.
                if (side2Edges.Contains(edgeIn.pair) && GetHalfEdgeStartVertex(edgeIn) == heHalfEdges[edgeIn.pair].endVertex)
                {
                    addedEdges.Add(Mathf.Max(edgeIn.index, edgeIn.pair));
                }

                if (side2Edges.Contains(edgeOut.pair) && GetHalfEdgeStartVertex(heHalfEdges[edgeOut.pair]) == edgeOut.endVertex)
                {
                    addedEdges.Add(Mathf.Max(edgeOut.index, edgeOut.pair));
                }

                // Constraints for these edges should be updated. (There's no guarantee the constraint exists!).
                updatedEdges.Add(edgeIn.index);
                updatedEdges.Add(edgeIn.pair);
                updatedEdges.Add(edgeOut.index);
                updatedEdges.Add(edgeOut.pair);

                // stitch in half edge to new vertex
                edgeIn.endVertex   = newVertex.index;
                newVertex.halfEdge = edgeOut.index;

                heHalfEdges[edgeIn.index]  = edgeIn;
                heHalfEdges[edgeOut.index] = edgeOut;

                // update mesh triangle buffer to point at new vertex where needed:
                if (meshBuffer != null)
                {
                    if (meshBuffer.triangles[face.index * 3] == visualVertexBuffer[vertex.index][0])
                    {
                        meshBuffer.triangles[face.index * 3] = meshBuffer.vertexCount - 1;
                    }
                    if (meshBuffer.triangles[face.index * 3 + 1] == visualVertexBuffer[vertex.index][0])
                    {
                        meshBuffer.triangles[face.index * 3 + 1] = meshBuffer.vertexCount - 1;
                    }
                    if (meshBuffer.triangles[face.index * 3 + 2] == visualVertexBuffer[vertex.index][0])
                    {
                        meshBuffer.triangles[face.index * 3 + 2] = meshBuffer.vertexCount - 1;
                    }
                }
            }

            // Add the nex vertex to the half-edge.
            heVertices.Add(newVertex);

            meshInfo.closed = false;

            return(true);
        }