Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MeshSplitController Gizmos don't account for mesh rotation #8

Open
STARasGAMES opened this issue May 29, 2022 · 3 comments
Open

MeshSplitController Gizmos don't account for mesh rotation #8

STARasGAMES opened this issue May 29, 2022 · 3 comments

Comments

@STARasGAMES
Copy link

Here is how it looks
image

Transform handle is in pivot local position
image

Also, Gizmos don't account for selected split axes
image

@STARasGAMES
Copy link
Author

I changed the way cubes are drawn.
Now they properly preview how the mesh will be split by the tool, with the scale and rotation applied.
However, it doesn't work when only one axis is selected.

image

Also, this script accounts for cases when the root object has MeshCollider, and in parameters GenerateColliders is set to true.

/* https://github.com/artnas/Unity-Plane-Mesh-Splitter */
/* https://github.com/artnas/Unity-Plane-Mesh-Splitter/issues/8 */

using System;
using System.Collections.Generic;
using UnityEngine;

namespace MeshSplit
{
    public class MeshSplitController : MonoBehaviour
    {
        public bool AutoSplitAtAwake;
        public MeshSplitParameters Parameters;
        public bool DrawGridGizmosWhenSelected = false;

        private Mesh _baseMesh;
        private MeshRenderer _baseRenderer;

        // generated children are kept here, so the script knows what to delete on Split() or Clear()
        [HideInInspector]
        [SerializeField]
        private List<GameObject> _children;

        private void Awake()
        {
            if (AutoSplitAtAwake)
            {
                Split();
            }
        }

        public void Split()
        {
            DestroyChildren();

            if (GetUsedAxisCount() < 1)
            {
                throw new Exception("You have to choose at least 1 axis.");
            }

            var meshFilter = GetComponent<MeshFilter>();
            if (meshFilter)
            {
                _baseMesh = meshFilter.sharedMesh;
            }
            else
            {
                throw new Exception("MeshFilter component is required.");
            }

            _baseRenderer = GetComponent<MeshRenderer>();
            if (_baseRenderer)
            {
                _baseRenderer.enabled = false;
            }

            var meshCollider = GetComponent<MeshCollider>();
            if (meshCollider && Parameters.GenerateColliders)
            {
                meshCollider.enabled = false;
            }

            var meshSplitter = new MeshSplitter(Parameters);
            var subMeshes = meshSplitter.Split(_baseMesh);

            _children = new List<GameObject>();
            foreach (var subMesh in subMeshes)
            {
                CreateChild(subMesh);
            }
        }

        private void CreateChild((Vector3Int gridPoint, Mesh mesh) subMesh)
        {
            var newGameObject = new GameObject
            {
                name = "SubMesh " + subMesh.gridPoint
            };

            newGameObject.transform.SetParent(transform, false);
            if (Parameters.UseParentLayer)
            {
                newGameObject.layer = gameObject.layer;
            }

            if (Parameters.UseParentStaticFlag)
            {
                newGameObject.isStatic = gameObject.isStatic;
            }

            // assign the new mesh to this submeshes mesh filter
            var newMeshFilter = newGameObject.AddComponent<MeshFilter>();
            newMeshFilter.sharedMesh = subMesh.mesh;

            var newMeshRenderer = newGameObject.AddComponent<MeshRenderer>();
            if (Parameters.UseParentMeshRendererSettings && _baseRenderer)
            {
                newMeshRenderer.sharedMaterial = _baseRenderer.sharedMaterial;
                newMeshRenderer.sortingOrder = _baseRenderer.sortingOrder;
                newMeshRenderer.sortingLayerID = _baseRenderer.sortingLayerID;
                newMeshRenderer.shadowCastingMode = _baseRenderer.shadowCastingMode;
            }

            if (Parameters.GenerateColliders)
            {
                var meshCollider = newGameObject.AddComponent<MeshCollider>();
                meshCollider.convex = Parameters.UseConvexColliders;
                meshCollider.sharedMesh = subMesh.mesh;
            }

            _children.Add(newGameObject);
        }

