Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using UnityEditor;
- using System.Collections.Generic;
- using Sirenix.OdinInspector;
- using Sirenix.OdinInspector.Editor;
- using HoudiniEngineUnity;
- namespace Skatebirb
- {
- //public class SkateMaker : EditorWindow
- public class SkateMaker : OdinEditorWindow
- {
- #region Selection Tracker
- private HEU_HoudiniAssetRoot activeHoudiniRoot = null;
- private bool noHoudiniRoot = false;
- #endregion
- #region Group and Marker Names
- private const string RailNodeMarker = "Grind_Node";
- private const string CollisionMarker = "_collision";
- private const string RailParentName = "Generated_Rail_Nodes";
- private const string RailNodeStandalone = "Generated_Rail_Node";
- private const string RampParentName = "Generated_Ramp_Zones";
- private const string RampObjectName = "Generated_Ramp_Zone";
- private const string VertParentName = "Generated_Vert_Zones";
- private const string VertObjectName = "Generated_Vert_Zone";
- #endregion
- #region Rail Binding Paramters
- private const float RailDotBreakPoint = 0.174f; // Cos of 80deg
- private const float RailDotDestroyPoint = -0.174f; // Cos of 100deg
- #endregion
- #region Vert Parameters
- private const float VertThickness = 1.5f;
- private const float VertHeightFromRail = 7f;
- private const float VertPlaneAdjustment = -0.3f;
- #endregion
- #region Ramp Paramters
- private const float RampHeightCutoff = 4f;
- private const float VertHeightCutoff = 10f;
- #endregion
- #region Component Trackers
- // Each entry in this list could be a multi-segment rail, it does NOT track every node in every rail
- private List<GrindableRail> activeRailOrigins = new List<GrindableRail>();
- private List<VertZone> activeVertZones = new List<VertZone>();
- private List<RampZone> activeRampZones = new List<RampZone>();
- #endregion
- #region Menu Handling
- [MenuItem("Tools/Skate Maker")]
- public static void ShowWindow()
- {
- GetWindow<SkateMaker>().Show();
- }
- protected override void OnGUI()
- {
- // First, try to establish a Houdini root (which also enables/disables tooling related)
- activeHoudiniRoot = null;
- if (Selection.activeTransform != null)
- {
- HEU_HoudiniAssetRoot newRoot = Selection.activeTransform.gameObject.GetComponent<HEU_HoudiniAssetRoot>();
- if (newRoot != null && newRoot != activeHoudiniRoot)
- {
- // If we click between Houdini objects, clear any temp data out
- activeRailOrigins.Clear();
- }
- activeHoudiniRoot = newRoot;
- }
- noHoudiniRoot = (activeHoudiniRoot == null) ? true : false;
- // Once we have a root, try to establish a list of any contained rail segments (if we don't already have one)
- if (activeHoudiniRoot != null && activeRailOrigins.Count == 0)
- {
- Transform railParent = activeHoudiniRoot.transform.Find(RailParentName);
- if (railParent != null)
- {
- GrindableRail[] foundRails = railParent.GetComponentsInChildren<GrindableRail>();
- for (int index = 0; index < foundRails.Length; index++)
- {
- GrindableRail foundRail = foundRails[index];
- // We're looking for rail origins, which means we need the start of each group of rails
- while (foundRail.prevGrindable != null)
- {
- foundRail = foundRail.prevGrindable;
- if (foundRail == foundRails[index]) { break; } // (not gonna catch me, loop boi! get outta here)
- }
- // If we haven't found this rail origin yet, add it!
- if (!activeRailOrigins.Contains(foundRail)) { activeRailOrigins.Add(foundRail); }
- }
- }
- }
- base.OnGUI();
- }
- [FoldoutGroup("Houdini", expanded: true)]
- [FoldoutGroup("Houdini/General Tools", expanded: true)]
- [ButtonGroup("Houdini/General Tools/Buttons")]
- [Button("Enable Physics", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_EnablePhysics()
- {
- Houdini_EnablePhysics();
- }
- [FoldoutGroup("Houdini/Ramp Processors", expanded: true)]
- [ButtonGroup("Houdini/Ramp Processors/Bulk Operations")]
- [Button("Clean", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_Clean()
- {
- Houdini_ClearExistingRails();
- Houdini_HideRailMarkers();
- Houdini_ClearExistingRamps();
- Houdini_ClearExistingVerts();
- }
- [ButtonGroup("Houdini/Ramp Processors/Bulk Operations")]
- [Button("Ultra Rampify 5000", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_FullRampProcessing()
- {
- Houdini_EnablePhysics();
- Houdini_ProcessRampRails();
- Houdini_ProcessRamps();
- Houdini_ProcessVerts();
- }
- [TitleGroup("Houdini/Ramp Processors/Separate Operations")]
- [ButtonGroup("Houdini/Ramp Processors/Separate Operations/Buttons")]
- [Button("Generate Rails", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_GenerateRails()
- {
- Houdini_ProcessRampRails();
- }
- [ButtonGroup("Houdini/Ramp Processors/Separate Operations/Buttons")]
- [Button("Add Ramp Zones", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_AddRampZones()
- {
- Houdini_ProcessRamps();
- }
- [ButtonGroup("Houdini/Ramp Processors/Separate Operations/Buttons")]
- [Button("Add Vert Zones", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_AddVertZones()
- {
- Houdini_ProcessVerts();
- }
- [FoldoutGroup("Houdini/In-Order Node Rails", expanded: true)]
- [ButtonGroup("Houdini/In-Order Node Rails/Buttons")]
- [Button("Clean", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_CleanInOrderRails()
- {
- Houdini_ClearExistingRails();
- Houdini_HideRailMarkers();
- }
- [ButtonGroup("Houdini/In-Order Node Rails/Buttons")]
- [Button("Link In Node Order", ButtonSizes.Large)]
- [DisableIf("noHoudiniRoot")]
- public void Button_Houdini_LinkRailsByOrder()
- {
- Houdini_MakeRailsInNodeOrder();
- }
- #endregion
- #region Houdini General Operations
- void Houdini_EnablePhysics()
- {
- Houdini_EnablePhysics_Recurisve(activeHoudiniRoot.gameObject);
- }
- void Houdini_EnablePhysics_Recurisve(GameObject curObj)
- {
- // Look for any collision-flagged objects...
- if (curObj.name.Contains(CollisionMarker))
- {
- // ... and enable any colliders we find, easy!
- MeshCollider tempCollider = curObj.GetComponent<MeshCollider>();
- if (tempCollider != null)
- {
- tempCollider.enabled = true;
- }
- }
- // Then handle the recursion
- foreach (Transform childTrans in curObj.transform)
- {
- Houdini_EnablePhysics_Recurisve(childTrans.gameObject);
- }
- }
- void Houdini_HideRailMarkers()
- {
- Houdini_HideRailMarkers_Recursive(activeHoudiniRoot.gameObject);
- }
- void Houdini_HideRailMarkers_Recursive(GameObject curObj)
- {
- bool shouldHide = false;
- // First we run through, processing nodes and flagging some for hiding
- if (curObj.name.Contains(RailNodeMarker))
- {
- // We're looking for the rail nodes with meshes, those are the ones that are sitting at the right position
- MeshRenderer tempRenderer = curObj.GetComponent<MeshRenderer>();
- if (tempRenderer != null && tempRenderer.enabled) // (they also need to be enabled, if they're hidden that means they're the instance originals sitting off in another folder)
- {
- // This is one of the nodes we're replacing with something else, so, no reason for it to be visible
- shouldHide = true;
- }
- // If it's an empty object, that means it's one of the empty parents to the rail node instances we also want to ditch
- else if (tempRenderer == null) { shouldHide = true; }
- }
- // Then handle the recursion (BEFORE we delete anything)
- foreach (Transform childTrans in curObj.transform)
- {
- Houdini_HideRailMarkers_Recursive(childTrans.gameObject);
- }
- // Finally, hide if we should hide
- if (shouldHide && curObj != null)
- {
- curObj.SetActive(false);
- }
- }
- #endregion
- #region Houdini Rail Addition
- void Houdini_ClearExistingRails()
- {
- // Clear our rail tracking
- activeRailOrigins.Clear();
- // Also, clear out any prior changes in the Houdini hierarchy
- for (int index = 0; index < activeHoudiniRoot.transform.childCount; index++)
- {
- Transform childTrans = activeHoudiniRoot.transform.GetChild(index);
- // Clear out any network of rails we may have previously created
- if (childTrans.name == RailParentName)
- {
- while (childTrans.childCount > 0)
- {
- Transform tempTrans = childTrans.GetChild(0);
- DestroyImmediate(tempTrans.gameObject);
- }
- DestroyImmediate(childTrans.gameObject);
- index--; // (since we just destroyed a child)
- continue;
- }
- }
- }
- /// <summary>
- /// This is used by most rail processing, to go through and find the rail nodes to then link or otherwise operate on
- /// </summary>
- /// <param name="curObj">the active houdini root object</param>
- /// <param name="inProcessRails">the list to add found rail nodes to</param>
- /// <param name="activeRailRoot">the node to parent created rail nodes to</param>
- void Houdini_ProcessRails_Recursive(GameObject curObj, List<SortableGrindableRail> inProcessRails, Transform activeRailRoot)
- {
- bool shouldHide = false;
- // First we run through, processing nodes and flagging some for hiding
- if (curObj.name.Contains(RailNodeMarker))
- {
- // We're looking for the rail nodes with meshes, those are the ones that are sitting at the right position
- MeshRenderer tempRenderer = curObj.GetComponent<MeshRenderer>();
- if (tempRenderer != null && tempRenderer.enabled) // (they also need to be enabled, if they're hidden that means they're the instance originals sitting off in another folder)
- {
- // Make a clean clone of the object, that we control, that retains the pos and rot (we'll need the forward vec as a normal, later)
- GameObject newRailNode = new GameObject();
- newRailNode.name = RailNodeStandalone;
- newRailNode.transform.position = curObj.transform.position;
- newRailNode.transform.rotation = curObj.transform.rotation;
- newRailNode.transform.parent = activeRailRoot;
- // ... and set it up as a rail node
- SortableGrindableRail inProcessRail = new SortableGrindableRail();
- inProcessRail.theRail = newRailNode.AddComponent<GrindableRail>();
- // ... and extract the index
- string[] containsIndex = curObj.name.Substring(curObj.name.IndexOf(RailNodeMarker) + RailNodeMarker.Length).Split('_');
- if (containsIndex.Length > 0)
- {
- inProcessRail.index = int.Parse(containsIndex[0]);
- inProcessRail.theRail.gameObject.name += inProcessRail.index;
- }
- else { Debug.Log("Couldn't find rail index for '" + curObj.name + "', generated rail ain't gonna be great."); inProcessRail.index = 0; }
- // And track it (for later sorting)
- inProcessRails.Add(inProcessRail);
- // This is one of the nodes we're replacing with something else, so, no reason for it to be visible
- shouldHide = true;
- }
- // If it's an empty object, that means it's one of the empty parents to the rail node instances we also want to ditch
- else if (tempRenderer == null) { shouldHide = true; }
- }
- // Then handle the recursion (BEFORE we delete anything)
- foreach (Transform childTrans in curObj.transform)
- {
- Houdini_ProcessRails_Recursive(childTrans.gameObject, inProcessRails, activeRailRoot);
- }
- // Finally, hide if we should hide
- if (shouldHide && curObj != null)
- {
- curObj.SetActive(false);
- }
- }
- private class SortableGrindableRail
- {
- public GrindableRail theRail;
- public int index;
- }
- /// <summary>
- /// Processing of rails assumed to be part of ramps (ie. marking out curves, and probably not numbered in-order because ramps are weird)
- /// </summary>
- void Houdini_ProcessRampRails()
- {
- if (activeHoudiniRoot == null) { return; }
- // First, clear out any prior work done on it
- Houdini_ClearExistingRails();
- // Then set the clean object up to be rail-ified
- GameObject newRailRoot = new GameObject();
- newRailRoot.name = RailParentName;
- newRailRoot.transform.parent = activeHoudiniRoot.transform;
- newRailRoot.transform.localPosition = Vector3.zero;
- newRailRoot.transform.localRotation = Quaternion.identity;
- newRailRoot.transform.localScale = Vector3.one;
- Transform activeRailRoot = newRailRoot.transform;
- // Now, process it!
- List<SortableGrindableRail> inProcessRails = new List<SortableGrindableRail>();
- Houdini_ProcessRails_Recursive(activeHoudiniRoot.gameObject, inProcessRails, activeRailRoot);
- // Finally, we need to thread the rails together (if there are any)
- if (inProcessRails.Count > 1)
- {
- // First, we sort the rails and decide what kind of rail this is
- inProcessRails.Sort((r1, r2) => r1.index.CompareTo(r2.index));
- bool railIsLinear = (inProcessRails.Count == 2) ? true : false;
- // First node, post-sort, will be a good starting point. Should be at an end, etc.
- GrindableRail curRail = inProcessRails[0].theRail;
- Vector3 curDir = (curRail.transform.position - activeHoudiniRoot.transform.position).normalized;
- inProcessRails.RemoveAt(0);
- // Now step through the rest
- float signFlip = 1f;
- bool lastDitchReverse = false;
- while (inProcessRails.Count > 0)
- {
- int closestNextIndex = -1;
- float closestNextDot = -2f;
- for (int sortedIndex = 0; sortedIndex < inProcessRails.Count; sortedIndex++)
- {
- SortableGrindableRail sortedRail = inProcessRails[sortedIndex];
- Vector3 newDir = (sortedRail.theRail.transform.position - activeHoudiniRoot.transform.position).normalized;
- // We only link in a clockwise (or anti-clockwise as a fallback) direction
- if (Vector3.Dot(Vector3.Cross(curDir, newDir).normalized, Vector3.up) * signFlip < 0.0f) { continue; }
- // Now see if this is closer than whatever our current best option is
- float newDot = Vector3.Dot(curDir, newDir);
- if (newDot > closestNextDot)
- {
- closestNextIndex = sortedIndex;
- closestNextDot = newDot;
- }
- }
- // If we found something, link it in and continue
- if (closestNextIndex >= 0)
- {
- GrindableRail prevRail = curRail;
- curRail = inProcessRails[closestNextIndex].theRail;
- inProcessRails.RemoveAt(closestNextIndex);
- prevRail.nextGrindable = curRail;
- curRail.prevGrindable = prevRail;
- lastDitchReverse = false; // (we found one, so if we were in a last ditch reverse, we're good to keep in this direction for a while)
- continue;
- }
- // If we get this far, somehow we didn't find a candidate next-node in our current clockwise or anti-clockwise spin - so try again the other way (catches when we start in the wrong direction or have an odd-one-out last point)
- if (!lastDitchReverse) { signFlip *= -1f; lastDitchReverse = true; }
- // ... or Shit Broke, so just bail on this whole mess
- else { break; }
- }
- // Finish up by linking a (non linear) rail's tail back to its head
- GrindableRail lastRail = curRail;
- GrindableRail firstRail = lastRail;
- while (firstRail.prevGrindable != null) { firstRail = firstRail.prevGrindable; }
- if (!railIsLinear)
- {
- lastRail.nextGrindable = firstRail;
- firstRail.prevGrindable = lastRail;
- // Now, let's also hard-break any connections too severe to possibly be ground around (because those are probably loop closures we didn't actually want closed)
- GrindableRail hardBreakOtherEnd = null;
- curRail = firstRail;
- do
- {
- GrindableRail nextRail = curRail.nextGrindable;
- if (nextRail == null) { break; }
- if (curRail.prevGrindable == null) { curRail = nextRail; continue; }
- Vector3 lastRailDir = (curRail.transform.position - curRail.prevGrindable.transform.position).normalized;
- Vector3 curRailDir = (curRail.nextGrindable.transform.position - curRail.transform.position).normalized;
- // After we destroy a single connection in the loop, all bets are off for continuing to check for these, so we just have to assume there's only ever one (the loop closure point)
- if (Vector3.Dot(lastRailDir, curRailDir) < RailDotDestroyPoint)
- {
- if (hardBreakOtherEnd == null) { hardBreakOtherEnd = curRail; }
- else
- {
- // This is probably overly precise, I don't think there's ever a case where only one end could be too severe, but like... ugghhhh I'm tired
- if (curRail.nextGrindable == hardBreakOtherEnd)
- {
- curRail.nextGrindable = null;
- hardBreakOtherEnd.prevGrindable = null;
- }
- else if (curRail.prevGrindable == hardBreakOtherEnd)
- {
- curRail.prevGrindable = null;
- hardBreakOtherEnd.nextGrindable = null;
- }
- break;
- }
- }
- curRail = nextRail;
- } while (curRail != null && curRail != firstRail);
- // Now here, break the rails into separate chunks based on corner sharpness
- activeRailOrigins.Add(firstRail);
- curRail = firstRail;
- do
- {
- GrindableRail nextRail = curRail.nextGrindable;
- if (nextRail == null) { break; }
- if (curRail.prevGrindable == null) { curRail = nextRail; continue; }
- Vector3 lastRailDir = (curRail.transform.position - curRail.prevGrindable.transform.position).normalized;
- Vector3 curRailDir = (curRail.nextGrindable.transform.position - curRail.transform.position).normalized;
- // Any time we detect a sharp corner this way, we're on the "far" side of the sharp corner...
- if (Vector3.Dot(lastRailDir, curRailDir) < RailDotBreakPoint)
- {
- // ... meaning we're the new first-node in the next strip of rails (until the next sharp corner), so make a clone of ourselves to cap the prior run
- GrindableRail hardCornerEnd = Instantiate(curRail);
- hardCornerEnd.transform.parent = curRail.transform.parent;
- // Since we changed the parent, we have to re-assign the pos/rot/scale? Because it changes arbitrarily when you change parenting? Sigh.
- hardCornerEnd.transform.position = curRail.transform.position;
- hardCornerEnd.transform.rotation = curRail.transform.rotation;
- hardCornerEnd.transform.localScale = curRail.transform.localScale;
- hardCornerEnd.gameObject.name = curRail.gameObject.name + "(hard corner end)";
- hardCornerEnd.nextGrindable = null;
- hardCornerEnd.prevGrindable.nextGrindable = hardCornerEnd;
- // Also remember to snip our own link backwards
- curRail.prevGrindable = null;
- // Each time we make a new chunk, we need to make sure the new chunk gets added to the rail tracker
- if (!activeRailOrigins.Contains(curRail)) { activeRailOrigins.Add(curRail); }
- }
- curRail = nextRail;
- } while (curRail != firstRail);
- }
- else
- {
- // Put your single, solitary rail into the tracking group (so sad)
- activeRailOrigins.Add(firstRail);
- }
- // Finally, let's step through and flatten / square up our rail forwards
- Houdini_RailFlattenOrientation(activeRailOrigins);
- }
- }
- /// <summary>
- /// Simpler rail processing that simply links them together in the order they say to link them in
- /// </summary>
- void Houdini_MakeRailsInNodeOrder()
- {
- if (activeHoudiniRoot == null) { return; }
- // First, clear out any prior work done on it
- Houdini_ClearExistingRails();
- // Then set the clean object up to be rail-ified
- GameObject newRailRoot = new GameObject();
- newRailRoot.name = RailParentName;
- newRailRoot.transform.parent = activeHoudiniRoot.transform;
- newRailRoot.transform.localPosition = Vector3.zero;
- newRailRoot.transform.localRotation = Quaternion.identity;
- newRailRoot.transform.localScale = Vector3.one;
- Transform activeRailRoot = newRailRoot.transform;
- // Now, process it!
- List<SortableGrindableRail> inProcessRails = new List<SortableGrindableRail>();
- Houdini_ProcessRails_Recursive(activeHoudiniRoot.gameObject, inProcessRails, activeRailRoot);
- if (inProcessRails.Count == 0) { return; }
- // First, we sort the rails and decide what kind of rail this is
- inProcessRails.Sort((r1, r2) => r1.index.CompareTo(r2.index));
- // Now we just link the rails together in their sorted order!
- GrindableRail curRail = inProcessRails[0].theRail;
- activeRailOrigins.Add(curRail); // (it's all one rail, eyyy)
- GrindableRail prevRail = curRail;
- for (int index = 1; index < inProcessRails.Count; index++)
- {
- curRail = inProcessRails[index].theRail;
- prevRail.nextGrindable = curRail;
- curRail.prevGrindable = prevRail;
- prevRail = curRail;
- }
- // Finally, let's step through and flatten / square up our rail forwards
- Houdini_RailFitOrientationToExisting(activeRailOrigins);
- }
- /// <summary>
- /// Steps through the rails, flattening and squaring them up to being aligned with the rail's connectivity
- /// </summary>
- /// <param name="railOriginsToFlatten">the list of rail origins you want flattened</param>
- void Houdini_RailFlattenOrientation(List<GrindableRail> railOriginsToFlatten)
- {
- foreach (GrindableRail railOrigin in railOriginsToFlatten)
- {
- GrindableRail curRail = railOrigin;
- do
- {
- // First, we just flatten
- Vector3 newForward = curRail.transform.forward - (activeHoudiniRoot.transform.up * Vector3.Dot(curRail.transform.forward, activeHoudiniRoot.transform.up));
- newForward.Normalize();
- // Then, check if we have a next. If so, make us perpendicular to rail dir.
- if (curRail.nextGrindable)
- {
- Vector3 curRailDir = (curRail.nextGrindable.transform.position - curRail.transform.position).normalized;
- newForward = newForward - (curRailDir * Vector3.Dot(newForward, curRailDir));
- newForward.Normalize();
- }
- // If no next, we copy our prev's rotation and use that for ours too.
- else
- {
- newForward = curRail.prevGrindable.transform.forward;
- }
- // Apply our new forward!
- curRail.transform.LookAt(curRail.transform.position + newForward, activeHoudiniRoot.transform.up);
- // Next!
- curRail = curRail.nextGrindable;
- }
- while (curRail != null && curRail != railOrigin);
- }
- }
- /// <summary>
- /// This retains the Houdini-specied "up" (which ends up in our forward) as our up, and conforms rail orientation to that up and the rail's connectivity
- /// </summary>
- /// <param name="railOriginsToFlatten">the list of rails you want conformed</param>
- void Houdini_RailFitOrientationToExisting(List<GrindableRail> railOriginsToFlatten)
- {
- foreach (GrindableRail railOrigin in railOriginsToFlatten)
- {
- GrindableRail curRail = railOrigin;
- do
- {
- // First, pull out the Houdini up (which ends up in our Forward). That's the "up" we actually want to align to.
- Vector3 houdiniUp = curRail.transform.forward;
- // Then, check if we have a next. If so, that's to our immediate left.
- Vector3 newForward;
- Vector3 newRight;
- if (curRail.nextGrindable)
- {
- newRight = -(curRail.nextGrindable.transform.position - curRail.transform.position).normalized;
- }
- // If no next, we copy our prev's right and use that for ours too.
- else
- {
- newRight = curRail.prevGrindable.transform.right;
- }
- // Now generate the new forward from that right
- newForward = Vector3.Cross(newRight, houdiniUp).normalized;
- // Apply our new forward!
- curRail.transform.rotation = Quaternion.LookRotation(newForward, houdiniUp);
- // Next!
- curRail = curRail.nextGrindable;
- }
- while (curRail != null && curRail != railOrigin);
- }
- }
- #endregion
- #region Houdini Ramp Addition
- void Houdini_ClearExistingRamps()
- {
- // Clear our vert tracking
- activeRampZones.Clear();
- // Also, clear out any prior changes in the Houdini hierarchy
- Transform rampParent = activeHoudiniRoot.transform.Find(RampParentName);
- if (rampParent != null)
- {
- while (rampParent.childCount > 0)
- {
- Transform tempTrans = rampParent.GetChild(0);
- DestroyImmediate(tempTrans.gameObject);
- }
- DestroyImmediate(rampParent.gameObject);
- }
- }
- void Houdini_ProcessRamps()
- {
- if (activeHoudiniRoot == null) { return; }
- // First, clear out any prior work done on it
- Houdini_ClearExistingRamps();
- if (activeRailOrigins.Count == 0)
- {
- Debug.LogWarning("Skate Maker: Can't make verts until you've defined rails, sorry!");
- return;
- }
- // Then set the clean object up to be vert-ified
- GameObject newRampRoot = new GameObject();
- newRampRoot.name = RampParentName;
- newRampRoot.transform.parent = activeHoudiniRoot.transform;
- newRampRoot.transform.localPosition = Vector3.zero;
- newRampRoot.transform.localRotation = Quaternion.identity;
- newRampRoot.transform.localScale = Vector3.one;
- Transform activeRampRoot = newRampRoot.transform;
- // Now, we're gonna find the generated ramp mesh to base our ramp volume on
- Mesh meshToBound = null;
- Transform meshToBoundTrans = null;
- MeshRenderer[] childMeshes = activeHoudiniRoot.transform.GetComponentsInChildren<MeshRenderer>();
- foreach (MeshRenderer childMesh in childMeshes)
- {
- // Given that this is called after we've cleaned and disabled any node markers, there SHOULD only ever be one mesh here - the overall mesh!
- if (childMesh.gameObject.activeSelf && childMesh.enabled)
- {
- MeshFilter meshFilter = childMesh.gameObject.GetComponent<MeshFilter>();
- if (meshFilter != null)
- {
- meshToBound = meshFilter.sharedMesh;
- meshToBoundTrans = meshFilter.transform;
- }
- else
- {
- // Fallback to skinned mesh, just in case we eventually get fancy with our Houdini shit
- SkinnedMeshRenderer skinnedMeshRenderer = childMesh.gameObject.GetComponent<SkinnedMeshRenderer>();
- if (skinnedMeshRenderer != null)
- {
- meshToBound = skinnedMeshRenderer.sharedMesh;
- meshToBoundTrans = skinnedMeshRenderer.transform;
- }
- }
- break;
- }
- }
- // If there's no mesh filter (or no mesh), not much else we can do at this point
- if (meshToBound == null)
- {
- Debug.LogError("Houdini_ProcessRamps: Can't generate a ramp for something that doesn't even have a mesh!");
- return;
- }
- // Extract the bounds from that mesh, and so long as the new object has the position, boom, a bounding ramp for our entire shape!
- GameObject rampBoundObj = new GameObject();
- rampBoundObj.name = RampObjectName;
- rampBoundObj.layer = LayerMask.NameToLayer("Skate Zones");
- rampBoundObj.transform.parent = activeRampRoot;
- rampBoundObj.transform.position = meshToBoundTrans.position;
- rampBoundObj.transform.rotation = meshToBoundTrans.rotation;
- rampBoundObj.transform.localScale = meshToBoundTrans.localScale;
- BoxCollider rampBound = rampBoundObj.AddComponent<BoxCollider>();
- rampBound.isTrigger = true;
- Bounds meshBounds = GetMeshBounds(meshToBound);
- rampBound.center = meshBounds.center;
- rampBound.size = meshBounds.size;
- RampZone rampZone = rampBoundObj.AddComponent<RampZone>();
- if (rampBound.size.y > VertHeightCutoff) { rampZone.rampType = RampZone.RampTypes.MegaRamp; }
- else if (rampBound.size.y > RampHeightCutoff) { rampZone.rampType = RampZone.RampTypes.Vert; }
- }
- public static Bounds GetMeshBounds(Mesh mesh)
- {
- if (mesh == null)
- {
- Debug.LogError("GetMeshBounds: no mesh given");
- return new Bounds(Vector3.zero, Vector3.one);
- }
- Vector3[] vertices = mesh.vertices;
- if (vertices.Length <= 0)
- {
- Debug.LogError("GetMeshBounds: mesh doesn't have vertices");
- return new Bounds(Vector3.zero, Vector3.one);
- }
- Vector3 min, max;
- min = max = vertices[0];
- for (int i = 1; i < vertices.Length; i++)
- {
- Vector3 V = vertices[i];
- for (int n = 0; n < 3; n++)
- {
- if (V[n] > max[n]) { max[n] = V[n]; }
- if (V[n] < min[n]) { min[n] = V[n]; }
- }
- }
- Bounds meshBounds = new Bounds();
- meshBounds.SetMinMax(min, max);
- return meshBounds;
- }
- #endregion
- #region Houdini Vert Addition
- void Houdini_ClearExistingVerts()
- {
- // Clear our vert tracking
- activeVertZones.Clear();
- // Also, clear out any prior changes in the Houdini hierarchy
- Transform vertParent = activeHoudiniRoot.transform.Find(VertParentName);
- if (vertParent != null)
- {
- while (vertParent.childCount > 0)
- {
- Transform tempTrans = vertParent.GetChild(0);
- DestroyImmediate(tempTrans.gameObject);
- }
- DestroyImmediate(vertParent.gameObject);
- }
- }
- void Houdini_ProcessVerts()
- {
- if (activeHoudiniRoot == null) { return; }
- // First, clear out any prior work done on it
- Houdini_ClearExistingVerts();
- if (activeRailOrigins.Count == 0)
- {
- Debug.LogWarning("Skate Maker: Can't make verts until you've defined rails, sorry!");
- return;
- }
- // Then set the clean object up to be vert-ified
- GameObject newVertRoot = new GameObject();
- newVertRoot.name = VertParentName;
- newVertRoot.transform.parent = activeHoudiniRoot.transform;
- newVertRoot.transform.localPosition = Vector3.zero;
- newVertRoot.transform.localRotation = Quaternion.identity;
- newVertRoot.transform.localScale = Vector3.one;
- Transform activeVertRoot = newVertRoot.transform;
- // Now, let's add some verts!
- VertZone lastNeighborVert = null;
- GrindableRail curRail = activeRailOrigins[0];
- int nextRailOriginIndex = 1;
- while (curRail != null && curRail.nextGrindable != null)
- {
- // First, extract some base truths about where the rail is and where it's facing
- Vector3 vertForward = curRail.transform.forward;
- //Vector3 vertUp = curRail.transform.up; (we don't use this because magazine ramps have to be tilted to line up right, but that does NOT mean we want them to generate a tilted vert volume by default)
- Vector3 vertUp = Vector3.up;
- vertForward -= Vector3.Project(vertForward, vertUp);
- vertForward.Normalize();
- float railHeight = (curRail.transform.localPosition.y + curRail.nextGrindable.transform.localPosition.y) / 2f;
- Vector3 railDir = curRail.nextGrindable.transform.position - curRail.transform.position;
- float railWidth = railDir.magnitude;
- railDir.Normalize();
- float vertHeight = railHeight + VertHeightFromRail;
- Vector3 vertBottomCenter = curRail.transform.position + (railDir * railWidth / 2f) - (vertUp * railHeight) + (vertForward * VertThickness / 2f);
- vertBottomCenter += vertUp * vertHeight / 2f;
- // Now, create the vert zone!
- GameObject newVertZoneObj = new GameObject();
- newVertZoneObj.name = VertObjectName;
- newVertZoneObj.layer = LayerMask.NameToLayer("Skate Zones");
- newVertZoneObj.transform.parent = activeVertRoot;
- newVertZoneObj.transform.position = vertBottomCenter;
- newVertZoneObj.transform.LookAt(vertBottomCenter + vertForward, vertUp);
- newVertZoneObj.transform.localScale = new Vector3(railWidth, vertHeight, VertThickness);
- VertZone newVertZone = newVertZoneObj.AddComponent<VertZone>();
- newVertZone.planeAdjustment = VertPlaneAdjustment;
- BoxCollider newVertZoneCollider = newVertZoneObj.AddComponent<BoxCollider>();
- newVertZoneCollider.isTrigger = true;
- // Now, link us to the last neighbor vert (if there was any), and move on
- if (lastNeighborVert != null)
- {
- Vector3 dirToNeighborVert = lastNeighborVert.VertPlaneCenter - newVertZone.VertPlaneCenter;
- dirToNeighborVert.Normalize();
- if (Vector3.Dot(dirToNeighborVert, newVertZone.VertPlaneRight) > 0f)
- {
- newVertZone.rightNeighbor = lastNeighborVert;
- lastNeighborVert.leftNeighbor = newVertZone;
- }
- else
- {
- newVertZone.leftNeighbor = lastNeighborVert;
- lastNeighborVert.rightNeighbor = newVertZone;
- }
- }
- lastNeighborVert = newVertZone;
- // We're done! Now we just select the next rail
- curRail = curRail.nextGrindable;
- if (curRail.nextGrindable == null) { curRail = null; }
- // If the current stretch of rail has run out, pop to the next rail origin (if we can)
- if (curRail == null && nextRailOriginIndex < activeRailOrigins.Count)
- {
- curRail = activeRailOrigins[nextRailOriginIndex];
- nextRailOriginIndex++;
- // Clear this, since we're starting a new strip of rails (and thus they won't be a neighbor to current vert)
- lastNeighborVert = null;
- }
- }
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment