/// <summary> /// Iterates over a given face. /// </summary> /// <param name="face"></param> /// <param name="currentVertexSelector"></param> /// <param name="returnCurrent"> /// There are always 2 possible edges to follow from each vertex. So we have to /// keep track from which vertex did we come to the current vertex. /// /// The returnCurrent argument determines which of the two vertices is returned. /// true - returns the current vertex /// false - returns the previous vertex /// </param> /// <returns></returns> private IEnumerable <Vertex <T> > IterateFace(FaceHandle <Vertex <T> > face, Func <FaceHandle <Vertex <T> >, Vertex <T> > currentVertexSelector, bool returnCurrent = true) { var previous = face.Anchor; var current = currentVertexSelector(face); return(IterateFace(current, previous, returnCurrent)); }
/// <summary> /// Iterates over both sides of the face in parallel until the root is found. /// </summary> /// <remarks> /// Always returns the "previous" vertex! /// /// The first returned vertex is the anchor of a given face. Both iterators are then /// advanced so that anchor point is not returned twice. After that, both iterators /// alternate in returning the current follow vertex. If any of the iterators encounter /// the root vertex, the whole process ends. /// </remarks> /// <param name="face"></param> /// <returns></returns> private IEnumerable <Vertex <T> > IterateBothSides(FaceHandle <Vertex <T> > face) { var firstEnumerable = IterateFirstSide(face, false); var secondEnumerable = IterateSecondSide(face, false); var firstActive = false; using (var firstEnumerator = firstEnumerable.GetEnumerator()) { using (var secondEnumerator = secondEnumerable.GetEnumerator()) { if (!firstEnumerator.MoveNext() || !secondEnumerator.MoveNext()) { yield break; } yield return(firstEnumerator.Current); if (!firstEnumerator.MoveNext() || !secondEnumerator.MoveNext()) { yield break; } while (true) { if (firstActive) { yield return(firstEnumerator.Current); if (!firstEnumerator.MoveNext()) { yield break; } } else { yield return(secondEnumerator.Current); if (!secondEnumerator.MoveNext()) { yield break; } } firstActive = !firstActive; } } } }
public override void OnHandlerDrag(PointerEventData eventData) { SCPointEventData scPointEventData = eventData as SCPointEventData; if (scPointEventData == null) { return; } if (currentGrabPoint == Vector3.zero) { initialGrabPoint = currentGrabPoint = scPointEventData.Position3D; } currentGrabPoint = scPointEventData.Position3D; float initialDist = Vector3.Dot(initialGrabPoint - oppositeCorner, diagonalDir); float currentDist = Vector3.Dot(currentGrabPoint - oppositeCorner, diagonalDir); float scaleFactor = 1 + (currentDist - initialDist) / initialDist; Vector3 newScale = initialScaleOnGrabStart;// * scaleFactor; FaceHandle facePointHandle = currentHandle as FaceHandle; Vector3 axisScaleFactor = Vector3.one; if (facePointHandle.axis == BoundingBox.AxisType.X || facePointHandle.axis == BoundingBox.AxisType.NX) { axisScaleFactor = new Vector3(scaleFactor, 1, 1); } else if (facePointHandle.axis == BoundingBox.AxisType.Y || facePointHandle.axis == BoundingBox.AxisType.NY) { axisScaleFactor = new Vector3(1, scaleFactor, 1); } else if (facePointHandle.axis == BoundingBox.AxisType.Z || facePointHandle.axis == BoundingBox.AxisType.NZ) { axisScaleFactor = new Vector3(1, 1, scaleFactor); } newScale = Vector3.Scale(initialScaleOnGrabStart, axisScaleFactor); boundingBox.transform.localScale = newScale; float distance = Vector3.Distance(initialPositionOnGrabStart, oppositeCorner); float coef = (facePointHandle.axis == BoundingBox.AxisType.X || facePointHandle.axis == BoundingBox.AxisType.Y || facePointHandle.axis == BoundingBox.AxisType.Z) ? -1 : 1; boundingBox.transform.position = initialPositionOnGrabStart + coef * (boundingBox.transform.rotation * (Vector3.one - axisScaleFactor) * distance); }
private void UpdateMesh() { mVertices.Clear(); mNormals.Clear(); mUvs.Clear(); mIndices.Clear(); int triangle = 0; for (int faceIndex = 0; faceIndex < mFaces.Count; ++faceIndex) { FaceHandle face = mFaces[faceIndex]; if (face.vertices.Count < 3) { Debug.LogWarning("Invalid face. A face needs at least 3 vertices. The mesh will exlude this face."); continue; } for (int vertexIndex = 0; vertexIndex < face.vertices.Count; ++vertexIndex) { Vertex vertex = face.vertices[vertexIndex]; mVertices.Add(vertex.position); Vector3 AB = face.vertices[(vertexIndex + 1) % face.vertices.Count].position - vertex.position; Vector3 AC = face.vertices[(vertexIndex + 2) % face.vertices.Count].position - vertex.position; Vector3 normal = Vector3.Cross(AB, AC).normalized; mNormals.Add(normal); } for (int triangleIndex = 0; triangleIndex < face.vertices.Count - 2; ++triangleIndex) { AddTriangle(triangle, triangle + 1 + triangleIndex, triangle + 2 + triangleIndex); } triangle += face.vertices.Count; } mMesh.Clear(); mMesh.vertices = mVertices.ToArray(); mMesh.normals = mNormals.ToArray(); mMesh.triangles = mIndices.ToArray(); mMesh.RecalculateBounds(); MeshFilter meshFilter = GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.mesh = mMesh; } }
private void Update() { ResetMesh(); for (int ruleSetIndex = 0; ruleSetIndex < mRuleSets.Count; ++ruleSetIndex) { List <FaceHandle> facesToEdit = new List <FaceHandle>(); for (int faceIndex = 0; faceIndex < mFaces.Count; ++faceIndex) { if (mFaces[faceIndex].name == mRuleSets[ruleSetIndex].mName) { facesToEdit.Add(mFaces[faceIndex]); } } for (int faceIndex = 0; faceIndex < facesToEdit.Count; ++faceIndex) { FaceHandle currentFaceHandle = facesToEdit[faceIndex]; for (int ruleIndex = 0; ruleIndex < mRuleSets[ruleSetIndex].mRules.Count; ++ruleIndex) { ProceduralMeshRule rule = mRuleSets[ruleSetIndex].mRules[ruleIndex]; if (SparkUtilities.Cast <ProceduralMeshRuleExtrude>(rule) != null) { ProceduralMeshRuleExtrude extrudeRule = SparkUtilities.Cast <ProceduralMeshRuleExtrude>(rule); float length = extrudeRule.mLength; List <FaceHandle> newFaces = ExtrudeFace(currentFaceHandle, length); for (int newFaceIndex = 0; newFaceIndex < newFaces.Count; ++newFaceIndex) { //newFaces[newFaceIndex].name = extrudeRule.mNewFaceNames; } currentFaceHandle = mFaces.Last(); } else if (SparkUtilities.Cast <ProceduralMeshRuleScale>(rule) != null) { ProceduralMeshRuleScale scaleRule = SparkUtilities.Cast <ProceduralMeshRuleScale>(rule); Vector2 scale = scaleRule.mScale; ScaleFace(currentFaceHandle, scale); } } } } UpdateMesh(); }
public void ScaleFace(FaceHandle aFace, Vector2 aScale) { if (aFace.vertices.Count < 3) { Debug.LogWarning("Invalid face. A face needs at least 3 vertices. The face scaling will be skipped."); return; } Vector3 center = Vector3.zero; for (int vertexIndex = 0; vertexIndex < aFace.vertices.Count; ++vertexIndex) { center += aFace.vertices[vertexIndex].position; } center /= aFace.vertices.Count; for (int vertexIndex = 0; vertexIndex < aFace.vertices.Count; ++vertexIndex) { Vector3 original = aFace.vertices[vertexIndex].position; aFace.vertices[vertexIndex].position = center * (1.0f - aScale.x) + original * aScale.x; } }
public List <FaceHandle> ExtrudeFace(FaceHandle aFace, float aLength) { List <FaceHandle> newFaces = new List <FaceHandle>(); if (aFace.vertices.Count < 3) { Debug.LogWarning("Invalid face. A face needs at least 3 vertices. The face extrusion will be skipped."); return(newFaces); } Vector3 averageNormal = Vector3.zero; for (int triangleIndex = 0; triangleIndex < aFace.vertices.Count - 2; ++triangleIndex) { Vector3 AB = aFace.vertices[(triangleIndex + 1) % aFace.vertices.Count].position - aFace.vertices[triangleIndex].position; Vector3 AC = aFace.vertices[(triangleIndex + 2) % aFace.vertices.Count].position - aFace.vertices[triangleIndex].position; Vector3 normal = Vector3.Cross(AB, AC).normalized; averageNormal += normal; } averageNormal.Normalize(); Vertex[] tempVertices = new Vertex[aFace.vertices.Count]; for (int vertexIndex = 0; vertexIndex < aFace.vertices.Count; ++vertexIndex) { tempVertices[vertexIndex] = new Vertex { position = aFace.vertices[vertexIndex].position + averageNormal * aLength, normal = Vector3.up, uv = Vector2.up }; } for (int faceIndex = 0; faceIndex < aFace.vertices.Count; ++faceIndex) { int numVertices = aFace.vertices.Count; int i0 = faceIndex; int i1 = (faceIndex + 1) % numVertices; mFaces.Add(new FaceHandle(aFace.vertices[i0], aFace.vertices[i1], tempVertices[i1], tempVertices[i0])); newFaces.Add(mFaces.Last()); } mFaces.Add(new FaceHandle(tempVertices)); mFaces.Remove(aFace); return(newFaces); }
/// <summary> /// Starts with the "second" vertex of a given face handle. /// Stops after a root is find. /// </summary> /// <param name="face"></param> /// <param name="returnCurrent"> /// There are always 2 possible edges to follow from each vertex. So we have to /// keep track from which vertex did we come to the current vertex. /// /// The returnCurrent argument determines which of the two vertices is returned. /// true - returns the current vertex /// false - returns the previous vertex /// </param> /// <returns></returns> private IEnumerable <Vertex <T> > IterateSecondSide(FaceHandle <Vertex <T> > face, bool returnCurrent = true) { return(IterateFace(face, x => x.SecondVertex, returnCurrent)); }
private void ReCreateVisual() { if (boundingBox.CornerBoundingBoxRoot == null) { return; } handles = new FaceHandle[FACE_NUM]; for (int i = 0; i < FACE_NUM; i++) { handles[i] = new FaceHandle(); } CornerBoundingBoxRoot cornerBoundingBoxRoot = boundingBox.CornerBoundingBoxRoot; handles[0].localPosition = (cornerBoundingBoxRoot.handles[0].localPosition + cornerBoundingBoxRoot.handles[3].localPosition) * 0.5f; handles[1].localPosition = (cornerBoundingBoxRoot.handles[3].localPosition + cornerBoundingBoxRoot.handles[6].localPosition) * 0.5f; handles[2].localPosition = (cornerBoundingBoxRoot.handles[5].localPosition + cornerBoundingBoxRoot.handles[6].localPosition) * 0.5f; handles[3].localPosition = (cornerBoundingBoxRoot.handles[0].localPosition + cornerBoundingBoxRoot.handles[5].localPosition) * 0.5f; handles[4].localPosition = (cornerBoundingBoxRoot.handles[0].localPosition + cornerBoundingBoxRoot.handles[6].localPosition) * 0.5f; handles[5].localPosition = (cornerBoundingBoxRoot.handles[1].localPosition + cornerBoundingBoxRoot.handles[7].localPosition) * 0.5f; handles[0].axis = BoundingBox.AxisType.NZ; handles[1].axis = BoundingBox.AxisType.Y; handles[2].axis = BoundingBox.AxisType.Z; handles[3].axis = BoundingBox.AxisType.NY; handles[4].axis = BoundingBox.AxisType.NX; handles[5].axis = BoundingBox.AxisType.X; for (int i = 0; i < FACE_NUM; i++) { string rootName = "FacePointRoot_" + i.ToString(); Transform existRoot = boundingBox.BoundingBoxContainer.Find(rootName); if (existRoot != null) { GameObject.Destroy(existRoot.gameObject); } handles[i].root = new GameObject("FacePointRoot_" + i).transform; handles[i].root.transform.parent = boundingBox.BoundingBoxContainer; handles[i].root.transform.localPosition = handles[i].localPosition; handles[i].root.transform.localRotation = Quaternion.identity; handles[i].visual = boundingBox.facePrefab == null?GameObject.CreatePrimitive(PrimitiveType.Cube) : GameObject.Instantiate(boundingBox.facePrefab); handles[i].visual.name = "visuals"; if (handles[i].visual.GetComponent <Collider>()) { GameObject.Destroy(handles[i].visual.GetComponent <Collider>()); } handles[i].bounds = BoundingBoxUtils.GetMaxBounds(handles[i].visual); float maxDim = Mathf.Max(Mathf.Max(handles[i].bounds.size.x, handles[i].bounds.size.y), handles[i].bounds.size.z); float invScale = boundingBox.AxisScaleHandleSize / maxDim; handles[i].visual.transform.parent = handles[i].root.transform; handles[i].visual.transform.localScale = new Vector3(invScale, invScale, invScale); handles[i].visual.transform.localPosition = Vector3.zero; handles[i].visual.transform.localRotation = Quaternion.identity; Bounds bounds = new Bounds(handles[i].bounds.center * invScale, handles[i].bounds.size * invScale); BoxCollider collider = handles[i].root.gameObject.AddComponent <BoxCollider>(); collider.size = bounds.size; collider.center = bounds.center; handles[i].root.gameObject.AddComponent <NearInterationGrabbable>(); var cursorBehavoir = handles[i].root.gameObject.AddComponent <CursorBehavoir>(); cursorBehavoir.positionBehavoir = CursorBehavoir.PositionBehavoir.AnchorPosition3D; cursorBehavoir.visualBehavoir = CursorBehavoir.VisualBehavoir.Scale; } }