void RefreshSelectedFacePreview() { pb_Face face = new pb_Face(currentSelection.face); // Copy the currently selected face face.ShiftIndicesToZero(); // Shift the selected face indices to zero Vector3[] verts = currentSelection.pb.VerticesInWorldSpace( currentSelection.face); // Copy the currently selected vertices in world space. // World space so that we don't have to apply transforms // to match the current selection. // Now go through and move the verts we just grabbed out about .1m from the original face. Vector3 normal = pb_Math.PlaneNormal(verts); for (int i = 0; i < verts.Length; i++) { verts[i] += normal.normalized * .01f; } if (preview) { Destroy(preview.gameObject); } preview = ProBuilder.CreateObjectWithVerticesFaces(verts, new pb_Face[1] { face }); preview.SetName("Preview"); preview.SetObjectMaterial(previewMaterial); }
/** * \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.SetName(p.GetName()+"-DUPLICATE-"); 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.FreezeScaleTransform(); EditorUtility.SetDirty(p); return(p); }
public static void Cube() { GameObject go = ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube); pb_Editor_Utility.SetEntityType(ProBuilder.EntityType.Brush, go); pb_Editor_Utility.ScreenCenter(go); }
/** * \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 OnGUI() { if (GUI.Button(new Rect(5, Screen.height - 25, 80, 20), "Reset")) { if (pb != null) { Destroy(pb.gameObject); } pb = (pb_Object)ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube).GetComponent <pb_Object>(); } }
/** * \brief Creates a new ProBuilder cube and sets it up with a concave MeshCollider. */ void SpawnCube() { // This creates a basic cube with ProBuilder features enabled. See the ProBuilder.Shape enum to // see all possible primitive types. pb_Object pb = (pb_Object)ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube).GetComponent <pb_Object>(); // The runtime component requires that a concave mesh collider be present in order for face selection // to work. pb.gameObject.AddComponent <MeshCollider>().convex = false; // Now set it to the currentSelection currentSelection = new pb_Selection(pb, null); }
private void SealExitWithADoor(ModuleConnector baseExit) { //Debug.Log("Couldn't find any possible combination. Sealing off the exit with a door"); var newModule = ProBuilder.Instantiate(DoorPrefab.gameObject, Vector3.zero, Quaternion.identity).GetComponent <Module>(); newModule.transform.parent = DungeonGameObject.transform; var doorExit = newModule.GetExits()[0]; MatchExits(baseExit, doorExit); baseExit.ConnectWith(doorExit); doorExit.ConnectWith(baseExit); }
public static pb_Object CubeGenerator(Vector3 size) { Vector3[] points = new Vector3[pb_Constant.TRIANGLES_CUBE.Length]; for (int i = 0; i < pb_Constant.TRIANGLES_CUBE.Length; i++) { points[i] = Vector3.Scale(pb_Constant.VERTICES_CUBE[pb_Constant.TRIANGLES_CUBE[i]], size); } pb_Object pb = ProBuilder.CreateObjectWithPoints(points); pb.SetName("Cube"); return(pb); }
public void OnGUI() { if (GUILayout.Button("Reset")) { Destroy(cube); for (int i = 0; i < pieces.Length; i++) { Destroy(pieces[i]); } cube = ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube).gameObject; } if (GUILayout.Button("Explode!!")) { pieces = ExplodeObject(cube.GetComponent <pb_Object>()); } }
private IEnumerator GenerateNewDungeonCo() { WaitForSeconds delay = null; if (UseDelay) { delay = new WaitForSeconds(GenerationDelay); } DungeonGameObject = new GameObject("Dungeon"); //Get the starting module and orient it var startModule = ProBuilder.Instantiate(RootModule, transform.position, transform.rotation).GetComponent <Module>(); startModule.transform.parent = DungeonGameObject.transform; //Get all the exits of the starting module var baseModuleExits = new List <ModuleConnector>(startModule.GetExits()); //Iterate through the number of iterations //Only allow "Open" modules for the initial iterations for (int iteration = 0; iteration < Iterations; iteration++) { var newExits = new List <ModuleConnector>(); var randomizedModules = new List <GameObject>(); //Loop through all the basemodule exits foreach (var baseModuleExit in baseModuleExits) { yield return(delay); //loop through the random list of available modules, until there is a valid candidate randomizedModules.Clear(); GetRandomizedModuleList(randomizedModules, ModulePrefabs, "Open"); GameObject newModuleGameObject = null; if (!CreateNewModule(baseModuleExit, randomizedModules, newExits, out newModuleGameObject)) { SealExitWithADoor(baseModuleExit); } } baseModuleExits = newExits; } StartCoroutine(ApplyFinalIterationCo(baseModuleExits)); }
/** * \brief Returns a pb_Object cone with the passed size. * @param radius Radius of the generated cone. * @param height How tall the cone will be. * @param subdivAxis How many subdivisions on the axis. * \returns New #pb_Object. */ public static pb_Object ConeGenerator( float radius, float height, int subdivAxis) { // template is outer ring - radius refers to outer ring always Vector3[] template = new Vector3[subdivAxis]; for (int i = 0; i < subdivAxis; i++) { Vector2 ct = pb_Math.PointInCircumference(radius, i * (360f / subdivAxis), Vector2.zero); template[i] = new Vector3(ct.x, 0f, ct.y); } List <Vector3> v = new List <Vector3>(); List <pb_Face> f = new List <pb_Face>(); // build sides for (int i = 0; i < subdivAxis; i++) { // side face v.Add(template[i]); v.Add((i < subdivAxis - 1) ? template[i + 1] : template[0]); v.Add(Vector3.up * height); // bottom face v.Add(template[i]); v.Add((i < subdivAxis - 1) ? template[i + 1] : template[0]); v.Add(Vector3.zero); } for (int i = 0; i < subdivAxis * 6; i += 6) { f.Add(new pb_Face(new int[3] { i + 2, i + 1, i + 0 })); f.Add(new pb_Face(new int[3] { i + 3, i + 4, i + 5 })); } pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(v.ToArray(), f.ToArray()); pb.SetName("Cone"); return(pb); }
public void CustomGUI(bool doGenShape) { #if FREE || TORNADO_TWINS GUI.enabled = false; #endif GUILayout.Label("Custom Geometry", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Vertices must be wound in faces, and counter-clockwise.\n(Think horizontally reversed Z)", MessageType.Info); scrollbar = GUILayout.BeginScrollView(scrollbar); verts = EditorGUILayout.TextArea(verts, GUILayout.MinHeight(160)); GUILayout.EndScrollView(); if (showPreview && (GUI.changed || initPreview)) { SetPreviewObject(ProBuilder.CreateObjectWithPoints(pbUtil.StringToVector3Array(verts))); } if (doGenShape) { if (verts.Length > 256) { Debug.Log("Whoa! Did you seriously type all those points!?"); } pb_Object pb = ProBuilder.CreateObjectWithPoints(pbUtil.StringToVector3Array(verts)); 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 }
public static void MenuCreateCube() { pb_Object pb = ProBuilder.CreatePrimitive(Shape.Cube); #if !PROTOTYPE Material mat = null; if (EditorPrefs.HasKey(pb_Constant.pbDefaultMaterial)) { mat = (Material)AssetDatabase.LoadAssetAtPath(EditorPrefs.GetString(pb_Constant.pbDefaultMaterial), typeof(Material)); } if (mat != null) { pb.SetFaceMaterial(pb.faces, mat); } #endif pb_Editor_Utility.InitObjectFlags(pb, pb_Preferences_Internal.GetEnum <ColliderType>(pb_Constant.pbDefaultCollider), EntityType.Detail); pb_Editor_Utility.SetPivotAndSnapWithPref(pb, null); }
public static pb_Object ProBuilderize(Transform t) { Mesh m = t.GetComponent <MeshFilter>().sharedMesh; pb_Face[] faces = new pb_Face[m.triangles.Length / 3]; int f = 0; for (int n = 0; n < m.subMeshCount; n++) { for (int i = 0; i < m.triangles.Length; i += 3) { faces[f] = new pb_Face( new int[3] { m.triangles[i + 0], m.triangles[i + 1], m.triangles[i + 2] }, t.GetComponent <MeshRenderer>().sharedMaterials[n], new pb_UV(), 0, Color.white ); f++; } } t.gameObject.SetActive(false); pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(m.vertices, faces); pb.SetName("FrankenMesh"); pb_Editor_Utility.SetEntityType(ProBuilder.EntityType.Detail, pb.gameObject); GameObject go = pb.gameObject; go.transform.position = t.position; go.transform.localRotation = t.localRotation; go.transform.localScale = t.localScale; pb.FreezeScaleTransform(); return(pb); }
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(); }
public void Start() { cube = ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube).gameObject; }
/** * \brief Returns a pb_Object pipe with the passed size. * @param radius Radius of the generated pipe. * @param height Height of the generated pipe. * @param thickness How thick the walls will be. * @param subdivAxis How many subdivisions on the axis. * @param subdivHeight How many subdivisions on the Y axis. * \returns New #pb_Object. */ public static pb_Object PipeGenerator( float radius, float height, float thickness, int subdivAxis, int subdivHeight) { // template is outer ring - radius refers to outer ring always Vector2[] templateOut = new Vector2[subdivAxis]; Vector2[] templateIn = new Vector2[subdivAxis]; for (int i = 0; i < subdivAxis; i++) { templateOut[i] = pb_Math.PointInCircumference(radius, i * (360f / subdivAxis), Vector2.zero); templateIn[i] = pb_Math.PointInCircumference(radius - thickness, i * (360f / subdivAxis), Vector2.zero); } List <Vector3> v = new List <Vector3>(); subdivHeight += 1; // build out sides Vector2 tmp, tmp2, tmp3, tmp4; for (int i = 0; i < subdivHeight; i++) { // height subdivisions float y = i * (height / subdivHeight); float y2 = (i + 1) * (height / subdivHeight); for (int n = 0; n < subdivAxis; n++) { tmp = templateOut[n]; tmp2 = n < (subdivAxis - 1) ? templateOut[n + 1] : templateOut[0]; // outside quads Vector3[] qvo = new Vector3[4] { new Vector3(tmp2.x, y, tmp2.y), new Vector3(tmp.x, y, tmp.y), new Vector3(tmp2.x, y2, tmp2.y), new Vector3(tmp.x, y2, tmp.y) }; // inside quad tmp = templateIn[n]; tmp2 = n < (subdivAxis - 1) ? templateIn[n + 1] : templateIn[0]; Vector3[] qvi = new Vector3[4] { new Vector3(tmp.x, y, tmp.y), new Vector3(tmp2.x, y, tmp2.y), new Vector3(tmp.x, y2, tmp.y), new Vector3(tmp2.x, y2, tmp2.y) }; v.AddRange(qvo); v.AddRange(qvi); } } // build top and bottom for (int i = 0; i < subdivAxis; i++) { tmp = templateOut[i]; tmp2 = (i < subdivAxis - 1) ? templateOut[i + 1] : templateOut[0]; tmp3 = templateIn[i]; tmp4 = (i < subdivAxis - 1) ? templateIn[i + 1] : templateIn[0]; // top Vector3[] tpt = new Vector3[4] { new Vector3(tmp2.x, height, tmp2.y), new Vector3(tmp.x, height, tmp.y), new Vector3(tmp4.x, height, tmp4.y), new Vector3(tmp3.x, height, tmp3.y) }; // top Vector3[] tpb = new Vector3[4] { new Vector3(tmp.x, 0f, tmp.y), new Vector3(tmp2.x, 0f, tmp2.y), new Vector3(tmp3.x, 0f, tmp3.y), new Vector3(tmp4.x, 0f, tmp4.y), }; v.AddRange(tpb); v.AddRange(tpt); } pb_Object pb = ProBuilder.CreateObjectWithPoints(v.ToArray()); pb.SetName("Pipe"); return(pb); }
/** * The only scenario where CreateNewModule would return false, is if there was no way to generate a module, so we have to seal it off with a door */ private bool CreateNewModule(ModuleConnector baseExit, List <GameObject> availableModulePrefabs, List <ModuleConnector> newExits, out GameObject moduleGameObject) { bool foundExit = false; bool foundModule = false; ModuleConnector newModuleExit = null; ModuleConnector[] newModuleExits = null; moduleGameObject = null; Module newModule = null; foreach (var newModulePrefab in availableModulePrefabs) { //Create the new module prefab newModule = ProBuilder.Instantiate(newModulePrefab, Vector3.zero, Quaternion.identity).GetComponent <Module>(); newModule.transform.parent = DungeonGameObject.transform; newModuleExits = newModule.GetExits(); Util.ShuffleArray(newModuleExits); for (var i = 0; i < newModuleExits.Count(); i++) { newModuleExit = newModuleExits[i]; //Match the exits MatchExits(baseExit, newModuleExit); //Letting a full frame go by so we can do a collision check if (CollisionCheck(newModule, baseExit)) { foundModule = true; foundExit = true; break; } } //We've tried every exit combination with this module, get a new module if (!foundExit) { Destroy(newModule.gameObject); continue; } //if we've reached here, we have found a suitable exit with a suitable module, or we have not found anything suitable. break; } //We haven't found anything useful. Just make a door, and find another baseModuleExit if (!foundModule) { return(false); } //the new module was received. All is good. Connect with the base module exit. Find another baseModuleExit to connect with baseExit.ConnectWith(newModuleExit); newModuleExit.ConnectWith(baseExit); if (newExits != null) { newExits.AddRange(newModuleExits.Where(e => e != newModuleExit)); } CameraPortal cameraPortal = (CameraPortal)newModule.gameObject.GetComponentInChildren(typeof(CameraPortal)); if (cameraPortal != null) { Portals.Add(cameraPortal); } moduleGameObject = newModule.gameObject; return(true); }
/** * \brief Returns a pb_Object prism with the passed size. * @param size Size to apply to generated object. * \returns New #pb_Object. */ public static pb_Object PrismGenerator(Vector3 size) { Vector3[] template = new Vector3[6] { Vector3.Scale(new Vector3(-.5f, 0f, -.5f), size), Vector3.Scale(new Vector3(.5f, 0f, -.5f), size), Vector3.Scale(new Vector3(0f, .5f, -.5f), size), Vector3.Scale(new Vector3(-.5f, 0f, .5f), size), Vector3.Scale(new Vector3(0.5f, 0f, .5f), size), Vector3.Scale(new Vector3(0f, .5f, .5f), size) }; Vector3[] v = new Vector3[18] { template[0], // 0 front template[1], // 1 template[2], // 2 template[1], // 3 right side template[4], // 4 template[2], // 5 template[5], // 6 template[4], // 7 back side template[3], // 8 template[5], // 9 template[3], // 10 left side template[0], // 11 template[5], // 12 template[2], // 13 template[0], // 14 // bottom template[1], // 15 template[3], // 16 template[4] // 17 }; pb_Face[] f = new pb_Face[5] { new pb_Face(new int[3] { 2, 1, 0 }), // x new pb_Face(new int[6] { 5, 4, 3, 5, 6, 4 }), // x new pb_Face(new int[3] { 9, 8, 7 }), new pb_Face(new int[6] { 12, 11, 10, 12, 13, 11 }), new pb_Face(new int[6] { 14, 15, 16, 15, 17, 16 }) }; pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(v, f); pb.RebuildFaceCaches(); pb.SetName("Prism"); return(pb); }
void Awake() { pb = (pb_Object)ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube).GetComponent <pb_Object>(); }
void Update() { mPos_screen = Input.mousePosition; // If mouse is in the menu, ignore any clicks Vector2 mPos_gui = new Vector2(mPos_screen.x, Screen.height - mPos_screen.y); if (prefWindow.Contains(mPos_gui)) { return; } // If left click detected, instantiate the selected prefab where the mouse clicked (lock Z to 0) if (Input.GetMouseButtonUp(0)) { // grab mouse position in world space Vector3 mPos_world = Camera.main.ScreenToWorldPoint(new Vector3( mPos_screen.x, mPos_screen.y, Camera.main.transform.position.x)); // for some reason I decided to set the cube up on the x axis? GameObject myInstantiatedObject; switch (objectToInstantiate) { case ObjectSelectionOptions.Prefab: // Use ProBuilder.Instantiate(GameObject) to build cube. This force rebuilds the mesh // immediately. It is also safe to use with non-ProBuilder objects, and will behave // exactly like GameObject.Instantiate() if no pb_Object type is found. myInstantiatedObject = ProBuilder.Instantiate(probuilderPrefab, Vector3.zero, Quaternion.identity); break; ///* These demonstrate how to instantiate ProBuilder Primitive Types ///* (called 'Shapes' to differentiate from UnityEngine.PrimitiveType). case ObjectSelectionOptions.Cube: // Using the basic Shape instantiation, build a cube. CreatePrimitive() returns a // pb_Object, so get the GameObject after instantiation. pb_Object pb = ProBuilder.CreatePrimitive(ProBuilder.Shape.Cube); // Cubes alone are a little boring, so let's add some color to it Color[] cubeColors = new Color[6] { Color.green, Color.red, Color.cyan, Color.blue, Color.yellow, Color.magenta }; int i = 0; foreach (pb_Face face in pb.faces) { pb.SetFaceColor(face, cubeColors[i++]); } myInstantiatedObject = pb.gameObject; // Cube gets a BoxCollider myInstantiatedObject.gameObject.AddComponent <BoxCollider>(); break; case ObjectSelectionOptions.Cylinder: // ProBuilder also offers an extended interface for creating objects with // parameters. "ProBuilder.CreatePrimitive(ProBuilder.Shape.Cylinder);" // would also work here. See the pb_Shape docs for full lists with params. // axisDivisions, radius, height, heightCuts myInstantiatedObject = pb_Shape.CylinderGenerator(12, .7f, .5f, 0).gameObject; // A convex MeshCollider suits a Cylinder nicely myInstantiatedObject.gameObject.AddComponent <MeshCollider>().convex = true; break; case ObjectSelectionOptions.Pipe: // ProBuilder also offers an extended interface for creating objects with // parameters. "ProBuilder.CreatePrimitive(ProBuilder.Shape.Cylinder);" // would also work here. See the pb_Shape docs for full lists with params. // axisDivisions, radius, height, heightCuts // float radius, float height, float thickness, int subdivAxis, int subdivHeight) myInstantiatedObject = pb_Shape.PipeGenerator(1f, 1f, .3f, 8, 0).gameObject; // A convex MeshCollider suits a Pipe nicely myInstantiatedObject.gameObject.AddComponent <MeshCollider>().convex = true; break; default: return; } // Move instantiated object to mouse position myInstantiatedObject.transform.position = mPos_world; // Add some rotation, cause that's fun myInstantiatedObject.transform.localRotation = Quaternion.Euler( Random.Range(0f, 360f), Random.Range(0f, 360f), Random.Range(0f, 360f)); // Get some physics up in here myInstantiatedObject.AddComponent <Rigidbody>(); // Add this to the list of instantiated gameObjects so we can remove it later generatedObjects.Add(myInstantiatedObject); } }
/** * \brief Returns a pb_Object cone with the passed size. * @param angle amount of a circle the arch takes up * @param radius distance from origin to furthest extent of geometry * @param width distance from arch top to inner radius * @param depth depth of arch blocks * @param radialCuts how many blocks compose the arch * @param insideFaces render inside faces toggle * @param outsideFaces render outside faces toggle * @param frontFaces render front faces toggle * @param backFaces render back faces toggle * \returns New #pb_Object. */ public static pb_Object ArchGenerator( float angle, float radius, float width, float depth, int radialCuts, bool insideFaces, bool outsideFaces, bool frontFaces, bool backFaces) { Vector2[] templateOut = new Vector2[radialCuts]; Vector2[] templateIn = new Vector2[radialCuts]; for (int i = 0; i < radialCuts; i++) { templateOut[i] = pb_Math.PointInCircumference(radius, i * (angle / (radialCuts - 1)), Vector2.zero); templateIn[i] = pb_Math.PointInCircumference(radius - width, i * (angle / (radialCuts - 1)), Vector2.zero); } List <Vector3> v = new List <Vector3>(); Vector2 tmp, tmp2, tmp3, tmp4; float y = 0; for (int n = 0; n < radialCuts; n++) { // outside faces tmp = templateOut[n]; tmp2 = n < (radialCuts - 1) ? templateOut[n + 1] : templateOut[n]; Vector3[] qvo = new Vector3[4] { new Vector3(tmp.x, tmp.y, y), new Vector3(tmp2.x, tmp2.y, y), new Vector3(tmp.x, tmp.y, depth), new Vector3(tmp2.x, tmp2.y, depth) }; // inside faces tmp = templateIn[n]; tmp2 = n < (radialCuts - 1) ? templateIn[n + 1] : templateIn[n]; Vector3[] qvi = new Vector3[4] { new Vector3(tmp2.x, tmp2.y, y), new Vector3(tmp.x, tmp.y, y), new Vector3(tmp2.x, tmp2.y, depth), new Vector3(tmp.x, tmp.y, depth) }; if (outsideFaces) { v.AddRange(qvo); } if (n != radialCuts - 1 && insideFaces) { v.AddRange(qvi); } // left side bottom face if (n == 0 && angle < 360.0f) { v.AddRange( new Vector3[4] { new Vector3(templateOut[n].x, templateOut[n].y, depth), new Vector3(templateIn[n].x, templateIn[n].y, depth), new Vector3(templateOut[n].x, templateOut[n].y, y), new Vector3(templateIn[n].x, templateIn[n].y, y) }); } // ride side bottom face if (n == radialCuts - 1 && angle < 360.0f) { v.AddRange( new Vector3[4] { new Vector3(templateIn[n].x, templateIn[n].y, depth), new Vector3(templateOut[n].x, templateOut[n].y, depth), new Vector3(templateIn[n].x, templateIn[n].y, y), new Vector3(templateOut[n].x, templateOut[n].y, y) }); } } // build front and back faces for (int i = 0; i < radialCuts; i++) { tmp = templateOut[i]; tmp2 = (i < radialCuts - 1) ? templateOut[i + 1] : templateOut[i]; tmp3 = templateIn[i]; tmp4 = (i < radialCuts - 1) ? templateIn[i + 1] : templateIn[i]; // front Vector3[] tpb = new Vector3[4] { new Vector3(tmp.x, tmp.y, depth), new Vector3(tmp2.x, tmp2.y, depth), new Vector3(tmp3.x, tmp3.y, depth), new Vector3(tmp4.x, tmp4.y, depth), }; // back Vector3[] tpt = new Vector3[4] { new Vector3(tmp2.x, tmp2.y, 0f), new Vector3(tmp.x, tmp.y, 0f), new Vector3(tmp4.x, tmp4.y, 0f), new Vector3(tmp3.x, tmp3.y, 0f) }; if (frontFaces) { v.AddRange(tpb); } if (backFaces) { v.AddRange(tpt); } } pb_Object pb = ProBuilder.CreateObjectWithPoints(v.ToArray()); pb.SetName("Arch"); return(pb); }
/** * \brief Returns a pb_Object door with the passed parameters. * @param totalWidth the total width of the door * @param totalHeight the total height of the door * @param ledgeHeight the height between the top of the door frame and top of the object * @param legWidth the width of each leg on both sides of the door * @param depth the distance between the front and back faces of the door object * \returns New #pb_Object. */ public static pb_Object DoorGenerator(float totalWidth, float totalHeight, float ledgeHeight, float legWidth, float depth) { float xLegCoord = totalWidth / 2f; legWidth = xLegCoord - legWidth; ledgeHeight = totalHeight - ledgeHeight; Vector3[] template = new Vector3[12] // front verts { // _ _ _ _ new Vector3(-xLegCoord, 0f, depth), // 0 new Vector3(-legWidth, 0f, depth), // 1 new Vector3(legWidth, 0f, depth), // 2 new Vector3(xLegCoord, 0f, depth), // 3 // . . . . // _ _ _ _ new Vector3(-xLegCoord, ledgeHeight, depth), // 4 new Vector3(-legWidth, ledgeHeight, depth), // 5 new Vector3(legWidth, ledgeHeight, depth), // 6 new Vector3(xLegCoord, ledgeHeight, depth), // 7 // - - - - // . . . . // _ _ _ _ new Vector3(-xLegCoord, totalHeight, depth), // 8 new Vector3(-legWidth, totalHeight, depth), // 9 new Vector3(legWidth, totalHeight, depth), // 10 new Vector3(xLegCoord, totalHeight, depth) // 11 }; // front face Vector3[] v = new Vector3[30] { template[0], // left template[1], // left template[4], // left template[1], // left template[5], // left template[4], // left template[4], // top left template[5], template[8], template[5], template[9], template[8], template[5], // mid center template[6], // mid center template[9], // mid center template[6], // mid center template[10], // mid center template[9], // mid center template[6], // right top template[7], template[10], template[7], template[11], template[10], template[2], // right mid template[3], template[6], template[3], template[7], template[6], }; System.Array.Resize(ref v, 88); for (int i = 30; i < 60; i++) { v[i] = v[i - 30]; v[i].z = -v[i].z; } // // build inside frame // left inside v[60 + 0] = template[1]; v[60 + 1] = new Vector3(template[1].x, template[1].y, -template[1].z); v[60 + 2] = template[5]; v[60 + 3] = new Vector3(template[5].x, template[5].y, -template[5].z); // top inside arch v[60 + 4] = template[5]; v[60 + 5] = new Vector3(template[5].x, template[5].y, -template[5].z); v[60 + 6] = template[6]; v[60 + 7] = new Vector3(template[6].x, template[6].y, -template[6].z); // right inside v[60 + 8] = template[6]; v[60 + 9] = new Vector3(template[6].x, template[6].y, -template[6].z); v[60 + 10] = template[2]; v[60 + 11] = new Vector3(template[2].x, template[2].y, -template[2].z); int[] tris = new int[30] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }; System.Array.Resize(ref tris, 78); // copy and flip tris for (int i = 30; i < 60; i += 3) { tris[i + 2] = tris[i - 30] + 30; tris[i + 1] = tris[i - 29] + 30; tris[i + 0] = tris[i - 28] + 30; } int vInd = 60; for (int i = 60; i < 78; i += 6) { tris[i + 0] = vInd + 0; tris[i + 1] = vInd + 1; tris[i + 2] = vInd + 2; tris[i + 3] = vInd + 1; tris[i + 4] = vInd + 3; tris[i + 5] = vInd + 2; vInd += 4; } pb_Face[] f = new pb_Face[13]; for (int i = 0; i < 13; i++) { int[] seg = new int[6]; System.Array.Copy(tris, i * 6, seg, 0, 6); f[i] = new pb_Face(seg); } pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(v, f); pb.SetName("Door"); return(pb); }
/** * \brief Creates a stair set with the given parameters. * @param steps How many steps should this stairwell have? * @param width How wide (in meters) should this stairset be? * @param height How tall (in meters) should this stairset be? * @param depth How deep (in meters) should this stairset be? * @param sidesGoToFloor If true, stair step sides will extend to the floor. If false, sides will only extend as low as the stair is high. * @param generateBack If true, a back face to the stairwell will be appended. * @param platformsOnly If true, only the front face and tops of the stairwell will be built. Nice for when a staircase is embedded between geometry. * \returns A pb_Object reference to the created stairset. */ public static pb_Object StairGenerator(int steps, float width, float height, float depth, bool sidesGoToFloor, bool generateBack, bool platformsOnly) { int i = 0; List <Vector3> verts = new List <Vector3>(); Vector3[] v = (platformsOnly) ? new Vector3[8] : new Vector3[16]; float stepWidth = width; float stepHeight = height / steps; float stepDepth = depth / steps; float yMax = stepHeight; // used when stair sides extend to floor // platforms for (i = 0; i < steps; i++) { float x = stepWidth / 2f, y = i * stepHeight, z = i * stepDepth; if (sidesGoToFloor) { y = 0; } yMax = i * stepHeight + stepHeight; // Front v[0] = new Vector3(x, i * stepHeight, z); v[1] = new Vector3(-x, i * stepHeight, z); v[2] = new Vector3(x, yMax, z); v[3] = new Vector3(-x, yMax, z); // Platform v[4] = new Vector3(x, yMax, z); v[5] = new Vector3(-x, yMax, z); v[6] = new Vector3(x, yMax, z + stepDepth); v[7] = new Vector3(-x, yMax, z + stepDepth); if (!platformsOnly) { // Left side v[8] = new Vector3(x, y, z + stepDepth); v[9] = new Vector3(x, y, z); v[10] = new Vector3(x, yMax, z + stepDepth); v[11] = new Vector3(x, yMax, z); // Right side v[12] = new Vector3(-x, y, z); v[13] = new Vector3(-x, y, z + stepDepth); v[14] = new Vector3(-x, yMax, z); v[15] = new Vector3(-x, yMax, z + stepDepth); } verts.AddRange(v); } if (generateBack) { verts.Add(new Vector3(-stepWidth / 2f, 0f, depth)); verts.Add(new Vector3(stepWidth / 2f, 0f, depth)); verts.Add(new Vector3(-stepWidth / 2f, height, depth)); verts.Add(new Vector3(stepWidth / 2f, height, depth)); } pb_Object pb = ProBuilder.CreateObjectWithPoints(verts.ToArray()); pb.SetName("Stairs"); return(pb); }
/** * \brief Returns a pb_Object plane with the passed size. * @param _width Plane width. * @param _height Plane height. * @param _widthCuts Divisions on the X axis. * @param _heightCuts Divisions on the Y axis. * @param axis The axis to build the plane on. Ex: ProBuilder.Axis.Up is a plane with a normal of Vector3.up. * @param smooth (Unsupported) Toggles the sharing of vertices in triangle array. Default is false. * \returns New #pb_Object. */ public static pb_Object PlaneGenerator(float _width, float _height, int widthCuts, int heightCuts, Axis axis, bool smooth) { float width = _width; float height = _height; int w = widthCuts + 1; int h = heightCuts + 1; Vector2[] p = (smooth) ? new Vector2[w * h] : new Vector2[(w * h) * 4]; Vector3[] v = (smooth) ? new Vector3[w * h] : new Vector3[(w * h) * 4]; pb_Face[] f = new pb_Face[w * h]; int i = 0, j = 0; { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { float x0 = x * (width / w) - (width / 2f) - ((width / w) / w); float x1 = (x + 1) * (width / w) - (width / 2f) - ((width / w) / w); float y0 = y * (height / h) - (height / 2f) - ((height / h) / h); float y1 = (y + 1) * (height / h) - (height / 2f) - ((height / h) / h); p[i + 0] = new Vector2(x0, y0); p[i + 1] = new Vector2(x1, y0); p[i + 2] = new Vector2(x0, y1); p[i + 3] = new Vector2(x1, y1); f[j++] = new pb_Face(new int[6] { i + 0, i + 1, i + 2, i + 1, i + 3, i + 2 }); i += 4; } } } switch (axis) { case Axis.Right: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(0f, p[i].x, p[i].y); } break; case Axis.Left: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(0f, p[i].y, p[i].x); } break; case Axis.Up: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(p[i].y, 0f, p[i].x); } break; case Axis.Down: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(p[i].x, 0f, p[i].y); } break; case Axis.Forward: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(p[i].x, p[i].y, 0f); } break; case Axis.Backward: for (i = 0; i < v.Length; i++) { v[i] = new Vector3(p[i].y, p[i].x, 0f); } break; } pb_Object pb; pb = ProBuilder.CreateObjectWithVerticesFaces(v, f); pb.SetName("Plane"); Vector3 center = Vector3.zero; Vector3[] verts = pb.VerticesInWorldSpace(); foreach (Vector3 vector in verts) { center += vector; } center /= verts.Length; Vector3 dir = (pb.transform.position - center); pb.transform.position = center; // the last bool param force disables snapping vertices pb.TranslateVertices(pb.uniqueIndices, dir, true); return(pb); }
public static pb_Object ProBuilderize(Transform t) { Mesh m = t.GetComponent <MeshFilter>().sharedMesh; // pb_Face[] faces = new pb_Face[m.triangles.Length/3]; List <pb_Face> faces = new List <pb_Face>(); for (int n = 0; n < m.subMeshCount; n++) { int[] tris = m.GetTriangles(n); for (int i = 0; i < tris.Length; i += 3) { int index = -1; for (int j = 0; j < faces.Count; j++) { if (faces[j].distinctIndices.Contains(tris[i + 0]) || faces[j].distinctIndices.Contains(tris[i + 1]) || faces[j].distinctIndices.Contains(tris[i + 2])) { index = j; break; } } if (index > -1) { int len = faces[index].indices.Length; int[] arr = new int[len + 3]; System.Array.Copy(faces[index].indices, 0, arr, 0, len); arr[len + 0] = tris[i + 0]; arr[len + 1] = tris[i + 1]; arr[len + 2] = tris[i + 2]; faces[index].SetIndices(arr); faces[index].RebuildCaches(); } else { faces.Add( new pb_Face( new int[3] { tris[i + 0], tris[i + 1], tris[i + 2] }, t.GetComponent <MeshRenderer>().sharedMaterials[n], new pb_UV(), 0, -1, Color.white )); } } } #if UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 t.gameObject.active = false; #else t.gameObject.SetActive(false); #endif pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(m.vertices, faces.ToArray()); pb.SetName("FrankenMesh"); pb.Refresh(); pb_Editor_Utility.SetEntityType(ProBuilder.EntityType.Detail, pb.gameObject); GameObject go = pb.gameObject; go.transform.position = t.position; go.transform.localRotation = t.localRotation; go.transform.localScale = t.localScale; pb.FreezeScaleTransform(); return(pb); }
/** * \brief Creates a cylinder #pb_Object with the supplied parameters. * @param axisDivisions How many divisions to create on the vertical axis. Larger values = smoother surface. * @param radius The radius in world units. * @param height The height of this object in world units. * @param heightCuts The amount of divisions to create on the horizontal axis. * \returns The newly generated #pb_Object. */ public static pb_Object CylinderGenerator(int axisDivisions, float radius, float height, int heightCuts) { if (axisDivisions % 2 != 0) { axisDivisions++; } if (axisDivisions > 64) { axisDivisions = 64; } float stepAngle = 360f / axisDivisions; float heightStep = height / (heightCuts + 1); Vector3[] circle = new Vector3[axisDivisions]; // get a circle for (int i = 0; i < axisDivisions; i++) { float angle0 = stepAngle * i * Mathf.Deg2Rad; float x = Mathf.Cos(angle0) * radius; float z = Mathf.Sin(angle0) * radius; circle[i] = new Vector3(x, 0f, z); } // add two because end caps Vector3[] verts = new Vector3[(axisDivisions * (heightCuts + 1) * 4) + (axisDivisions * 6)]; pb_Face[] faces = new pb_Face[axisDivisions * (heightCuts + 1) + (axisDivisions * 2)]; // build vertex array int it = 0; // +1 to account for 0 height cuts for (int i = 0; i < heightCuts + 1; i++) { float Y = i * heightStep; float Y2 = (i + 1) * heightStep; for (int n = 0; n < axisDivisions; n++) { verts[it + 0] = new Vector3(circle[n + 0].x, Y, circle[n + 0].z); verts[it + 1] = new Vector3(circle[n + 0].x, Y2, circle[n + 0].z); if (n != axisDivisions - 1) { verts[it + 2] = new Vector3(circle[n + 1].x, Y, circle[n + 1].z); verts[it + 3] = new Vector3(circle[n + 1].x, Y2, circle[n + 1].z); } else { verts[it + 2] = new Vector3(circle[0].x, Y, circle[0].z); verts[it + 3] = new Vector3(circle[0].x, Y2, circle[0].z); } it += 4; } } // wind side faces int f = 0; for (int i = 0; i < heightCuts + 1; i++) { for (int n = 0; n < axisDivisions * 4; n += 4) { int index = (i * (axisDivisions * 4)) + n; int zero = index; int one = index + 1; int two = index + 2; int three = index + 3; faces[f++] = new pb_Face(new int[6] { zero, one, two, one, three, two }); } } // construct caps seperately, cause they aren't wound the same way int ind = (axisDivisions * (heightCuts + 1) * 4); int f_ind = axisDivisions * (heightCuts + 1); for (int n = 0; n < axisDivisions; n++) { // bottom faces verts[ind + 0] = new Vector3(circle[n].x, 0f, circle[n].z); verts[ind + 1] = Vector3.zero; if (n != axisDivisions - 1) { verts[ind + 2] = new Vector3(circle[n + 1].x, 0f, circle[n + 1].z); } else { verts[ind + 2] = new Vector3(circle[000].x, 0f, circle[000].z); } faces[f_ind + n] = new pb_Face(new int[3] { ind + 2, ind + 1, ind + 0 }); ind += 3; // top faces verts[ind + 0] = new Vector3(circle[n].x, height, circle[n].z); verts[ind + 1] = new Vector3(0f, height, 0f); if (n != axisDivisions - 1) { verts[ind + 2] = new Vector3(circle[n + 1].x, height, circle[n + 1].z); } else { verts[ind + 2] = new Vector3(circle[000].x, height, circle[000].z); } faces[f_ind + (n + axisDivisions)] = new pb_Face(new int[3] { ind + 0, ind + 1, ind + 2 }); ind += 3; } pb_Object pb = ProBuilder.CreateObjectWithVerticesFaces(verts, faces); pb.SetName("Cylinder"); return(pb); }