        private int GetUsedAxisCount()
        {
            return (Parameters.SplitAxisX ? 1 : 0) + (Parameters.SplitAxisY ? 1 : 0) + (Parameters.SplitAxisZ ? 1 : 0);
        }

        public void Clear()
        {
            DestroyChildren();

            var meshRenderer = GetComponent<MeshRenderer>();
            if (meshRenderer)
            {
                meshRenderer.enabled = true;
            }
        }

        private void DestroyChildren()
        {
            if (_children == null) return;

            foreach (var t in _children)
            {
                DestroyImmediate(t.GetComponent<MeshFilter>().sharedMesh);
                DestroyImmediate(t);
            }

            _children.Clear();
        }

        private void OnDrawGizmosSelected()
        {
            var meshFilter = GetComponent<MeshFilter>();
            var renderer = GetComponent<Renderer>();
            if (!DrawGridGizmosWhenSelected || !meshFilter || !meshFilter.sharedMesh || !renderer)
                return;

            var t = transform;
            var bounds = meshFilter.sharedMesh.bounds;

            var xSize = Parameters.SplitAxisX ? Mathf.Ceil(bounds.extents.x) : 0 + Parameters.GridSize / 2f;
            var ySize = Parameters.SplitAxisY ? Mathf.Ceil(bounds.extents.y) : 0 + Parameters.GridSize /2f;
            var zSize = Parameters.SplitAxisZ ? Mathf.Ceil(bounds.extents.z) : 0 + Parameters.GridSize/2f;

            var center = bounds.center;

            Gizmos.color = new Color(1, 1, 1, 0.3f);

            // X aligned lines
            for (var y = -ySize; y <= ySize; y += Parameters.GridSize)
            {
                for (var z = -zSize; z <= zSize; z += Parameters.GridSize)
                {
                    var start = t.TransformPoint(center + new Vector3(-xSize, y, z));
                    var end = t.TransformPoint(center + new Vector3(xSize, y, z));
                    Gizmos.DrawLine(start, end);
                }
            }

            // Y aligned lines
            for (var x = -xSize; x <= xSize; x += Parameters.GridSize)
            {
                for (var z = -zSize; z <= zSize; z += Parameters.GridSize)
                {
                    var start = t.TransformPoint(center + new Vector3(x, -ySize, z));
                    var end = t.TransformPoint(center + new Vector3(x, ySize, z));
                    Gizmos.DrawLine(start, end);
                }
            }
            
            // Z aligned lines
            for (var y = -ySize; y <= ySize + 1; y += Parameters.GridSize)
            {
                for (var x = -xSize; x <= xSize + 1; x += Parameters.GridSize)
                {
                    var start = t.TransformPoint(center + new Vector3(x, y, -zSize));
                    var end = t.TransformPoint(center + new Vector3(x, y, zSize));
                    Gizmos.DrawLine(start, end);
                }
            }
        }
    }
}

@artnas
Copy link
Owner

artnas commented May 29, 2022

Hey. This is very cool, want to make a pull request?

However, it doesn't work when only one axis is selected.

I'll take a look at that

@STARasGAMES
Copy link
Author

Hey. This is very cool, want to make a pull request?

For this, I need to fix a bunch of issues :)

  1. There should be two different modes for setting grid size: Local and Global. For now, the plugin splits mesh in its local space, but draws gizmos as if it splits mesh in global space. My version partially fixes this issue, but there is more...
  2. I don't like the idea of manually setting GridSize. Instead, there should be Vector3Int which indicates how many splits mesh needs in its local space. This way problem 1 vanishes automatically and there is no need in Parameters.SplitAxis[X,Y,Z].
    Also, it makes more sense to do this way, because using GridSize may produce uneven pieces. For example, a mesh has bounds of 100x100x100, and GridSize is set to 16. Splitting will produce 4x4x4 meshes on the edges. Kinda cringe:)
  3. Need to modify mesh splitting algorithm to work properly with the approach from 2.
  4. Setting GridSize is easy and convenient, it's just a slider with instant feedback in Gizmos. Approach with Vector3Int requires writing a custom editor that will simplify the setup process.
  5. Another way is to make GridSize a Vector3 instead of float.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants