gord0 2 Report post Posted March 28, 2018 2 minutes ago, karl said: Yes, but you'd end up with two faces sandwiched next to each other. If that works for you, it would be fine to use use that approach. I also just remembered that I did a very similar thing for an article a few years ago. I can't find the article, but the example code is here. https://github.com/karl-/pipedreams Cool. I'll check that out when I'm back at work tomorrow. : ] Share this post Link to post Share on other sites
gord0 2 Report post Posted April 4, 2018 Sorry, I was off work longer than I knew I was going to be. Anyway, I've got that project opened up. It didn't have the probuilder stuff with it so I imported it. After that I now have " The type or namespace name `Math' does not exist in the namespace `ProBuilder2'. Are you missing an assembly reference?" coming from Pipe.cs on line 5: using ProBuilder2.Math; If I comment that out, the next problem is "The name `pb_Shape_Generator' does not exist in the current context" coming from PipeSpawner.cs at line 238: pb_Object pb = pb_Shape_Generator.CubeGenerator(Vector3.one * pipeSize); I imagine this is due to deprecation? How might I sort this out? Share this post Link to post Share on other sites
karl 321 Report post Posted April 4, 2018 Yeah, these things have moved around quite a bit since that was written. Math was moved into Core, and I think the shape gen class is now just pb_ShapeGenerator. 1 gord0 reacted to this Share this post Link to post Share on other sites
gord0 2 Report post Posted April 4, 2018 1 hour ago, karl said: Yeah, these things have moved around quite a bit since that was written. Math was moved into Core, and I think the shape gen class is now just pb_ShapeGenerator. Cheers, that sorted that out. Looking at code now. Share this post Link to post Share on other sites
gord0 2 Report post Posted April 4, 2018 Alright, so is this what's going on with the pipes? If so, is this not just an automated version of the example that comes with probuilder that I started with? Share this post Link to post Share on other sites
karl 321 Report post Posted April 4, 2018 Yes, precisely. It seems like you've got the parts mostly correct, now it's just a matter of making sure that the pb_Object mesh state is set after you do the modifications. So looking at this as an example you can parse out when the appropriate times to call Extrude, ToMesh, and Refresh. Share this post Link to post Share on other sites
gord0 2 Report post Posted April 5, 2018 19 hours ago, karl said: Yes, precisely. It seems like you've got the parts mostly correct, now it's just a matter of making sure that the pb_Object mesh state is set after you do the modifications. So looking at this as an example you can parse out when the appropriate times to call Extrude, ToMesh, and Refresh. I've added a couple more ToMesh() and Refesh()es so that each time I Extrude(), SetVertices(), ReverseIndices(), and TranslateVertices() I call those two methods immediately after. Seems to have been redundant though because my result is the same as before protected void CommenceModifications() { Vector3 facePos = FaceCenter(_currentSelection.Face, _currentSelection.PB); //get the center point of selected face Vector3 toWidget = (_widget.localPosition - facePos).normalized; //get direction from face center to widget bool behind = Mathf.Approximately(Vector3.Dot(toWidget, _localNormal), -1.0f); //determine if widget is in front or behind face if (_canExtrude) //may we extrude? { //make it so _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.IndividualFaces, !_specifiedFaceSelect ? Mathf.Epsilon : 0.0f); //epsilon if not custom face, otherwise 0 _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); if (_specifiedFaceSelect) //is this a user defined face? { //move their plane back to be flush with the actual face they want to extrude from _customExtruderPlane.gameObject.transform.position -= _customExtruderPlane.gameObject.transform.forward * 0.1f; //extrude again with 0 distance _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.IndividualFaces, 0.0f); _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); Vector3[] verts = _currentSelection.PB.vertices; //grab all our verts int[] indices = _currentSelection.Face.indices /*distinctIndices*/; //grab the indices of the current face Vector3[] toVerts = _customExtruderPlane.vertices; //grab the verts of the user defined plane //place markers to represent the postions of the user defined plane verts for (int iMarker = 0; iMarker < _faceScalerMarkers.Length; iMarker++) { //child marker to user defined plane _faceScalerMarkers[iMarker].parent = _customExtruderPlane.gameObject.transform; //place marker at user defined plane's iMarker vertice position _faceScalerMarkers[iMarker].localPosition = toVerts[iMarker]; _faceScalerMarkers[iMarker].parent = transform; //child marker to us } //set current face vertices to the position of the closest marker (to retain wind order) for (int iVert = 0; iVert < indices.Length; iVert++) { verts[indices[iVert]] = ClosestScalerMarkerPos(verts[indices[iVert]]); } _currentSelection.PB.SetVertices(verts); //apply new vertice positions _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); _currentSelection.Face.ReverseIndices(); //reverse the indices so we can see the face (for some reason backwards) _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); Destroy(_customExtruderPlane.gameObject); //destroy user defined plane for (int iMarker = 0; iMarker < _faceScalerMarkers.Length; iMarker++) //unchild markers { _faceScalerMarkers[iMarker].parent = null; } } _currentSelection.PB.ToMesh(); //apply changes _currentSelection.PB.Refresh(); //.. _canExtrude = false; //no more extuding for now } if (!_specifiedFaceSelect) //if this was a not a user defined face, translate the verts based on widget pos { _currentSelection.PB.TranslateVertices( _currentSelection.Face.distinctIndices, _localNormal.normalized * (Vector3.Distance(_widget.localPosition, facePos)) * (behind ? -1.0f : 1.0f) ); _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); } else //otherwise { _specifiedFaceSelect = false; //we're done with the user defined face _destroyPreview = true; //destroy the preview plane _waitAFrame = true; //we should probably wait a frame before we do anything else } // Refresh will update the Collision mesh volume, face UVs as applicatble, and normal information. _currentSelection.PB.Refresh(); // this creates the selected face preview RefreshSelectedFacePreview(); } Share this post Link to post Share on other sites
gord0 2 Report post Posted April 5, 2018 How are these pb_Object methods used?: AppendFace, Connect, and MergeFaces Could they be of use? Share this post Link to post Share on other sites
gord0 2 Report post Posted April 9, 2018 Alright I'm getting better results using a different approach. The new problem is, what is this diagonal plain on the inside of the "corridor"? I've used a 2 sided transparent material so you can see (it seems your attachment system is broken so I'm using external links): https://pasteboard.co/HfQ4Xja.png https://pasteboard.co/HfQ5Ahq.png This is how I'm achieving it: protected void CommenceModifications() { Vector3 facePos = FaceCenter(_currentSelection.Face, _currentSelection.PB); //get the center point of selected face Vector3 toWidget = (_widget.localPosition - facePos).normalized; //get direction from face center to widget bool behind = Mathf.Approximately(Vector3.Dot(toWidget, _localNormal), -1.0f); //determine if widget is in front or behind face if (_canExtrude) //may we extrude? { //make it so _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.IndividualFaces, !_specifiedFaceSelect ? Mathf.Epsilon : 0.0f); //epsilon if not custom face, otherwise 0 _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); if (_specifiedFaceSelect) //is this a user defined face? { //move their plane back to be flush with the actual face they want to extrude from _customExtruderPlane.gameObject.transform.position -= _customExtruderPlane.gameObject.transform.forward * 0.1f; Transform t = _customExtruderPlane.gameObject.transform; if (Mathf.Approximately(t.forward.z, 1.0f) || Mathf.Approximately(t.forward.x, 1.0f) || Mathf.Approximately(t.forward.x, -1.0f) || Mathf.Approximately(t.forward.y, 1.0f) || Mathf.Approximately(t.forward.y, -1.0f)) { _customExtruderPlane.faces[0].ReverseIndices(); } t.parent = _currentSelection.PB.gameObject.transform; Vector3[] offSetVerts = _customExtruderPlane.vertices; float xDist = Vector3.Distance(offSetVerts[0], offSetVerts[2]); float yDist = Vector3.Distance(offSetVerts[0], offSetVerts[1]); for (int iVert=0; iVert<offSetVerts.Length; iVert++) { offSetVerts[iVert] += t.localPosition; if (Mathf.Approximately(t.forward.z, -1.0f)) { offSetVerts[iVert].x += xDist; } /*if (iVert==5) //touching: 0, 2, 5 { //not touching: 1, 3, 4 Transform go = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; go.parent = _currentSelection.PB.gameObject.transform; go.localPosition = offSetVerts[iVert]; }*/ if ((iVert!=0 && iVert!=1 && iVert!=3) && (Mathf.Approximately(t.forward.x, 1.0f) || Mathf.Approximately(t.forward.x, -1.0f))) { offSetVerts[iVert].x = offSetVerts[0].x; offSetVerts[iVert].z += xDist * (Mathf.Approximately(t.forward.x, -1.0f) ? -1.0f : 1.0f); } if ((iVert!=0 && iVert!=2 && iVert!=5) && (Mathf.Approximately(t.forward.y, 1.0f) ||Mathf.Approximately(t.forward.y, -1.0f))) { offSetVerts[iVert].y = offSetVerts[0].y; offSetVerts[iVert].z += yDist * (Mathf.Approximately(t.forward.y, 1.0f) ? -1.0f : 1.0f); } } t.parent = null; pb_Face pbf=_currentSelection.PB.AppendFace(offSetVerts, new Color[1] { Color.white }, _customExtruderPlane.uv, _customExtruderPlane.faces[0]); _manualFaceSelect = true; _manualFaceSelectPBO = _currentSelection.PB; _manualFaceSelectFace = pbf; /*Debug.LogWarning("_customExtruderPlane.gameObject.transform.forward: " + _customExtruderPlane.gameObject.transform.forward);*/ if (_customExtruderPlane != null) { Destroy(_customExtruderPlane.gameObject); } } _currentSelection.PB.ToMesh(); //apply changes _currentSelection.PB.Refresh(); //.. _canExtrude = false; //no more extuding for now } if (!_specifiedFaceSelect) //if this was a not a user defined face, translate the verts based on widget pos { _currentSelection.PB.TranslateVertices( _currentSelection.Face.distinctIndices, _localNormal.normalized * (Vector3.Distance(_widget.localPosition, facePos)) * (behind ? -1.0f : 1.0f) ); _currentSelection.PB.ToMesh(); _currentSelection.PB.Refresh(); } else //otherwise { _specifiedFaceSelect = false; //we're done with the user defined face _destroyPreview = true; //destroy the preview plane _waitAFrame = true; //we should probably wait a frame before we do anything else } // Refresh will update the Collision mesh volume, face UVs as applicatble, and normal information. _currentSelection.PB.Refresh(); // this creates the selected face preview RefreshSelectedFacePreview(); Have you seen this kind of problem before? Share this post Link to post Share on other sites
karl 321 Report post Posted April 9, 2018 Yup, your only problem is the ExtrudeMethod being used. You want `ExtrudeMethod.FaceNormal`, not InvdividualFaces. _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.FaceNormal, !_specifiedFaceSelect ? Mathf.Epsilon : 0.0f); //epsilon if not custom face, otherwise 0 1 gord0 reacted to this Share this post Link to post Share on other sites
gord0 2 Report post Posted April 9, 2018 11 minutes ago, karl said: Yup, your only problem is the ExtrudeMethod being used. You want `ExtrudeMethod.FaceNormal`, not InvdividualFaces. _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.FaceNormal, !_specifiedFaceSelect ? Mathf.Epsilon : 0.0f); //epsilon if not custom face, otherwise 0 Ahhhh, I didn't even think to look there since I had been using that line as is for so long. Will give it a go in the morning! Share this post Link to post Share on other sites
gord0 2 Report post Posted April 10, 2018 17 hours ago, karl said: Yup, your only problem is the ExtrudeMethod being used. You want `ExtrudeMethod.FaceNormal`, not InvdividualFaces. _currentSelection.PB.Extrude(new pb_Face[] { _currentSelection.Face }, ExtrudeMethod.FaceNormal, !_specifiedFaceSelect ? Mathf.Epsilon : 0.0f); //epsilon if not custom face, otherwise 0 I was hopeful but...same issue. I also tried VertexNormal just see what would happen and it's also the same. All three methods seem to turn out the same in this scenario. Share this post Link to post Share on other sites
karl 321 Report post Posted April 10, 2018 Okay, so the face that you're extruding from is two triangles then. What is the code that is creating the initial cube or face from which you extrude? Share this post Link to post Share on other sites
gord0 2 Report post Posted April 10, 2018 59 minutes ago, karl said: Okay, so the face that you're extruding from is two triangles then. What is the code that is creating the initial cube or face from which you extrude? protected void DrawCustomPlane() { if (Input.GetMouseButtonUp(0)) //they let go of the button, lets get outta here { _customExtruding = false; _meoc.RelinquishNonAxisMovement = false; _specifiedFaceSelect = true; CommenceModifications(); return; } if (!Input.GetKey(KeyCode.LeftControl)) { return; } //they're not holding left control, so let's chill if (_customExtruderPlane==null) //if our plane is null { _ray = _cam.ScreenPointToRay(Input.mousePosition); //let's fire a ray to see if we can fix that if (Physics.Raycast(_ray, out _hit, Mathf.Infinity, _lm)) //if we hit something { if (_hit.collider.gameObject.GetComponent<pb_Object>()==null) { return; } //forget it, not pb object Vector3[] verts = new Vector3[6] //we'll start with all the vertices zero'd out { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero }; int[] indices = new int[verts.Length]; //define our indices for (int iVert=0; iVert<verts.Length; iVert++) { indices[iVert] = iVert; } //.. //now we can make the plane _customExtruderPlane = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[] { new pb_Face(indices) }); _customExtruderPlane.SetFaceMaterial(_customExtruderPlane.faces, PreviewMaterial); _customExtruderPlane.ToMesh(); _customExtruderPlane.Refresh(); //move it just a little in front of whatever the ray hit so we can see it proper _customExtruderPlane.gameObject.transform.position = _hit.point + (_hit.normal * 0.1f); _customExtruderPlane.gameObject.transform.forward = _hit.normal; } } if (_customExtruderPlane==null) { return; } //i guess we missed else //lets move our vertices according to mouse movement { /* verts[0] -- upper left corner verts[0] -- upper left corner verts[1,3] -- lower left corner verts[2,3] -- lower left corner verts[2,5] -- upper right corner verts[1,4] -- upper right corner verts[4] -- lower right corner verts[5] -- lower righ corner 0 --- 2,5 0 --- 1,4 | | | | | | | | | | | | 1,3 --- 4 2,3 --- 5 */ _ray = _cam.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(_ray, out _hit, Mathf.Infinity, _lm)) //fire ray from the mouse { if (_hit.collider.gameObject.GetComponent<pb_Object>() == null) { return; } //forget it, not pb object _customPlaneMarker.position = _hit.point; //place our marker at the hit point _customPlaneMarker.parent = _customExtruderPlane.gameObject.transform; //child it to the plane Vector3[] verts = _customExtruderPlane.vertices; //grab verts from the plane verts[4] = _customPlaneMarker.localPosition; //place lower right corner at marker verts[4].z = verts[0].z; //copy z from upper right corner to lower left (remember plane is a little in front of hit) verts[2].x = verts[4].x; //make rest of verts form the rest of the rectangle based on 0 and 4 verts[5].x = verts[4].x; //.. verts[1].y = verts[4].y; //.. verts[3].y = verts[4].y; //.. //same as above but clockwise winding order //verts[5] = _customPlaneMarker.localPosition; //verts[5].z = verts[0].z; //verts[1].x = verts[5].x; //verts[4].x = verts[5].x; //verts[2].y = verts[5].y; //verts[3].y = verts[5].y; _customExtruderPlane.SetVertices(verts); //update the plane's vertices with our changes _customExtruderPlane.ToMesh(); //apply changes _customExtruderPlane.Refresh(); //.. _customPlaneMarker.parent = null; //unchild marker from plane } } } This is the code that allows the user to draw their own plane. Share this post Link to post Share on other sites
karl 321 Report post Posted April 10, 2018 The problem stems from how you're creating that initial face. The gist of it is that for the moment it assumes any triangle edge with unique vertex positions are perimeter edges. So when you extrude, ProBuilder thinks that the face you're extruding from is actually two faces. To fix this, just use 4 vertex positions instead of 6. Ex: /** * Vertex positions for a quad are laid out like this. Note that positions 0 & 3 are reused. * * 2-----3 * | | * | | * 0-----1 * */ Vector3[] verts = new Vector3[4] { new Vector3(-1, -1f, 0f), new Vector3( 1, -1f, 0f), new Vector3(-1, 1f, 0f), new Vector3( 1, 1f, 0f), }; /** * Quad is two tris: * * 2←-------3 * |↖ ↘ ↑ * | ↖ ↘ | * ↓ ↖ ↘| * 0-------→1 */ var face = new pb_Face(new int[6] { 0, 1, 2, 1, 3, 2 }); face.material = pb_Constant.DefaultMaterial; var pb = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[] { face }); pb.ToMesh(); pb.Refresh(); 1 gord0 reacted to this Share this post Link to post Share on other sites
gord0 2 Report post Posted April 10, 2018 3 minutes ago, karl said: The problem stems from how you're creating that initial face. The gist of it is that for the moment it assumes any triangle edge with unique vertex positions are perimeter edges. So when you extrude, ProBuilder thinks that the face you're extruding from is actually two faces. To fix this, just use 4 vertex positions instead of 6. Ex: /** * Vertex positions for a quad are laid out like this. Note that positions 0 & 3 are reused. * * 2-----3 * | | * | | * 0-----1 * */ Vector3[] verts = new Vector3[4] { new Vector3(-1, -1f, 0f), new Vector3( 1, -1f, 0f), new Vector3(-1, 1f, 0f), new Vector3( 1, 1f, 0f), }; /** * Quad is two tris: * * 2←-------3 * |↖ ↘ ↑ * | ↖ ↘ | * ↓ ↖ ↘| * 0-------→1 */ var face = new pb_Face(new int[6] { 0, 1, 2, 1, 3, 2 }); face.material = pb_Constant.DefaultMaterial; var pb = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[] { face }); pb.ToMesh(); pb.Refresh(); Cheers, will try this out in the morning. : ] Share this post Link to post Share on other sites
gord0 2 Report post Posted April 12, 2018 On 10/04/2018 at 4:29 PM, karl said: The problem stems from how you're creating that initial face. The gist of it is that for the moment it assumes any triangle edge with unique vertex positions are perimeter edges. So when you extrude, ProBuilder thinks that the face you're extruding from is actually two faces. To fix this, just use 4 vertex positions instead of 6. Ex: /** * Vertex positions for a quad are laid out like this. Note that positions 0 & 3 are reused. * * 2-----3 * | | * | | * 0-----1 * */ Vector3[] verts = new Vector3[4] { new Vector3(-1, -1f, 0f), new Vector3( 1, -1f, 0f), new Vector3(-1, 1f, 0f), new Vector3( 1, 1f, 0f), }; /** * Quad is two tris: * * 2←-------3 * |↖ ↘ ↑ * | ↖ ↘ | * ↓ ↖ ↘| * 0-------→1 */ var face = new pb_Face(new int[6] { 0, 1, 2, 1, 3, 2 }); face.material = pb_Constant.DefaultMaterial; var pb = pb_Object.CreateInstanceWithVerticesFaces(verts, new pb_Face[] { face }); pb.ToMesh(); pb.Refresh(); It is working! I still have to make some adjustments so that it works on all axis but 4 of the 6 are working. I'll let you know if I have any more questions/troubles. : ] Share this post Link to post Share on other sites
gord0 2 Report post Posted April 16, 2018 One more thing. When using AppendFace() is there a way to make the face physically stay where it was before appending. It seems to always go to the origin of the pbo that I attach it to. I then have to move the vertices manually with offsets depending where I intended to attach it. Which was fine until I realized that if the pbo is rotated at all it throws everything out of whack. Share this post Link to post Share on other sites
karl 321 Report post Posted April 16, 2018 AppendFace will always assume vertices are in local coordinates. To account for rotation, you can use the functions "TransformPoint" and "InverseTransformPoint" in the Transform class to translate from one object's local coordinates to another. 1 gord0 reacted to this Share this post Link to post Share on other sites
gord0 2 Report post Posted April 19, 2018 I think I'm golden now. Thanks for all your help! : ] Share this post Link to post Share on other sites
karl 321 Report post Posted April 19, 2018 No problem, I'm looking forward to seeing what you create! Share this post Link to post Share on other sites
gord0 2 Report post Posted April 27, 2018 Well of course because people love changing things, the whole input style has changed. The want to be able to just place nodes and have the "corridors" just connect the nodes. Which is fine, but it also means a lot of how I was doing things has changed. Have you ever had a face just disappear after an extrusion? In this case, not even the face I had extruded. Share this post Link to post Share on other sites
karl 321 Report post Posted April 27, 2018 Any errors in the console? 1 gord0 reacted to this Share this post Link to post Share on other sites
gord0 2 Report post Posted April 27, 2018 14 minutes ago, karl said: Any errors in the console? Will let you know on Monday. Share this post Link to post Share on other sites
gord0 2 Report post Posted April 30, 2018 On 4/27/2018 at 4:13 PM, karl said: Any errors in the console? No, it would be wonderful if there was though lol Share this post Link to post Share on other sites