//Adds a new hook to the collider public void AddHook(DeformHook dh) { List <DeformHook> tempHooks = hooks.ToList(); tempHooks.Add(dh); hooks = tempHooks.ToArray(); }
//Adds a new hook with the given properties to the collider public DeformHook AddHook(string name, DeformHook.HookType hType, Vector3 pos, Quaternion rot, float radius, float strength, float falloff) { List <DeformHook> tempHooks = hooks.ToList(); DeformHook newHook = new DeformHook(name, hType, pos, rot, radius, strength, falloff); tempHooks.Add(newHook); hooks = tempHooks.ToArray(); return(newHook); }
//Removes a hook from the collider if it exists public void RemoveHook(DeformHook hook) { List <DeformHook> tempHooks = hooks.ToList(); if (tempHooks.Contains(hook)) { tempHooks.Remove(hook); hooks = tempHooks.ToArray(); } else { Debug.LogWarning("Specified hook does not exist in hook list."); } }
//Creates a new hook by copying an existing one public DeformHook(DeformHook h) { name = h.name; enabled = h.enabled; showHandles = h.showHandles; hookType = h.hookType; localPos = h.localPos; localRot = h.localRot; localEulerRot = h.localEulerRot; radius = h.radius; strength = h.strength; falloff = h.falloff; set = true; }
//Copies properties from another GeneratorProps instance //If copyPreset is true, it will also copy the linked preset reference from the other instance public void CopyProperties(GeneratorProps gp, bool copyPreset) { if (copyPreset) { linkedPreset = gp.linkedPreset; } meshAssetPath = gp.meshAssetPath; cornerPositionMode = gp.cornerPositionMode; cornerRadiusMode = gp.cornerRadiusMode; cornerOffsetMode = gp.cornerOffsetMode; cornerDetailMode = gp.cornerDetailMode; boxSize = gp.boxSize; boxOffset = gp.boxOffset; boxSidesPos = gp.boxSidesPos; boxSidesNeg = gp.boxSidesNeg; for (int i = 0; i < corners.Length; i++) { corners[i] = new ColliderCorner(gp.corners[i]); } for (int i = 0; i < cornerDetails.Length; i++) { cornerDetails[i] = gp.cornerDetails[i]; } topSegments = gp.topSegments; bottomSegments = gp.bottomSegments; XYDetail = gp.XYDetail; YZDetail = gp.YZDetail; XZDetail = gp.XZDetail; detailSmoothness = gp.detailSmoothness; stripDistribution1 = gp.stripDistribution1; stripDistribution2 = gp.stripDistribution2; bypassPolyTest = gp.bypassPolyTest; polyTestMode = gp.polyTestMode; detailReduction = gp.detailReduction; detailReductionAttempts = gp.detailReductionAttempts; boxedCorners = gp.boxedCorners; hooks = new DeformHook[gp.hooks.Length]; for (int i = 0; i < hooks.Length; i++) { hooks[i] = new DeformHook(gp.hooks[i]); } }
//Actual mesh generation with the indicated properties and generation container; do not call this directly static void GenerateMesh(ref GeneratorInstance gi, GeneratorProps genProps) { //Important vertex strips at ends of sections VertexStrip firstBottomStrip = new VertexStrip(); VertexStrip lastBottomStrip = new VertexStrip(); VertexStrip firstTopStrip = new VertexStrip(); VertexStrip lastTopStrip = new VertexStrip(); int bottomSegments = Mathf.Max(1, genProps.bottomSegments); int topSegments = Mathf.Max(1, genProps.topSegments); //Bottom section verts for (int i = 0; i < bottomSegments + 1; i++) { float stripProgress = (i * 1.0f) / (bottomSegments * 1.0f); //Properties for current vertex strip VertexStripProps stripProps = new VertexStripProps { isTop = false, flat = genProps.bottomSegments == 0, cornerDetails = genProps.cornerDetails, XYDetail = genProps.XYDetail, YZDetail = genProps.YZDetail, cornerProgress = Mathf.Pow(1.0f - Mathf.Pow(stripProgress, genProps.stripDistribution1), genProps.stripDistribution2), corners = genProps.corners, detailSmoothness = genProps.detailSmoothness }; lastBottomStrip = new VertexStrip(stripProps); gi.strips.Add(lastBottomStrip); if (i == 0) { firstBottomStrip = new VertexStrip(stripProps); } } //Top section verts for (int i = 0; i < topSegments + 1; i++) { float stripProgress = 1.0f - (i * 1.0f) / (topSegments * 1.0f); //Properties for current vertex strip VertexStripProps stripProps = new VertexStripProps { isTop = true, flat = genProps.topSegments == 0, cornerDetails = genProps.cornerDetails, XYDetail = genProps.XYDetail, YZDetail = genProps.YZDetail, cornerProgress = Mathf.Pow(1.0f - Mathf.Pow(stripProgress, genProps.stripDistribution1), genProps.stripDistribution2), corners = genProps.corners, detailSmoothness = genProps.detailSmoothness }; firstTopStrip = new VertexStrip(stripProps); //Add lateral strips between top and bottom sections if (genProps.XZDetail > 0 && i == 0) { int curStrip = 1; while (curStrip < genProps.XZDetail + 1) { gi.strips.Add(new VertexStrip(lastBottomStrip, firstTopStrip, ((curStrip * 1.0f) / ((genProps.XZDetail + 1) * 1.0f)), genProps.detailSmoothness)); curStrip++; } } else if (i == topSegments) { lastTopStrip = new VertexStrip(stripProps); } gi.strips.Add(firstTopStrip); } //Top cap lastTopStrip.ArrangeSides(); lastTopStrip.GenerateCap(); //Bottom cap firstBottomStrip.ArrangeSides(); firstBottomStrip.GenerateCap(); //Final vert array concatenation List <Vector3> tempVerts = new List <Vector3>(); for (int i = 0; i < gi.strips.Count; i++) { tempVerts.AddRange(gi.strips[i].verts); } //Adding vertices of the caps int capStartIndex = tempVerts.Count; tempVerts.AddRange(lastTopStrip.capVerts); tempVerts.AddRange(firstBottomStrip.capVerts); gi.finalVerts = tempVerts.ToArray(); //Triangle assignment int stripLength = gi.strips[0].verts.Count; int baseVert = 0; int stripLoop = 0; while (stripLoop < gi.strips.Count - 1) { for (int i = 0; i < stripLength - 1; i++) { gi.tris.Add(baseVert + i); gi.tris.Add(baseVert + stripLength + 1 + i); gi.tris.Add(baseVert + i + 1); gi.tris.Add(baseVert + stripLength + i); gi.tris.Add(baseVert + stripLength + 1 + i); gi.tris.Add(baseVert + i); } baseVert += stripLength; stripLoop++; } //Top cap triangles stripLength = lastTopStrip.side1.Count; for (int i = 0; i < lastTopStrip.capVerts.Count - stripLength - 1; i++) { if ((i + 1) % stripLength != 0) { gi.tris.Add(capStartIndex + i); gi.tris.Add(capStartIndex + i + 1); gi.tris.Add(capStartIndex + stripLength + i); gi.tris.Add(capStartIndex + stripLength + i); gi.tris.Add(capStartIndex + i + 1); gi.tris.Add(capStartIndex + stripLength + 1 + i); } } //Bottom cap triangles capStartIndex += lastTopStrip.capVerts.Count; stripLength = firstBottomStrip.side1.Count; for (int i = 0; i < firstBottomStrip.capVerts.Count - stripLength - 1; i++) { if ((i + 1) % stripLength != 0) { gi.tris.Add(capStartIndex + i + 1); gi.tris.Add(capStartIndex + i); gi.tris.Add(capStartIndex + stripLength + i); gi.tris.Add(capStartIndex + i + 1); gi.tris.Add(capStartIndex + stripLength + i); gi.tris.Add(capStartIndex + stripLength + 1 + i); } } //Hook Deformation if (genProps.hooks.Length > 0) { for (int i = 0; i < genProps.hooks.Length; i++) { DeformHook curHook = genProps.hooks[i]; if (curHook.enabled) { for (int j = 0; j < gi.finalVerts.Length; j++) { Vector3 curVert = gi.finalVerts[j]; float deformAmount = Mathf.Pow(Mathf.Max(0.0f, curHook.radius - Vector3.Distance(curVert, curHook.localPos)), curHook.falloff); switch (curHook.hookType) { case DeformHook.HookType.Pull: gi.finalVerts[j] += curHook.localRot * Vector3.forward * deformAmount * curHook.strength; break; case DeformHook.HookType.Twist: Vector3 newVert = curHook.localPos + curHook.localRot * (curVert - curHook.localPos); gi.finalVerts[j] += (newVert - curVert) * deformAmount * curHook.strength; break; case DeformHook.HookType.Expand: gi.finalVerts[j] += curHook.localPos + (curVert - curHook.localPos) * (1.0f + (curHook.strength - 1.0f) * deformAmount) - curVert; break; } } } } } //Set final mesh data gi.colMesh = new Mesh(); gi.colMesh.vertices = gi.finalVerts; gi.colMesh.triangles = gi.tris.ToArray(); }
//Function for flipping corners //cids must be a list of corner ID pairs where each pair represents corners being swapped void FlipOperation(ColliderCorner.CornerId[] cids, ref DeformHook[] mHooks, int xFactor, int yFactor, int zFactor) { if (cids.Length != 8) { Debug.LogError("Mirror operation failed, corner input array must contain 8 corners (4 pairs of corners being mirrored)."); return; } //Temporary corners for swapping ColliderCorner[] tempCorners = new ColliderCorner[4] { new ColliderCorner(GetCornerAtLocation(cids[1])), new ColliderCorner(GetCornerAtLocation(cids[3])), new ColliderCorner(GetCornerAtLocation(cids[5])), new ColliderCorner(GetCornerAtLocation(cids[7])) }; //First part of flipping by mirroring MirrorCorner(cids[0], cids[1], xFactor, yFactor, zFactor); MirrorCorner(cids[2], cids[3], xFactor, yFactor, zFactor); MirrorCorner(cids[4], cids[5], xFactor, yFactor, zFactor); MirrorCorner(cids[6], cids[7], xFactor, yFactor, zFactor); //Second part of flipping by mirroring temporary corners MirrorCorner(tempCorners[0], cids[0], xFactor, yFactor, zFactor); MirrorCorner(tempCorners[1], cids[2], xFactor, yFactor, zFactor); MirrorCorner(tempCorners[2], cids[4], xFactor, yFactor, zFactor); MirrorCorner(tempCorners[3], cids[6], xFactor, yFactor, zFactor); //Flipping hooks for (int i = 0; i < mHooks.Length; i++) { DeformHook curHook = mHooks[i]; curHook.localPos.Set(xFactor * curHook.localPos.x, yFactor * curHook.localPos.y, zFactor * curHook.localPos.z); Vector3 forwardDir = curHook.localRot * Vector3.forward; Vector3 upDir = curHook.localRot * Vector3.up; if (curHook.hookType != DeformHook.HookType.Twist) { //Flipping rules for pull and expand hook types Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else { //Special rules for flipping twist hook types if (xFactor == -1) { Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else if (yFactor == -1) { Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(yFactor * upDir.x, upDir.y, yFactor * upDir.z); curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else if (zFactor == -1) { Vector3 flippedForwardDir = new Vector3(zFactor * forwardDir.x, zFactor * forwardDir.y, forwardDir.z); Vector3 flippedUpDir = new Vector3(zFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } } curHook.localEulerRot = curHook.localRot.eulerAngles; } }
//Function for mirroring corners //cids must be a list of corner ID pairs where each pair represents a getter and setter corner, where one corner's properties are being mirrored and copied to the other one void MirrorOperation(ColliderCorner.CornerId[] cids, ref DeformHook[] mHooks, int xFactor, int yFactor, int zFactor, bool isPositiveSide) { if (cids.Length != 8) { Debug.LogError("Mirror operation failed, corner input array must contain 8 corners (4 pairs of corners being mirrored)."); return; } //Mirroring corners MirrorCorner(cids[0], cids[1], xFactor, yFactor, zFactor); MirrorCorner(cids[2], cids[3], xFactor, yFactor, zFactor); MirrorCorner(cids[4], cids[5], xFactor, yFactor, zFactor); MirrorCorner(cids[6], cids[7], xFactor, yFactor, zFactor); //Tests to make sure not to mirror hooks at the center of the flipping axis and remove hooks opposite of the mirroring side List <DeformHook> tempHooks = mHooks.ToList(); for (int i = 0; i < tempHooks.Count; i++) { if (isPositiveSide && ((xFactor < 0 && tempHooks[i].localPos.x < -0.001f) || (yFactor < 0 && tempHooks[i].localPos.y < -0.001f) || (zFactor < 0 && tempHooks[i].localPos.z < -0.001f)) || !isPositiveSide && ((xFactor <0 && tempHooks[i].localPos.x> 0.001f) || (yFactor <0 && tempHooks[i].localPos.y> 0.001f) || (zFactor <0 && tempHooks[i].localPos.z> 0.001f))) { tempHooks[i] = null; } } tempHooks.RemoveAll(hook => hook == null); //Mirroring hooks List <DeformHook> mirroredHooks = new List <DeformHook>(); for (int i = 0; i < tempHooks.Count; i++) { if ((xFactor < 0 && Mathf.Abs(tempHooks[i].localPos.x) > 0.001f) || (yFactor <0 && Mathf.Abs(tempHooks[i].localPos.y)> 0.001f) || (zFactor <0 && Mathf.Abs(tempHooks[i].localPos.z)> 0.001f)) { DeformHook newHook = new DeformHook(tempHooks[i]); if (!newHook.name.EndsWith("Mirrored")) { newHook.name += " Mirrored"; } newHook.localPos.Set(xFactor * newHook.localPos.x, yFactor * newHook.localPos.y, zFactor * newHook.localPos.z); Vector3 forwardDir = newHook.localRot * Vector3.forward; Vector3 upDir = newHook.localRot * Vector3.up; if (newHook.hookType != DeformHook.HookType.Twist) { //Mirroring rules for pull and expand hook types Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); newHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else { //Special rules for mirroring twist hook types if (xFactor == -1) { Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); newHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else if (yFactor == -1) { Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z); Vector3 flippedUpDir = new Vector3(yFactor * upDir.x, upDir.y, yFactor * upDir.z); newHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } else if (zFactor == -1) { Vector3 flippedForwardDir = new Vector3(zFactor * forwardDir.x, zFactor * forwardDir.y, forwardDir.z); Vector3 flippedUpDir = new Vector3(zFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z); newHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir); } } newHook.localEulerRot = newHook.localRot.eulerAngles; mirroredHooks.Add(newHook); } } tempHooks.AddRange(mirroredHooks); mHooks = tempHooks.ToArray(); }