public bool ClickShortcutCheck(EventModifiers em, pb_Object pb, pb_Face quad) { // if(em == (EventModifiers.Control | EventModifiers.Shift | EventModifiers.Alt)) // { // Continue(pb, quad); // pb_Editor_Utility.ShowNotification("Continue UV"); // return true; // } if (em == (EventModifiers.Control | EventModifiers.Shift)) { ApplyMaterial(pb, quad, queuedMat); RepaintSceneViews(); pb_Editor_Utility.ShowNotification("Quick Apply Material"); return(true); } if (em == (EventModifiers.Control)) { pb.SetFaceUV(quad, new pb_UV(uv_gui)); RepaintSceneViews(); pb_Editor_Utility.ShowNotification("Copy UV Settings"); return(true); } return(false); }
public void OnEnable() { if (EditorApplication.isPlayingOrWillChangePlaymode) { return; } if (target is pb_Object) { pb = (pb_Object)target; } else { return; } ren = pb.gameObject.GetComponent <Renderer>(); EditorUtility.SetSelectedWireframeHidden(ren, editor != null); /* if Verify returns false, that means the mesh was rebuilt - so generate UV2 again */ foreach (pb_Object selpb in Selection.transforms.GetComponents <pb_Object>()) { pb_Editor_Utility.VerifyMesh(selpb); } }
private static void DoUpgrade(pb_Object[] all) { bool interactive = all != null && all.Length > 8; for (int i = 0; i < all.Length; i++) { pb_Object pb = all[i]; if (interactive) { EditorUtility.DisplayProgressBar( "Applying Materials", "Setting pb_Object " + all[i].id + ".", ((float)i / all.Length)); } pb.SetFaceMaterial(pb.faces, pb.gameObject.GetComponent <MeshRenderer>().sharedMaterial); pb.ToMesh(); pb.Refresh(); pb.Optimize(); } if (interactive) { EditorUtility.ClearProgressBar(); } }
// breaks a pb_object into a zillion* faces public static GameObject[] ExplodeObject(pb_Object pb) { // disable 'ze donor pb.gameObject.SetActive(false); GameObject[] pieces = new GameObject[pb.faces.Length]; // extract mesh and material information for every face, and assign it to a gameobject for (int i = 0; i < pieces.Length; i++) { Mesh m = new Mesh(); m.vertices = pb.GetVertices(pb.faces[i]); m.triangles = new int[6] { 0, 1, 2, 1, 3, 2 }; m.normals = pb.GetNormals(pb.faces[i]); m.uv = pb.GetUVs(pb.faces[i]); m.RecalculateBounds(); GameObject go = new GameObject(); go.transform.position = pb.transform.position + pb_Math.PlaneNormal(m.vertices).normalized * .3f; go.transform.localRotation = pb.transform.localRotation; go.AddComponent <MeshFilter>().sharedMesh = m; go.AddComponent <MeshRenderer>().sharedMaterial = pb.GetMaterial(pb.faces[i]); pieces[i] = go; } return(pieces); }
/** * \brief Reverse the winding order for each passed #pb_Face. * @param faces The faces to apply normal flippin' to. * \returns Nothing. No soup for you. * \sa SelectedFaces pb_Face */ public static void ReverseWindingOrder(this pb_Object pb, pb_Face[] faces) { for (int i = 0; i < faces.Length; i++) { faces[i].ReverseIndices(); } }
bool FaceRaycast(Vector2 mouse, out pb_Object pb, out pb_Face face) { var ray = Camera.main.ScreenPointToRay(mouse); RaycastHit rayHit; if (Physics.Raycast(ray.origin, ray.direction, out rayHit)) { pb = rayHit.transform.gameObject.GetComponent <pb_Object>(); if (pb == null) { face = null; return(false); } Mesh m = pb.GetComponent <MeshFilter>().sharedMesh; int[] tri = new int[3] { m.triangles[rayHit.triangleIndex * 3 + 0], m.triangles[rayHit.triangleIndex * 3 + 1], m.triangles[rayHit.triangleIndex * 3 + 2] }; return(pb.FaceWithTriangle(tri, out face)); } pb = null; face = null; return(false); }
/** * Center the mesh pivot at the average of passed indices. */ public static void CenterPivot(this pb_Object pb, int[] indices) { Vector3 center = Vector3.zero; if (indices != null) { Vector3[] verts = pb.VerticesInWorldSpace(indices); foreach (Vector3 v in verts) { center += v; } center /= (float)verts.Length; } else { center = pb.transform.TransformPoint(pb.msh.bounds.center); } Vector3 dir = (pb.transform.position - center); pb.transform.position = center; pb.TranslateVertices_World(pb.msh.triangles, dir); pb.ToMesh(); pb.Refresh(); }
public static bool HiddenFace(pb_Object pb, pb_Face q, float dist) { // Grab the face normal Vector3 dir = pb_Math.Normal(pb.VerticesInWorldSpace(q.indices)); // If casting from the center of the plane hits, chekc the rest of the points for collisions Vector3 orig = pb.transform.TransformPoint(pb_Math.Average(pb.GetVertices(q))); bool hidden = true; Transform hitObj = RaycastFaceCheck(orig, dir, dist, null); if(hitObj != null) { Vector3[] v = pb.VerticesInWorldSpace(q.indices); for(int i = 0; i < v.Length; i++) { if(null == RaycastFaceCheck(v[i], dir, dist, hitObj)) { hidden = false; break; } } } else hidden = false; return hidden; }
private static void RebuildProBuilderMesh(pb_Object pb) { try { GameObject go = pb.gameObject; pb.dontDestroyMeshOnDelete = true; Undo.DestroyObjectImmediate(pb); // don't delete pb_Entity here because it won't // actually get removed till the next frame, and // probuilderize wants to add it if it's missing // (which it looks like it is from c# side but // is not) pb = Undo.AddComponent <pb_Object>(go); pbMeshOps.ResetPbObjectWithMeshFilter(pb, true); pb.ToMesh(); pb.Refresh(); pb.Optimize(); } catch (System.Exception e) { Debug.LogError("Failed rebuilding ProBuilder mesh: " + e.ToString()); } }
public bool FaceCheck(Vector3 pos) { Ray ray = Camera.main.ScreenPointToRay (pos); RaycastHit hit; if( Physics.Raycast(ray.origin, ray.direction, out hit)) { pb_Object hitpb = hit.transform.gameObject.GetComponent<pb_Object>(); if(hitpb == null) return false; Mesh m = hitpb.msh; int[] tri = new int[3] { m.triangles[hit.triangleIndex * 3 + 0], m.triangles[hit.triangleIndex * 3 + 1], m.triangles[hit.triangleIndex * 3 + 2] }; pb = hitpb; quad = hitpb.QuadWithTriangle(tri); return true; } return false; }
/** * Returns the average of each vertex position in a face. * In local space. */ private Vector3 FaceCenter(pb_Object pb, pb_Face face) { Vector3[] vertices = pb.vertices; Vector3 average = Vector3.zero; // face holds triangle data. distinctIndices is a // cached collection of the distinct indices that // make up the triangles. Ex: // tris = {0, 1, 2, 2, 3, 0} // distinct indices = {0, 1, 2, 3} foreach (int index in face.distinctIndices) { average.x += vertices[index].x; average.y += vertices[index].y; average.z += vertices[index].z; } float len = (float)face.distinctIndices.Length; average.x /= len; average.y /= len; average.z /= len; return(average); }
private void RefreshSelectedFacePreview() { Vector3[] array = currentSelection.pb.VerticesInWorldSpace(currentSelection.face.indices); int[] array2 = new int[array.Length]; for (int i = 0; i < array2.Length; i++) { array2[i] = i; } Vector3 vector = pb_Math.Normal(array); for (int j = 0; j < array.Length; j++) { array[j] += vector.normalized * 0.01f; } if ((bool)preview) { Object.Destroy(preview.gameObject); } preview = pb_Object.CreateInstanceWithVerticesFaces(array, new pb_Face[1] { new pb_Face(array2) }); preview.SetFaceMaterial(preview.faces, previewMaterial); preview.ToMesh(); preview.Refresh(); }
private void SpawnCube() { pb_Object pb_Object = pb_ShapeGenerator.CubeGenerator(Vector3.one); pb_Object.gameObject.AddComponent <MeshCollider>().convex = false; currentSelection = new pb_Selection(pb_Object, null); }
/** * Center the mesh pivot at the average of passed indices. */ public static void CenterPivot(this pb_Object pb, int[] indices) { Vector3[] verts = pb.VerticesInWorldSpace(indices == null ? pb.uniqueIndices : indices); Vector3 center = Vector3.zero; foreach (Vector3 v in verts) { center += v; } center /= (float)verts.Length; // if(pbUtil.SharedSnapEnabled) // center = pbUtil.SnapValue(center, pbUtil.SharedSnapValue); Vector3 dir = (pb.transform.position - center); pb.transform.position = center; // the last bool param force disables snapping vertices pb.TranslateVertices(pb.uniqueIndices, dir, true); pb.Refresh(); }
void Start() { player = null; levels.Clear(); // Technically we're still loading... // LocateAndUpdateCollectablesAndInteractables(); // Populate levels foreach (AreaController level in ExtendList.FindObjectsOfTypeInactive <AreaController>()) { //levelsParent.GetComponentsInChildren<Level>(true)) { levels.Add(level); } #if UNITY_EDITOR FindPlayer(); #endif if (backgroundPlane == null) { backgroundPlane = GameObject.Find("BackgroundPlane").GetComponent <pb_Object>(); } }
public static pb_Smoothing_Editor Init(pb_Texture_Editor del, pb_Object[] _selection) { pb_Smoothing_Editor pse = (pb_Smoothing_Editor)EditorWindow.GetWindow(typeof(pb_Smoothing_Editor), true, "Smoothing Groups", true); pse.SetDelegate(del); pse.UpdateSelection(_selection); return pse; }
/** * \brief Returns all connected faces. */ public static List<pb_Face> GetConnectedFaces(pb_Object pb, pb_Face[] selFaces) { int len = selFaces.Length; List<pb_Face> faces = new List<pb_Face>(); pb_IntArray[] sharedIndices = pb.sharedIndices; pb_Edge[][] sharedEdges = new pb_Edge[len][]; for(int i = 0; i < len; i++) sharedEdges[i] = pb_Edge.GetUniversalEdges(selFaces[i].edges, sharedIndices); for(int i = 0; i < pb.faces.Length; i++) { pb_Edge[] faceEdges = pb_Edge.GetUniversalEdges(pb.faces[i].edges, sharedIndices); for(int j = 0; j < len; j++) { int ind = faceEdges.ContainsMatch(sharedEdges[j]); if(ind > -1) faces.Add(pb.faces[i]); } } return faces; }
/** * \brief Rebuild targets if they can't be refreshed. */ private static void RebuildSharedIndices(pb_Object[] targets, bool interactive = true) { for (int i = 0; i < targets.Length; i++) { if (interactive) { EditorUtility.DisplayProgressBar( "Refreshing ProBuilder Objects", "Reshaping pb_Object " + targets[i].id + ".", ((float)i / targets.Length)); } pb_Object pb = targets[i]; try { pb.SetSharedIndices(pb_IntArrayUtility.ExtractSharedIndices(pb.vertices)); pb.ToMesh(); pb.Refresh(); pb.Optimize(); } catch (System.Exception e) { Debug.LogError("Failed rebuilding " + pb.name + " shared indices cache.\n" + e.ToString()); } } if (interactive) { EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Rebuild Shared Index Cache", "Successfully rebuilt " + targets.Length + " shared index caches", "Okay"); } }
/** * \brief Performs Entity specific initialization tasks (turn off renderer for nodraw faces, hide colliders, etc) */ public void Awake() { pb = GetComponent <pb_Object>(); if (pb == null) { return; } switch (entityType) { case EntityType.Occluder: // Destroy(gameObject); break; case EntityType.Detail: break; case EntityType.Trigger: #if !DEBUG GetComponent <MeshRenderer>().enabled = false; #endif break; case EntityType.Collider: #if !DEBUG GetComponent <MeshRenderer>().enabled = false; #endif break; } }
public void OnGUI() { GUILayout.Label("Mirror Axis", EditorStyles.boldLabel); scaleX = EditorGUILayout.Toggle("X", scaleX); scaleY = EditorGUILayout.Toggle("Y", scaleY); scaleZ = EditorGUILayout.Toggle("Z", scaleZ); if (GUILayout.Button("Mirror")) { List <GameObject> mirrors = new List <GameObject>(); foreach (pb_Object pb in pbUtil.GetComponents <pb_Object>(Selection.transforms)) { pb_Object result = pb_Mirror_Tool.Mirror(pb, new Vector3( (scaleX) ? -1f : 1f, (scaleY) ? -1f : 1f, (scaleZ) ? -1f : 1f )); mirrors.Add(result.gameObject); } if (pb_Editor.instance != null) { pb_Editor.instance.SetSelection(mirrors.ToArray()); } else { Selection.objects = mirrors.ToArray(); } SceneView.RepaintAll(); } }
/** * \brief Performs Entity specific initialization tasks (turn off renderer for nodraw faces, hide colliders, etc) */ public void Awake() { pb = GetComponent<pb_Object>(); if(pb == null) { return; } switch(entityType) { case EntityType.Occluder: // Destroy(gameObject); break; case EntityType.Detail: break; case EntityType.Trigger: #if !DEBUG GetComponent<MeshRenderer>().enabled = false; #endif break; case EntityType.Collider: #if !DEBUG GetComponent<MeshRenderer>().enabled = false; #endif break; } }
public static void Strip(pb_Object[] all) { for(int i = 0; i < all.Length; i++) { EditorUtility.DisplayProgressBar( "Stripping ProBuilder Scripts", "Working over " + all[i].id + ".", ((float)i / all.Length)); Mesh m = pbUtil.DeepCopyMesh(all[i].msh); m.name = all[i].msh.name; GameObject go = all[i].gameObject; DestroyImmediate(all[i]); if(go.GetComponent<pb_Entity>()) DestroyImmediate(go.GetComponent<pb_Entity>()); go.GetComponent<MeshFilter>().sharedMesh = m; if(go.GetComponent<MeshCollider>()) go.GetComponent<MeshCollider>().sharedMesh = m; } EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Strip ProBuilder Scripts", "Successfully stripped out all ProBuilder components.", "Okay"); }
/** * \brief Returns all connected faces. */ public static List <pb_Face> GetConnectedFaces(pb_Object pb, pb_Face[] selFaces) { int len = selFaces.Length; List <pb_Face> faces = new List <pb_Face>(); pb_IntArray[] sharedIndices = pb.sharedIndices; pb_Edge[][] sharedEdges = new pb_Edge[len][]; for (int i = 0; i < len; i++) { sharedEdges[i] = pb_Edge.GetUniversalEdges(selFaces[i].edges, sharedIndices); } for (int i = 0; i < pb.faces.Length; i++) { pb_Edge[] faceEdges = pb_Edge.GetUniversalEdges(pb.faces[i].edges, sharedIndices); for (int j = 0; j < len; j++) { int ind = faceEdges.ContainsMatch(sharedEdges[j]); if (ind > -1) { faces.Add(pb.faces[i]); } } } return(faces); }
/** * Returns all faces that share an edge with originFace */ public static List <pb_Face> GetConnectedFaces(pb_Object pb, pb_Face originFace) { List <pb_Face> faces = new List <pb_Face>(); pb_IntArray[] sharedIndices = pb.sharedIndices; pb_Edge[] sharedEdges = pb_Edge.GetUniversalEdges(originFace.edges, sharedIndices); for (int i = 0; i < pb.faces.Length; i++) { if (pb.faces[i] == originFace) { continue; } pb_Edge[] faceEdges = pb_Edge.GetUniversalEdges(pb.faces[i].edges, sharedIndices); int ind = faceEdges.ContainsMatch(sharedEdges); if (ind > -1) { faces.Add(pb.faces[i]); } } return(faces); }
void RefreshSelectedFacePreview() { pb_Face face = new pb_Face(currentSelection.face); // Copy the currently selected face face.ShiftIndicesToZero(); // Shift the selected face indices to zero // Copy the currently selected vertices in world space. // World space so that we don't have to apply transforms // to match the current selection. Vector3[] verts = currentSelection.pb.VerticesInWorldSpace(currentSelection.face.distinctIndices); // Now go through and move the verts we just grabbed out about .1m from the original face. Vector3 normal = pb_Math.Normal(verts); for (int i = 0; i < verts.Length; i++) { verts[i] += normal.normalized * .01f; } if (preview) { Destroy(preview.gameObject); } preview = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[1] { face }); preview.SetFaceMaterial(preview.faces, previewMaterial); preview.ToMesh(); preview.Refresh(); }
public static void UnwrapSphericalPB(pb_Object pb, int[] indices) { Vector2[] uv = pb.uv; Vector3[] v = pb.vertices; Vector3 cen = pb.msh.bounds.center; float radius = Vector3.Distance(pb.msh.bounds.extents, cen); for (int i = 0; i < indices.Length; i++) { Vector3 p = (v[i] - cen).normalized; uv[i].y = Mathf.Acos(p.z / radius) / Mathf.PI; if (p.y >= 0) { uv[i].x = Mathf.Acos(p.x / (radius * Mathf.Sin(Mathf.PI * (uv[i].y)))) / (Mathf.PI * 2f); } else { uv[i].x = (Mathf.PI + Mathf.Acos(p.x / (radius * Mathf.Sin(Mathf.PI * (uv[i].y))))) / (Mathf.PI * 2f); } } SplitUVs(pb, indices); pb.SetUV(uv); }
void Start() { // Create a new ProBuilder cube to work with. pb = ProBuilder.CreatePrimitive(Shape.Cube); // Because of the way colors are stored (one color per-index in triangle array), // we have to keep track of what color belongs to what index. A real pain, I am // aware. This will be changed in the future - because it is a terrible method. Dictionary<int, Color32> vertexColors = new Dictionary<int, Color32>(); // Cycle through each unique vertex in the cube (8 total), and assign a color // to the index in the sharedIndices array. int si_len = pb.sharedIndices.Length; for(int i = 0; i < si_len; i++) { vertexColors.Add(i, HSVtoRGB( (i/(float)si_len) * 360f, 1f, 1f) ); } // Now go through each face (vertex colors are stored the pb_Face class) and // assign the pre-calculated index color to each index in the triangles array. foreach(pb_Face face in pb.faces) { Color32[] faceColors = new Color32[face.indices.Length]; for(int i = 0; i < face.indices.Length; i++) { int index = pb.sharedIndices.IndexOf(face.indices[i]); faceColors[i] = vertexColors[index]; } face.SetColors(faceColors); } // In order for these changes to take effect, you must refresh the mesh // object. pb.Refresh(); }
/** * Provided two faces, this method will attempt to project @f2 and align its size, rotation, and position * to match the shared edge on f1. Returns true on success, false otherwise. */ public static bool AutoStitch(pb_Object pb, pb_Face f1, pb_Face f2) { // Cache shared indices (we gon' use 'em a lot) Dictionary <int, int> sharedIndices = pb.sharedIndices.ToDictionary(); for (int i = 0; i < f1.edges.Length; i++) { // find a matching edge int ind = f2.edges.IndexOf(f1.edges[i], sharedIndices); if (ind > -1) { // First, project the second face pbUVOps.ProjectFacesAuto(pb, new pb_Face[] { f2 }); // Use the first first projected as the starting point // and match the vertices f1.manualUV = true; f2.manualUV = true; f1.textureGroup = -1; f2.textureGroup = -1; AlignEdges(pb, f1, f2, f1.edges[i], f2.edges[ind]); return(true); } } // no matching edge found return(false); }
public void SetHighlight(pb_Object pb, bool isHighlighted) { Mesh m = null; if (m_Highlights.TryGetValue(pb, out m)) { if (!isHighlighted) { U.Object.Destroy(m); m_Highlights.Remove(pb); } else { GenerateBounds(m, pb.msh.bounds); } } else { if (isHighlighted) { m = new Mesh(); GenerateBounds(m, pb.msh.bounds); m_Highlights.Add(pb, m); } } }
void Start() { // Create a new ProBuilder cube to work with. pb = pb_Shape_Generator.CubeGenerator(Vector3.one); // Cycle through each unique vertex in the cube (8 total), and assign a color // to the index in the sharedIndices array. int si_len = pb.sharedIndices.Length; Color[] vertexColors = new Color[si_len]; for (int i = 0; i < si_len; i++) { vertexColors[i] = HSVtoRGB((i / (float)si_len) * 360f, 1f, 1f); } // Now go through each face (vertex colors are stored the pb_Face class) and // assign the pre-calculated index color to each index in the triangles array. Color[] colors = pb.colors; for (int CurSharedIndex = 0; CurSharedIndex < pb.sharedIndices.Length; CurSharedIndex++) { foreach (int CurIndex in pb.sharedIndices[CurSharedIndex].array) { colors[CurIndex] = vertexColors[CurSharedIndex]; } } pb.SetColors(colors); // In order for these changes to take effect, you must refresh the mesh // object. pb.Refresh(); }
/** * \brief Rebuild targets if they can't be refreshed. */ private static void StripAndProBuilderize(pb_Object[] targets, bool interactive = true) { for (int i = 0; i < targets.Length; i++) { if (interactive) { EditorUtility.DisplayProgressBar( "Refreshing ProBuilder Objects", "Reshaping pb_Object " + targets[i].id + ".", ((float)i / targets.Length)); } pb_Object pb = targets[i]; try { pb.ToMesh(); pb.Refresh(); pb.Optimize(); } catch { if (pb.msh != null) { RebuildProBuilderMesh(pb); } } } if (interactive) { EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Rebuild ProBuilder Objects", "Successfully rebuilt " + targets.Length + " ProBuilder Objects", "Okay"); } }
// breaks a pb_object into a zillion* faces public static GameObject[] ExplodeObject(pb_Object pb) { // disable 'ze donor pb.gameObject.SetActive(false); GameObject[] pieces = new GameObject[pb.faces.Length]; // extract mesh and material information for every face, and assign it to a gameobject for(int i = 0; i < pieces.Length; i++) { Mesh m = new Mesh(); m.vertices = pb.GetVertices(pb.faces[i]); m.triangles = new int[6] {0,1,2, 1,3,2}; m.normals = pb.GetNormals(pb.faces[i]); m.uv = pb.GetUVs(pb.faces[i]); m.RecalculateBounds(); GameObject go = new GameObject(); go.transform.position = pb.transform.position + pb_Math.PlaneNormal(m.vertices).normalized * .3f; go.transform.localRotation = pb.transform.localRotation; go.AddComponent<MeshFilter>().sharedMesh = m; go.AddComponent<MeshRenderer>().sharedMaterial = pb.GetMaterial(pb.faces[i]); pieces[i] = go; } return pieces; }
/** * @todo - Remove this and implement a pb_Selection class that can easily be recorded for undo without * doing this weird hcak. */ public static void RecordSelection(pb_Object[] pb, string msg) { if( pb.Sum(x => x.SelectedTriangleCount) > 256 ) RegisterCompleteObjectUndo(pb, msg); else RecordObjects(pb, msg); }
void Start() { // Create a new ProBuilder cube to work with. pb = pb_ShapeGenerator.CubeGenerator(Vector3.one); // Cycle through each unique vertex in the cube (8 total), and assign a color // to the index in the sharedIndices array. int si_len = pb.sharedIndices.Length; Color[] vertexColors = new Color[si_len]; for(int i = 0; i < si_len; i++) { vertexColors[i] = HSVtoRGB( (i/(float)si_len) * 360f, 1f, 1f); } // Now go through each face (vertex colors are stored the pb_Face class) and // assign the pre-calculated index color to each index in the triangles array. Color[] colors = pb.colors; for(int CurSharedIndex = 0; CurSharedIndex < pb.sharedIndices.Length; CurSharedIndex++) { foreach(int CurIndex in pb.sharedIndices[CurSharedIndex].array) { colors[CurIndex] = vertexColors[CurSharedIndex]; } } pb.SetColors(colors); // In order for these changes to take effect, you must refresh the mesh // object. pb.Refresh(); }
/** * \brief Duplicates and mirrors the passed pb_Object. * @param pb The donor pb_Object. * @param axe The axis to mirror the object on. * \returns The newly duplicated pb_Object. * \sa ProBuilder.Axis */ public static pb_Object Mirror(pb_Object pb, Vector3 scale) { pb_Object p = ProBuilder.CreateObjectWithObject(pb); p.MakeUnique(); p.transform.parent = pb.transform.parent; p.transform.position = pb.transform.position; p.transform.localRotation = pb.transform.localRotation; Vector3 lScale = p.gameObject.transform.localScale; p.transform.localScale = new Vector3(lScale.x * scale.x, lScale.y * scale.y, lScale.z * scale.z); // if flipping on an odd number of axes, flip winding order if( (scale.x * scale.y * scale.z) < 0) p.ReverseWindingOrder(p.faces); p.FreezeScaleTransform(); p.Refresh(); p.GenerateUV2(true); pb_Editor_Utility.InitObjectFlags(p, ColliderType.MeshCollider, pb.entity.entityType); return p; }
/** * \brief This is how we figure out what face is clicked. */ public bool FaceCheck(Vector3 pos) { Ray ray = Camera.main.ScreenPointToRay(pos); RaycastHit hit; if (Physics.Raycast(ray.origin, ray.direction, out hit)) { pb_Object hitpb = hit.transform.gameObject.GetComponent <pb_Object>(); if (hitpb == null) { return(false); } Mesh m = hitpb.msh; int[] tri = new int[3] { m.triangles[hit.triangleIndex * 3 + 0], m.triangles[hit.triangleIndex * 3 + 1], m.triangles[hit.triangleIndex * 3 + 2] }; currentSelection.pb = hitpb; return(hitpb.FaceWithTriangle(tri, out currentSelection.face)); } return(false); }
/** * \brief Duplicates and mirrors the passed pb_Object. * @param pb The donor pb_Object. * @param axe The axis to mirror the object on. * \returns The newly duplicated pb_Object. * \sa ProBuilder.Axis */ public static pb_Object Mirror(pb_Object pb, Vector3 scale) { pb_Object p = ProBuilder.CreateObjectWithObject(pb); p.MakeUnique(); p.transform.parent = pb.transform.parent; p.transform.position = pb.transform.position; p.transform.localRotation = pb.transform.localRotation; Vector3 lScale = p.gameObject.transform.localScale; p.transform.localScale = new Vector3(lScale.x * scale.x, lScale.y * scale.y, lScale.z * scale.z); // if flipping on an odd number of axes, flip winding order if ((scale.x * scale.y * scale.z) < 0) { p.ReverseWindingOrder(p.faces); } p.FreezeScaleTransform(); p.Refresh(); p.GenerateUV2(true); pb_Editor_Utility.InitObjectFlags(p, ColliderType.MeshCollider, pb.entity.entityType); return(p); }
void RefreshSelectedFacePreview() { // Copy the currently selected vertices in world space. // World space so that we don't have to apply transforms // to match the current selection. Vector3[] verts = currentSelection.pb.VerticesInWorldSpace(currentSelection.face.indices); // face.indices == triangles, so wind the face to match int[] indices = new int[verts.Length]; for (int i = 0; i < indices.Length; i++) { indices[i] = i; } // Now go through and move the verts we just grabbed out about .1m from the original face. Vector3 normal = pb_Math.Normal(verts); for (int i = 0; i < verts.Length; i++) { verts[i] += normal.normalized * .01f; } if (preview) { Destroy(preview.gameObject); } preview = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[] { new pb_Face(indices) }); preview.SetFaceMaterial(preview.faces, previewMaterial); preview.ToMesh(); preview.Refresh(); }
public static bool HiddenFace(pb_Object pb, pb_Face q, float dist) { // Grab the face normal Vector3 dir = pbUtil.PlaneNormal(pb.VerticesInWorldSpace(q)); // And also the center of the face Vector3 orig = pb.QuadCenter(q); // Case a ray from the center of the face out in the normal direction. // If an object is hit, return true (that this face is hidden), otherwise // return false. This is pretty simplistic and doesn't account for a lot // of "gotchas", but it ought to serve as a fairly decent jumping off point // for NoDrawing a dense level. RaycastHit hit; if(Physics.Raycast(orig, dir, out hit, dist)) { // We've hit something. Now check to see if it is a ProBuilder object, // and if so, make sure it's a visblocking brush. pb_Entity ent = hit.transform.GetComponent<pb_Entity>(); if(ent != null) { if(ent.entityType == ProBuilder.EntityType.Brush || ent.entityType == ProBuilder.EntityType.Occluder) return true; // it's a brush, blocks vision, return true else return false; // not a vis blocking brush } } // It ain't a ProBuilder object of the entity type Brush or Occluder (world brush) return false; }
/** * Iterates through face edges and builds a list using the opposite edge. * @todo Lots of slow stuff in here */ public static pb_Edge[] GetEdgeRing(pb_Object pb, pb_Edge[] edges) { List <pb_Edge> usedEdges = new List <pb_Edge>(); Dictionary <int, int> lookup = pb.sharedIndices.ToDictionary(); foreach (pb_Edge e in edges) { List <pb_Face> origFace; List <pb_Edge> origEdge; // ValidFaceAndEdgeWithEdge will return false if < 1 face and edge combo is found. if (!ValidFaceAndEdgeWithEdge(pb, e, lookup, out origFace, out origEdge)) { continue; } // Only add the initial edge once usedEdges.Add(origEdge[0]); pb_Face opFace; pb_Edge opEdge; bool superBreak = false; for (int i = 0; i < origFace.Count; i++) { pb_Face curFace = origFace[i]; pb_Edge curEdge = origEdge[i]; while (GetOppositeEdge(pb, curFace, curEdge, lookup, out opFace, out opEdge)) { curFace = opFace; curEdge = opEdge; usedEdges.Add(curEdge); if (curFace == null) { break; } if (curFace == origFace[i]) { superBreak = true; break; } } if (superBreak) { break; } } } pb_Edge[] dist = pb_Edge.GetUniversalEdges(usedEdges.ToArray(), lookup); return(pb_Edge.GetLocalEdges_Fast(dist.Distinct().ToArray(), pb.sharedIndices)); }
/** * When a new object is created this function is called with a reference to the pb_Object * last built. */ static void OnProBuilderObjectCreated(pb_Object pb) { pb_UnwrapParameters up = pb.unwrapParameters; up.hardAngle = 88f; // range: 1f, 180f up.packMargin = 15f; // range: 1f, 64f up.angleError = 30f; // range: 1f, 75f up.areaError = 15f; // range: 1f, 75f }
public void OnEnable() { ent = (pb_Entity)target; if(ent != null) pb = (pb_Object)ent.transform.GetComponent<pb_Object>(); // if(ent.colliderType != pb_Entity.ColliderType.Upgraded) ent.GenerateCollisions(); }
/** * Collapse shared vertices to a single vertex on the mesh object. Does not affect * pb_Object vertices. */ public static void CollapseSharedVertices(pb_Object pb) { List<List<int>> merge = pb_MeshUtility.FindDuplicateVertices(pb); Mesh m = pb.msh; pb_MeshUtility.MergeVertices(merge, ref m); }
/** * Collapse shared vertices to a single vertex on the mesh object. Does not affect * pb_Object vertices. */ public static void CollapseSharedVertices(pb_Object pb) { List <List <int> > merge = pb_MeshUtility.FindDuplicateVertices(pb); Mesh m = pb.msh; pb_MeshUtility.MergeVertices(merge, ref m); }
void OnSelectionUpdate(pb_Object[] selection) { try { foreach(pb_Object pb in selection) DrawElements(pb); } catch {} }
void ConeGUI(bool doGenShape) { #if FREE || TORNADO_TWINS GUI.enabled = false; #endif cone_radius = EditorGUILayout.FloatField("Radius", cone_radius); cone_height = EditorGUILayout.FloatField("Height", cone_height); cone_subdivAxis = EditorGUILayout.IntField("Subdivisions Axis", cone_subdivAxis); if (cone_radius < .1f) { cone_radius = .1f; } if (cone_height < .1f) { cone_height = .1f; } pipe_subdivHeight = (int)Mathf.Clamp(pipe_subdivHeight, 1f, 32f); pipe_thickness = Mathf.Clamp(pipe_thickness, .01f, cone_radius - .01f); cone_subdivAxis = (int)Mathf.Clamp(cone_subdivAxis, 3f, 32f); if (showPreview && (GUI.changed || initPreview)) { SetPreviewObject( pb_Shape_Generator.ConeGenerator( cone_radius, cone_height, cone_subdivAxis )); } if (doGenShape) { pb_Object pb = pb_Shape_Generator.ConeGenerator( cone_radius, cone_height, cone_subdivAxis ); if (userMaterial) { pb.SetFaceMaterial(pb.faces, userMaterial); } pb_Editor_Utility.InitObjectFlags(pb, pb_Preferences_Internal.GetEnum <ColliderType>(pb_Constant.pbDefaultCollider), EntityType.Detail); pb_Editor_Utility.SetPivotAndSnapWithPref(pb, null); AlignWithPreviewObject(pb.gameObject); DestroyPreviewObject(); showPreview = false; } #if FREE || TORNADO_TWINS GUI.enabled = true; #endif }
static void Triangulate(pb_Object pb) { Vector3[] v = pb.vertices; Vector2[] u = pb.msh.uv; int triangleCount = pb.msh.triangles.Length; if(triangleCount == v.Length) { Debug.LogWarning("We can't pull over any further!\npb_Object: " + pb.name + " is already triangulated."); } int vertexCount = triangleCount; int faceCount = vertexCount / 3; Vector3[] tri_vertices = new Vector3[vertexCount]; Vector2[] tri_uvs = new Vector2[vertexCount]; pb_Face[] tri_faces = new pb_Face[faceCount]; int n = 0, f = 0; foreach(pb_Face face in pb.faces) { int[] indices = face.indices; for(int i = 0; i < indices.Length; i+=3) { tri_vertices[n+0] = v[indices[i+0]]; tri_vertices[n+1] = v[indices[i+1]]; tri_vertices[n+2] = v[indices[i+2]]; tri_uvs[n+0] = u[indices[i+0]]; tri_uvs[n+1] = u[indices[i+1]]; tri_uvs[n+2] = u[indices[i+2]]; tri_faces[f++] = new pb_Face( new int[] { n+0, n+1, n+2 }, face.material, face.uv, face.smoothingGroup, face.textureGroup, // textureGroup -> force to manual uv mode face.elementGroup, face.manualUV, // manualUV face.color ); n += 3; } } pb.SetVertices(tri_vertices); pb.SetUV(tri_uvs); pb.SetFaces(tri_faces); pb.SetSharedIndices( pb_IntArrayUtility.ExtractSharedIndices(tri_vertices) ); pb.SetSharedIndicesUV( new pb_IntArray[0] ); }
/** * \brief Draws dimensions of passed pb_Object in screen space. Must be called from OnSceneGUI */ public static void DrawDimensions(pb_Object pb) { Rect r = pb_Editor_Utility.GUIRectWithObject(pb.gameObject); Rect info = new Rect(r.x+r.width, r.y, 400, 300); Handles.BeginGUI(); // Handles.DrawLine( new Vector2(r.x, r.y), new Vector2(r.x+r.width, r.y) ); // Handles.DrawLine( new Vector2(r.x+r.width, r.y), new Vector2(r.x+r.width, r.y+r.height) ); GUI.Label(info, "Size: " + pb.gameObject.GetComponent<Renderer>().bounds.size); Handles.EndGUI(); }
// static pb_Profiler profiler = new pb_Profiler("pb_Menu_Commands"); #endif #region Object Level #if !PROTOTYPE /** * Combine selected pb_Objects to a single object. * ProBuilder only. */ public static void MenuMergeObjects(pb_Object[] selected) { if(selected.Length < 2) { pb_Editor_Utility.ShowNotification("Must Select 2+ Objects"); return; } int option = EditorUtility.DisplayDialogComplex( "Save or Delete Originals?", "Saved originals will be deactivated and hidden from the Scene, but available in the Hierarchy.", "Merge Delete", // 0 "Merge Save", // 1 "Cancel"); // 2 pb_Object pb = null; if(option == 2) return; if( pbMeshOps.CombineObjects(selected, out pb) ) { pb_Editor_Utility.SetEntityType(selected[0].GetComponent<pb_Entity>().entityType, pb.gameObject); pb_Lightmap_Editor.SetObjectUnwrapParamsToDefault(pb); pb.Optimize(); pb.gameObject.name = "pb-MergedObject" + pb.id; switch(option) { case 0: // Delete donor objects for(int i = 0; i < selected.Length; i++) { if(selected[i] != null) pbUndo.DestroyImmediate(selected[i].gameObject, "Delete Merged Objects"); } break; case 1: foreach(pb_Object sel in selected) sel.gameObject.SetActive(false); break; } pbUndo.RegisterCreatedObjectUndo(pb.gameObject, "Merge Objects"); Selection.activeTransform = pb.transform; } if(editor) editor.UpdateSelection(); }
/** * Sets things in motion! */ public void Start() { pb = GetComponent<pb_Object>(); // When detaching, we're going right into a turn so we won't get the opportunity to set this in the usual Turn() spot. // Set it here. If this is the first segment in a pipe, this value will be overwritten by Turn(). movingFaces = new pb_Face[1] { pb.faces[0] }; selectedTriangles = pb_Face.AllTriangles(movingFaces); nrm = pb_Math.Normal(pb, movingFaces[0]); Turn(); }
/** * Returns all faces connected to the passed edge. */ public static List<pb_Face> GetConnectedFaces(pb_Object pb, pb_Edge edge) { List<pb_Face> faces = new List<pb_Face>(); pb_IntArray[] sharedIndices = pb.sharedIndices; foreach(pb_Face f in pb.faces) { if(f.edges.IndexOf(edge, sharedIndices) > -1) faces.Add(f); } return faces; }
public static Vector3 Normal(pb_Object pb, pb_Face face) { Vector3 p0 = pb.vertices[face.indices[0]]; Vector3 p1 = pb.vertices[face.indices[1]]; Vector3 p2 = pb.vertices[face.indices[2]]; Vector3 cross = Vector3.Cross(p1 - p0, p2 - p0); if (cross.magnitude < Mathf.Epsilon) return new Vector3(0f, 0f, 0f); // bad triangle else { return cross.normalized; } }
private static void SetPivot(pb_Object pbo, int[] testIndices) { Vector3 center = Vector3.zero; foreach (Vector3 vector in pbo.VerticesInWorldSpace(testIndices)) { center += vector; } center /= testIndices.Length; Vector3 dir = (pbo.transform.position - center); pbo.transform.position = center; pbo.TranslateVertices(pbo.uniqueIndices, dir); }
public pb_SerializableObject(pb_Object pb) { this.vertices = pb.vertices; // Make sure the mesh is valid, and in sync with current pb_Object if(pb.msh == null || pb.msh.vertexCount != pb.vertexCount) { pb_UpgradeKitUtils.RebuildMesh(pb); } this.uv = pb.msh != null ? pb.msh.uv : null; if(pb.msh != null && pb.msh.colors != null && pb.msh.colors.Length == pb.vertexCount) { this.color = pb.msh.colors; } else { this.color = new Color[pb.vertexCount]; for(int i = 0; i < this.color.Length; i++) this.color[i] = Color.white; } this.faces = pb.faces; this.sharedIndices = (int[][])pb.GetSharedIndices().ToArray(); PropertyInfo prop_uv = pb.GetType().GetProperty("sharedIndicesUV", BindingFlags.Instance | BindingFlags.Public); if(prop_uv != null) { var val = prop_uv.GetValue(pb, null); if(val != null) { pb_IntArray[] sharedUvs = (pb_IntArray[])val; this.sharedIndicesUV = (int[][])sharedUvs.ToArray(); } else { this.sharedIndicesUV = new int[0][]; } } else { this.sharedIndicesUV = new int[0][]; } PropertyInfo prop_userCollisions = pb.GetType().GetProperty("userCollisions", BindingFlags.Instance | BindingFlags.Public); userCollisions = prop_userCollisions == null ? false : (bool) prop_userCollisions.GetValue(pb, null); }
/** * \brief Duplicates and returns the passed pb_Object. * @param pb The pb_Object to duplicate. * \returns A unique copy of the passed pb_Object. */ public static pb_Object InitWithObject(pb_Object pb) { Vector3[] v = new Vector3[pb.vertexCount]; System.Array.Copy(pb.vertices, v, pb.vertexCount); pb_Face[] f = new pb_Face[pb.faces.Length]; for(int i = 0; i < f.Length; i++) f[i] = new pb_Face(pb.faces[i]); pb_Object p = CreateInstanceWithVerticesFacesSharedIndices(v, f, pb.GetSharedIndices()); p.gameObject.name = pb.gameObject.name + "-clone"; return p; }
public void OnEnable() { if(EditorApplication.isPlayingOrWillChangePlaymode) return; if(target is pb_Object) pb = (pb_Object)target; else return; ren = pb.gameObject.GetComponent<Renderer>(); // get all materials in use (as far as pb_Object knows) // if(Selection.activeTransform != pb.transform) //System.Array.IndexOf(Selection.transforms, pb.transform) < 0 ) // Unity drag and drop material always only sets the first sub-object material, so check that it's the same // if(ren.sharedMaterials.Length > 0) // { // Bugger.Log("OnEnable set face material"); // HashSet<Material> mats = new HashSet<Material>(); // foreach(pb_Face f in pb.faces) // mats.Add(f.material); // HashSet<Material> renMats = new HashSet<Material>(ren.sharedMaterials); // if(!renMats.SetEquals(mats)) // { // pbUndo.RecordObjects(pbUtil.GetComponents<pb_Object>(Selection.transforms), "Set Face Materials"); // foreach(pb_Object pbs in pbUtil.GetComponents<pb_Object>(Selection.transforms)) // pbs.SetFaceMaterial(pbs.faces, ren.sharedMaterials[0]); // } // } #if UNITY_4 EditorUtility.SetSelectedWireframeHidden(ren, true); #else EditorUtility.SetSelectedWireframeHidden(ren, false); #endif pb.Verify(); pb.GenerateUV2(true); }
/** * \brief Duplicates and mirrors the passed pb_Object. * @param pb The donor pb_Object. * @param axe The axis to mirror the object on. * \returns The newly duplicated pb_Object. * \sa ProBuilder.Axis */ public static pb_Object Mirror(pb_Object pb, Vector3 scale) { pb_Object p = pb_Object.InitWithObject(pb); p.MakeUnique(); p.transform.parent = pb.transform.parent; p.transform.localRotation = pb.transform.localRotation; Vector3 lScale = p.gameObject.transform.localScale; p.transform.localScale = new Vector3(lScale.x * scale.x, lScale.y * scale.y, lScale.z * scale.z); // if flipping on an odd number of axes, flip winding order if( (scale.x * scale.y * scale.z) < 0) p.ReverseWindingOrder(p.faces); p.FreezeScaleTransform(); p.transform.localScale = pb.transform.localScale; Collider col = pb.GetComponent<Collider>(); ColliderType colType = ColliderType.None; if(col != null) { if(col is MeshCollider) colType = ColliderType.MeshCollider; else colType = ColliderType.BoxCollider; } pb_Editor_Utility.InitObjectFlags(p, colType, pb.GetComponent<pb_Entity>().entityType); p.ToMesh(); p.Refresh(); // InitObjectFlags runs ScreenCenter() p.transform.position = pb.transform.position; Undo.RegisterCreatedObjectUndo(p.gameObject, "Mirror Object"); return p; }
private static void SetPivot(pb_Object pbo, int[] testIndices, bool doSnap) { Vector3 center = Vector3.zero; foreach (Vector3 vector in pbo.VerticesInWorldSpace(testIndices)) { center += vector; } center /= testIndices.Length; if(doSnap) center = pb_Object.SnapValue(center, Vector3.one); Vector3 dir = (pbo.transform.position - center); pbo.transform.position = center; // the last bool param force disables snapping vertices pbo.TranslateVertices(pbo.uniqueIndices, dir, true); }
public static void Strip(pb_Object[] all) { for(int i = 0; i < all.Length; i++) { if( EditorUtility.DisplayCancelableProgressBar( "Stripping ProBuilder Scripts", "Working over " + all[i].id + ".", ((float)i / all.Length)) ) break; DoStrip(all[i]); } EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("Strip ProBuilder Scripts", "Successfully stripped out all ProBuilder components.", "Okay"); if(pb_Editor.instance) pb_Editor.instance.UpdateSelection(); }
public void OnEnable() { if(EditorApplication.isPlayingOrWillChangePlaymode) return; if(target is pb_Object) pb = (pb_Object)target; else return; ren = pb.gameObject.GetComponent<Renderer>(); EditorUtility.SetSelectedWireframeHidden(ren, editor != null); /* if Verify returns false, that means the mesh was rebuilt - so generate UV2 again */ foreach(pb_Object selpb in Selection.transforms.GetComponents<pb_Object>()) pb_Editor_Utility.VerifyMesh(selpb); }