星鸿阁

 找回密码
 立即注册
搜索
热搜: 活动 交友 动画
查看: 904|回复: 0

MouseSlice

[复制链接]

2249

主题

2759

帖子

9603

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9603
发表于 2022-7-26 00:39:09 | 显示全部楼层 |阅读模式
  1. using System.Collections.Generic;
  2. using UnityEngine;

  3. public class MouseSlice : MonoBehaviour {

  4.     public GameObject plane;
  5.     public Transform ObjectContainer;

  6.     // How far away from the slice do we separate resulting objects
  7.     public float separation;

  8.     // Do we draw a plane object associated with the slice
  9.     private Plane slicePlane = new Plane();
  10.     public bool drawPlane;
  11.    
  12.     // Reference to the line renderer
  13.     public ScreenLineRenderer lineRenderer;

  14.     private MeshCutter meshCutter;
  15.     private TempMesh biggerMesh, smallerMesh;

  16.     #region Utility Functions

  17.     void DrawPlane(Vector3 start, Vector3 end, Vector3 normalVec)
  18.     {
  19.         Quaternion rotate = Quaternion.FromToRotation(Vector3.up, normalVec);

  20.         plane.transform.localRotation = rotate;
  21.         plane.transform.position = (end + start) / 2;
  22.         plane.SetActive(true);
  23.     }

  24.     #endregion

  25.     // Use this for initialization
  26.     void Start () {
  27.         // Initialize a somewhat big array so that it doesn't resize
  28.         meshCutter = new MeshCutter(256);
  29.         }

  30.     private void OnEnable()
  31.     {
  32.         lineRenderer.OnLineDrawn += OnLineDrawn;
  33.     }

  34.     private void OnDisable()
  35.     {
  36.         lineRenderer.OnLineDrawn -= OnLineDrawn;
  37.     }

  38.     private void OnLineDrawn(Vector3 start, Vector3 end, Vector3 depth)
  39.     {
  40.         var planeTangent = (end - start).normalized;

  41.         // if we didn't drag, we set tangent to be on x
  42.         if (planeTangent == Vector3.zero)
  43.             planeTangent = Vector3.right;

  44.         var normalVec = Vector3.Cross(depth, planeTangent);

  45.         if (drawPlane) DrawPlane(start, end, normalVec);

  46.         SliceObjects(start, normalVec);
  47.     }
  48.    

  49.     void SliceObjects(Vector3 point, Vector3 normal)
  50.     {
  51.         var toSlice = GameObject.FindGameObjectsWithTag("Sliceable");

  52.         // Put results in positive and negative array so that we separate all meshes if there was a cut made
  53.         List<Transform> positive = new List<Transform>(),
  54.             negative = new List<Transform>();

  55.         GameObject obj;
  56.         bool slicedAny = false;
  57.         for (int i = 0; i < toSlice.Length; ++i)
  58.         {
  59.             obj = toSlice[i];
  60.             // We multiply by the inverse transpose of the worldToLocal Matrix, a.k.a the transpose of the localToWorld Matrix
  61.             // Since this is how normal are transformed
  62.             var transformedNormal = ((Vector3)(obj.transform.localToWorldMatrix.transpose * normal)).normalized;

  63.             //Convert plane in object's local frame
  64.             slicePlane.SetNormalAndPosition(
  65.                 transformedNormal,
  66.                 obj.transform.InverseTransformPoint(point));

  67.             slicedAny = SliceObject(ref slicePlane, obj, positive, negative) || slicedAny;
  68.         }

  69.         // Separate meshes if a slice was made
  70.         if (slicedAny)
  71.             SeparateMeshes(positive, negative, normal);
  72.     }

  73.     bool SliceObject(ref Plane slicePlane, GameObject obj, List<Transform> positiveObjects, List<Transform> negativeObjects)
  74.     {
  75.         var mesh = obj.GetComponent<MeshFilter>().mesh;

  76.         if (!meshCutter.SliceMesh(mesh, ref slicePlane))
  77.         {
  78.             // Put object in the respective list
  79.             if (slicePlane.GetDistanceToPoint(meshCutter.GetFirstVertex()) >= 0)
  80.                 positiveObjects.Add(obj.transform);
  81.             else
  82.                 negativeObjects.Add(obj.transform);

  83.             return false;
  84.         }

  85.         // TODO: Update center of mass

  86.         // Silly condition that labels which mesh is bigger to keep the bigger mesh in the original gameobject
  87.         bool posBigger = meshCutter.PositiveMesh.surfacearea > meshCutter.NegativeMesh.surfacearea;
  88.         if (posBigger)
  89.         {
  90.             biggerMesh = meshCutter.PositiveMesh;
  91.             smallerMesh = meshCutter.NegativeMesh;
  92.         }
  93.         else
  94.         {
  95.             biggerMesh = meshCutter.NegativeMesh;
  96.             smallerMesh = meshCutter.PositiveMesh;
  97.         }

  98.         // Create new Sliced object with the other mesh
  99.         GameObject newObject = Instantiate(obj, ObjectContainer);
  100.         newObject.transform.SetPositionAndRotation(obj.transform.position, obj.transform.rotation);
  101.         var newObjMesh = newObject.GetComponent<MeshFilter>().mesh;

  102.         // Put the bigger mesh in the original object
  103.         // TODO: Enable collider generation (either the exact mesh or compute smallest enclosing sphere)
  104.         ReplaceMesh(mesh, biggerMesh);
  105.         ReplaceMesh(newObjMesh, smallerMesh);

  106.         (posBigger ? positiveObjects : negativeObjects).Add(obj.transform);
  107.         (posBigger ? negativeObjects : positiveObjects).Add(newObject.transform);

  108.         return true;
  109.     }


  110.     /// <summary>
  111.     /// Replace the mesh with tempMesh.
  112.     /// </summary>
  113.     void ReplaceMesh(Mesh mesh, TempMesh tempMesh, MeshCollider collider = null)
  114.     {
  115.         mesh.Clear();
  116.         mesh.SetVertices(tempMesh.vertices);
  117.         mesh.SetTriangles(tempMesh.triangles, 0);
  118.         mesh.SetNormals(tempMesh.normals);
  119.         mesh.SetUVs(0, tempMesh.uvs);
  120.         
  121.         //mesh.RecalculateNormals();
  122.         mesh.RecalculateTangents();

  123.         if (collider != null && collider.enabled)
  124.         {
  125.             collider.sharedMesh = mesh;
  126.             collider.convex = true;
  127.         }
  128.     }

  129.     void SeparateMeshes(Transform posTransform, Transform negTransform, Vector3 localPlaneNormal)
  130.     {
  131.         // Bring back normal in world space
  132.         Vector3 worldNormal = ((Vector3)(posTransform.worldToLocalMatrix.transpose * localPlaneNormal)).normalized;

  133.         Vector3 separationVec = worldNormal * separation;
  134.         // Transform direction in world coordinates
  135.         posTransform.position += separationVec;
  136.         negTransform.position -= separationVec;
  137.     }

  138.     void SeparateMeshes(List<Transform> positives, List<Transform> negatives, Vector3 worldPlaneNormal)
  139.     {
  140.         int i;
  141.         var separationVector = worldPlaneNormal * separation;

  142.         for(i = 0; i <positives.Count; ++i)
  143.             positives[i].transform.position += separationVector;

  144.         for (i = 0; i < negatives.Count; ++i)
  145.             negatives[i].transform.position -= separationVector;
  146.     }
  147. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|starfluidga

GMT+8, 2024-12-21 00:59 , Processed in 0.014043 second(s), 21 queries .

Made by Liga 星鸿阁

Copyright © 2020-2048, LigaStudio.

快速回复 返回顶部 返回列表