Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 156 additions & 46 deletions EzySlice/Slicer.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
Expand All @@ -9,6 +10,33 @@ namespace EzySlice {
*/
public sealed class Slicer {

internal struct SlicedMeshDetails : IEquatable<SlicedMeshDetails>
{
public List<Vector3> crossHull;
public SlicedSubmesh[] slices;

public bool Equals(SlicedMeshDetails other)
{
throw new NotImplementedException();
}
};

internal struct MeshDetails : IEquatable<MeshDetails>
{
public bool valid;
public MeshFilter filter;
public MeshRenderer renderer;
public Material[] materials;
public Mesh mesh;
public int submeshCount;
public int crossIndex;

public bool Equals(MeshDetails other)
{
throw new NotImplementedException();
}
};

/**
* An internal class for storing internal submesh values
*/
Expand Down Expand Up @@ -66,62 +94,63 @@ public bool isValid {
* See -> Slice(Mesh, Plane) for more info
*/
public static SlicedHull Slice(GameObject obj, Plane pl, TextureRegion crossRegion, Material crossMaterial) {
MeshFilter filter = obj.GetComponent<MeshFilter>();

// cannot continue without a proper filter
if (filter == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component.");
MeshDetails md = GetMeshDetails(obj);

if (!md.valid)
{
return null;
}

MeshRenderer renderer = obj.GetComponent<MeshRenderer>();

// cannot continue without a proper renderer
if (renderer == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshRenderer Component.");

return null;

// crossIndex - we need to find the index of the material for the cross section.
// default to the end of the array
// for cases where the sliced material is null, we will append the cross section to the end
// of the submesh array, this is because the application may want to set/change the material
// after slicing has occured, so we don't assume anything
if (crossMaterial != null) {
for (int i = 0; i < md.crossIndex; i++) {
if (md.materials[i] == crossMaterial) {
md.crossIndex = i;
break;
}
}
}

Material[] materials = renderer.sharedMaterials;
return Slice(md.mesh, pl, crossRegion, md.crossIndex);
}

Mesh mesh = filter.sharedMesh;

// cannot slice a mesh that doesn't exist
if (mesh == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a Mesh that is not NULL.");
// Helper function for edgeloop functionality
public static List<Vector3> EdgeLoop(GameObject obj, Plane pl) {

MeshDetails md = GetMeshDetails(obj);

if (!md.valid)
{
return null;
}

int submeshCount = mesh.subMeshCount;

// to make things straightforward, exit without slicing if the materials and mesh
// array don't match. This shouldn't happen anyway
if (materials.Length != submeshCount) {
Debug.LogWarning("EzySlice::Slice -> Provided Material array must match the length of submeshes.");
return EdgeLoop(md.mesh, pl);
}

private static List<Vector3> EdgeLoop(Mesh sharedMesh, Plane pl) {
if (sharedMesh == null) {
return null;
}

// we need to find the index of the material for the cross section.
// default to the end of the array
int crossIndex = materials.Length;

// for cases where the sliced material is null, we will append the cross section to the end
// of the submesh array, this is because the application may want to set/change the material
// after slicing has occured, so we don't assume anything
if (crossMaterial != null) {
for (int i = 0; i < crossIndex; i++) {
if (materials[i] == crossMaterial) {
crossIndex = i;
break;
}
SlicedMeshDetails sliceDetails = SliceMesh(sharedMesh, pl);

// check if slicing actually occured
for (int i = 0; i < sliceDetails.slices.Length; i++) {
// check if at least one of the submeshes was sliced. If so, stop checking
// because we need to go through the generation step
if (sliceDetails.slices[i] != null && sliceDetails.slices[i].isValid) {
return sliceDetails.crossHull;
}
}

return Slice(mesh, pl, crossRegion, crossIndex);
// no slicing occured, just return null to signify
return null;
}

/**
Expand All @@ -137,6 +166,27 @@ public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region,
return null;
}

SlicedMeshDetails sliceDetails = SliceMesh(sharedMesh, pl);

// check if slicing actually occured
for (int i = 0; i < sliceDetails.slices.Length; i++) {
// check if at least one of the submeshes was sliced. If so, stop checking
// because we need to go through the generation step
if (sliceDetails.slices[i] != null && sliceDetails.slices[i].isValid) {
return CreateFrom(sliceDetails.slices, CreateFrom(sliceDetails.crossHull, pl.normal, region), crossIndex);
}
}

// no slicing occured, just return null to signify
return null;
}

/**
* Slice the mesh, and return sliced mesh details
**/
private static SlicedMeshDetails SliceMesh(Mesh sharedMesh, Plane pl) {

SlicedMeshDetails details = new SlicedMeshDetails();
Vector3[] verts = sharedMesh.vertices;
Vector2[] uv = sharedMesh.uv;
Vector3[] norm = sharedMesh.normals;
Expand Down Expand Up @@ -222,17 +272,77 @@ public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region,
slices[submesh] = mesh;
}

// check if slicing actually occured
for (int i = 0; i < slices.Length; i++) {
// check if at least one of the submeshes was sliced. If so, stop checking
// because we need to go through the generation step
if (slices[i] != null && slices[i].isValid) {
return CreateFrom(slices, CreateFrom(crossHull, pl.normal, region), crossIndex);
}
details.slices = slices;
details.crossHull = crossHull;
return details;
}

private static bool IsGameObjectOk(GameObject obj)
{
MeshFilter filter = obj.GetComponent<MeshFilter>();

// cannot continue without a proper filter
if (filter == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component.");

return false;
}

// no slicing occured, just return null to signify
return null;
MeshRenderer renderer = obj.GetComponent<MeshRenderer>();

// cannot continue without a proper renderer
if (renderer == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshRenderer Component.");

return false;
}

Material[] materials = renderer.sharedMaterials;

Mesh mesh = filter.sharedMesh;

// cannot slice a mesh that doesn't exist
if (mesh == null) {
Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a Mesh that is not NULL.");

return false;
}

int submeshCount = mesh.subMeshCount;

// to make things straightforward, exit without slicing if the materials and mesh
// array don't match. This shouldn't happen anyway
if (materials.Length != submeshCount) {
Debug.LogWarning("EzySlice::Slice -> Provided Material array must match the length of submeshes.");

return false;
}

return true;
}

/**
* Return mesh details or null if the supplied gameobject cannot be processed.
*/
private static MeshDetails GetMeshDetails(GameObject obj)
{
MeshDetails md = new MeshDetails();

if (!IsGameObjectOk(obj))
{
md.valid = false;
return md;
}

md.filter = obj.GetComponent<MeshFilter>();
md.renderer = obj.GetComponent<MeshRenderer>();
md.materials = md.renderer.sharedMaterials;
md.mesh = md.filter.sharedMesh;
md.submeshCount = md.mesh.subMeshCount;
md.crossIndex = md.materials.Length;
md.valid = true;

return md;
}

/**
Expand Down
8 changes: 5 additions & 3 deletions EzySlice/SlicerExtensions.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EzySlice {
/**
* Define Extension methods for easy access to slicer functionality
*/
public static class SlicerExtensions {

/**
* SlicedHull Return functions and appropriate overrides!
*/
Expand Down Expand Up @@ -44,11 +44,12 @@ public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 positio
return SliceInstantiate(obj, position, direction, null);
}

public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMat) {
public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMat) {
return SliceInstantiate(obj, position, direction, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f), crossSectionMat);
}

public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, TextureRegion cuttingRegion, Material crossSectionMaterial = null) {

EzySlice.Plane cuttingPlane = new EzySlice.Plane();

Vector3 refUp = obj.transform.InverseTransformDirection(direction);
Expand Down Expand Up @@ -82,9 +83,10 @@ public static GameObject[] SliceInstantiate(this GameObject obj, Plane pl, Textu
if (lowerHull != null) {
return new GameObject[] { lowerHull };
}

// nothing to return, so return nothing!
return null;

}
}
}