Search code examples
c#unity-game-enginemeshraycastingtriangle

Removing Triangles of mesh having Cloth component


I have implemented the remove triangle for removing selected triangles using raycast in unity. My implementation works fine with mesh in having no components of cloth but when I am adding the cloth component, i am still able to remove the triangles but there is an issue. It removes the triangles and when I stop the game and re-run it, it shows me the result properly and the removal of triangles are still visible unless I restart the unity.

I have shared several screenshots, from the beginning till the end step by step along with the code.

1:Before running the scene

2:Removing the triangles of the mesh having cloth component using raycast

3:Stoped the scene

4:Re-run the scene and we can see the result of separation of plane after triangles removed vertically

My goal here is to see result during run-time. I am confused what should I do or what is wrong in my code. I will appreciate any guidance. Thank you in Advance.

using System;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.Numerics;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
using Vector4 = UnityEngine.Vector4;




public  class RemoveTriangle : MonoBehaviour
{
   // [Header("Game Object")][Tooltip("The game object that will be removed its triangles")]
    //public GameObject spherePrefab;
    // Better to reference those already in the Inspector
    [Header("Mesh Files to Load")]
   /* [SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private Obi.ObiBlueprintFilterMask meshFilter;
    [SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private Obi.ObiParticleRenderer meshRenderer;
    [SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private SkinnedMeshRenderer meshCollider;*/
    //[SerializeField] [Range(1.0f, 3.0f)] public float raycastSize = 1.0f;
    [Header("Origin and Target objects")]
    [Tooltip("Drag and drop the origin and target objects")]public Transform SelectOrigin;
    [Tooltip("Drag and drop the origin and target objects")] public  SkinnedMeshRenderer skinnedMeshRenderer;
    [Header("Raycast Distance")][Tooltip("The distance of the raycast")]
    [SerializeField][Range(0.1f,20.0f)]public float MaxDistance = 10f;

    public Mesh mesh;
    
   
    public bool useTethres;

    private void Start()
    {
        mesh = skinnedMeshRenderer.sharedMesh;
        

    }

    private void Update()
    {
        
        DeleteTriangle();
        

    }


    void DeleteTriangle()
    {//raycast from mouse position
        Mesh newMesh = new Mesh();
        
        
        if (Input.GetKey(KeyCode.C))
        {//raycast from mouse position
            Ray ray = new Ray(SelectOrigin.position, SelectOrigin.forward);
            RaycastHit hit;

           if(Physics.Raycast(ray, out hit, MaxDistance))
            {//if raycast hits a triangle
                Debug.DrawRay(SelectOrigin.position,
                            skinnedMeshRenderer.transform.forward - SelectOrigin.position, 
                             Color.red);
                Debug.Log("Triangle Removed at: " + hit.point + "/" + hit.triangleIndex + "/" + hit.normal);
                
                int index = hit.triangleIndex * 3;
                
                newMesh.vertices = mesh.vertices;
                newMesh.uv = mesh.uv;
                newMesh.tangents = mesh.tangents;
                newMesh.normals = mesh.normals;
                int[] triangles =mesh.triangles;
                
              
                
                int vertIndex_1 = triangles[hit.triangleIndex * 3 + 0];
                int vertIndex_2 = triangles[hit.triangleIndex * 3 + 1];
                int vertIndex_3 = triangles[hit.triangleIndex * 3 + 2];
              
                
                // Get the vertices for this triangle
                var vert_1 = newMesh.vertices[vertIndex_1];
                var vert_2 = newMesh.vertices[vertIndex_2];
                var vert_3 = newMesh.vertices[vertIndex_3];

              
                // Get the uv for this triangle
                var uv_1 = newMesh.uv[vertIndex_1];
                var uv_2 = newMesh.uv[vertIndex_2];
                var uv_3 = newMesh.uv[vertIndex_3];

                //Get the Normals for this triangle
                var normal_1 = mesh.normals[vertIndex_1];
                var normal_2 = mesh.normals[vertIndex_2];
                var normal_3 = mesh.normals[vertIndex_3];

                //Get Tangents for this triangle
                Vector4 tangent_1 = mesh.tangents[vertIndex_1];
                Vector4 tangent_2 = mesh.tangents[vertIndex_2];
                Vector4 tangent_3 = mesh.tangents[vertIndex_3];




                // Get the positions for the vertices
                var vertPos_1 = newMesh.vertices[vertIndex_1];
                var vertPos_2 = newMesh.vertices[vertIndex_2];
                var vertPos_3 = newMesh.vertices[vertIndex_3];

                

                // Now for all three vertices we first check if any other triangle if using it
                // by simply count how often the indices are used in the triangles list
                var verticesOccur_1 = 0;
                var verticesOccur_2 = 0;
                var verticesOccur_3 = 0;
                
                //for all three vertices of cloth mesh check if any other triangle is using it by simply count how often the indices are used in the triangles list
                


                for (var i = 0; i < triangles.Length; i++)
                {
                    if (triangles[i] == vertIndex_1)
                        verticesOccur_1++;
                    if (triangles[i] == vertIndex_2)
                        verticesOccur_2++;
                    if (triangles[i] == vertIndex_3)
                        verticesOccur_3++;
                }//end for
                // Remove the vertices
                if (verticesOccur_1 == 1)
                    newMesh.vertices[vertIndex_1] = Vector3.zero;
                if (verticesOccur_2 == 1)
                    newMesh.vertices[vertIndex_2] = Vector3.zero;
                if (verticesOccur_3 == 1)
                    newMesh.vertices[vertIndex_3] = Vector3.zero;

                // Remove the uv
                if (verticesOccur_1 == 1)
                    newMesh.uv[vertIndex_1] = Vector2.zero;
                if (verticesOccur_2 == 1)
                    newMesh.uv[vertIndex_2] = Vector2.zero;
                if (verticesOccur_3 == 1)
                    newMesh.uv[vertIndex_3] = Vector2.zero;

                // Remove the normals
                if (verticesOccur_1 == 1)
                    mesh.normals[vertIndex_1] = Vector3.zero;
                if (verticesOccur_2 == 1)
                    mesh.normals[vertIndex_2] = Vector3.zero;
                if (verticesOccur_3 == 1)
                    mesh.normals[vertIndex_3] = Vector3.zero;

                // Remove the tangents
                if (verticesOccur_1 == 1)
                    mesh.tangents[vertIndex_1] = Vector4.zero;
                if (verticesOccur_2 == 1)
                    mesh.tangents[vertIndex_2] = Vector4.zero;
                if (verticesOccur_3 == 1)
                    mesh.tangents[vertIndex_3] = Vector4.zero;
                
                // Find the intersecting triangles by checking if the ray intersects with their vertices
                //var intersectingTriangles = new List<int>();
                for (int i = 0; i < triangles.Length; i += 3)
                {
                    if (triangles[i] == triangles[index] && triangles[i + 1] == triangles[index + 1] && triangles[i + 2] == triangles[index + 2])
                    {
                        triangles[i] = triangles[triangles.Length - 3];
                        triangles[i + 1] = triangles[triangles.Length - 2];
                        triangles[i + 2] = triangles[triangles.Length - 1];
                    }
                }

                newMesh.triangles= triangles;
                skinnedMeshRenderer.sharedMesh = newMesh;

                //update the mesh with the new vertices, uv, normals and tangents
                mesh.vertices = newMesh.vertices;
                mesh.uv = newMesh.uv;
                mesh.tangents = newMesh.tangents;
                mesh.normals =newMesh.normals;
                //update the tirangles
                //newMesh.triangles = triangles;
                 //update the mesh with the new triangles
                mesh.triangles = newMesh.triangles;
                //update the mesh with the new vertices, uv, normals and tangents
                
 
            
            }//end of if
            else
            {

                Debug.Log("No Triangle to remove" + hit.point);
            }//end of if hit.triangleIndex
        }//end of remove triangle
    }//end of class
}//end of class

Solution

  • Because you are editing the shared mesh, maybe this is not what you expected:

    mesh = skinnedMeshRenderer.sharedMesh;
    ......
    mesh.vertices = newMesh.vertices;
    

    The Plane mesh is a built-in mesh, so it is reverted when Unity is relaunched. Because of your code, this error does not occur every time, but without the cloth component, it can occur sometimes.

    You can clone the mesh on start:

    private void Start()
    {
        mesh = Instantiate(skinnedMeshRenderer.sharedMesh);
        skinnedMeshRenderer.sharedMesh = mesh;
    }
    

    Then you don't need newMesh anymore, you can directly edit mesh now.