0
$\begingroup$

For a project about differential growth, I need to do two things: subdivide edges that are above a certain length, and then subdivide their adjacent faces. For the subdivision, I can't manage to do it without having disconnected geometry or losing faces. For now, my method consisted of separating the selected edges, subdividing the, and rejoining them with the geometry. Is there a way to do it "correctly"?

enter image description here

enter image description here

$\endgroup$
8
  • $\begingroup$ If this works for your needs, it's correct. Does it not work for your needs? If not, how? $\endgroup$
    – Nathan
    Dec 27, 2023 at 1:21
  • $\begingroup$ The problem is that it doesn't work as expected. After the edges are subdivided, the faces are lost, as you can see in the image. The goal is to transform the triangular face into a quad and then triangulate it, but that can't happen if the face is lost. $\endgroup$
    – Mansour
    Dec 28, 2023 at 8:46
  • $\begingroup$ What about if instead of separating the edges you want subdivided, you separate the faces you want subdivided-- "subdivide edges ... and then subdivide their adjacent faces." Doing the latter will do the former. Will that work for you? $\endgroup$
    – Nathan
    Dec 28, 2023 at 16:52
  • $\begingroup$ I've tried the method you're suggesting, unfortunately it doesn't work, since each face gets subdivided into 3 quads, which is not the result I'm looking for. What I want is subdivide an edge and split it's adjacent triangular faces into two triangular faces. With the method you suggested I end up with 6 quads instead of 4 triangles. In addition, the disconnected geometry problem is still present with this technique. $\endgroup$
    – Mansour
    Dec 29, 2023 at 18:36
  • $\begingroup$ So then, all input faces are triangles, you subdivide long edges, and join them to the opposite vertex of each face containing that edge? Just trying to make sure I know what you're after. $\endgroup$
    – Nathan
    Dec 29, 2023 at 19:01

1 Answer 1

1
$\begingroup$

Okay. This will probably be a little more complicated than it ought to be, but it's how I've figured out how to do what you want.

You have a mesh composed of triangles and an input length. For each triangle, if the longest edge is longer than the input, divide that longest edge into two, and then join the longest edge to the far vertex, creating two two triangles.

You may have two edges that are longer than the desired length. If you do, you'd like to handle this as an ordered process rather than simultaneous, as given by the picture you provided in comments:

enter image description here

The new edges don't intersect; first we make one edge, then the other.

I'm going to make one more assumption, which is that you have no faces where the longest edge length is shared by two faces. This would create ambiguity in the order in which you split the triangles. With that assumption, note that I also rule out any zero-area faces-- any degenerate triangles, with two coincident vertices.

So first, we'll subdivide the longest edge and join to the opposite vertex; then, we'll repeat that process for faces containing the second longest edge.

First thing, we're going to have different topology-- more faces-- than our input geometry, so we'll have to make triangles. I'll start by making a node group that will create a triangle with vertices at arbitrary positions:

enter image description here

Now, let's figure out how we can populate those positions, starting with a single triangle and cutting it in half:

enter image description here

Base geo on left.

I identify the longest edge with an attribute statistic node, which lets me separate into two distinct chunks of mesh: the longest edge, and the vertex that is not part of that edge. To get one position, I take the position of the edge; to get the second position, I take the position of the second vertex of the edge at index 0 (there's only one edge); and to get the third position, I take the point position of the vertex.

And to get the other half of the triangle, I can just take the position of vertex 1 of the edge instead of vertex 2. Which I can demonstrate by grouping this up, except for the relevant Edge Vertices node, and joining the output:

enter image description here

Now, we've got to repeat it for the new triangle, that contains the second longest edge of the original triangle. Let's go into our Split Tri node group and get it to output whether the triangle we created indeed, contains our second longest edge, as well as the length of that second longest edge:

enter image description here

I'm making a copy of my input geometry that gets rid of my longest edge and my shortest edge, and then sees if the output triangle contains any edge that is at the same location. And while I'm at it, I'm going to remember what the length of that edge actually is, so we can check it against a threshold.

Now, we can use that to iterate, splitting our faces twice:

enter image description here

We split the face into two tris; then, we split those two triangles into two more triangles. But if one of those first tris doesn't contain the second longest edge, we use the unsplit triangle instead. The input triangle is split along the longest edge, and then the triangle containing the second longest edge is split again. We can finally add a threshold input to our modifier to prevent that second longest edge from being split:

enter image description here

Because that second longest edge is shorter than 1 unit here, there's no second splitting going on.

Okay, but we got a lot of faces! And we haven't set a threshold for the first split. Let's group everything up again and then set that group aside. We'll start by separating our geometry into only the faces that contain edges longer than our threshold:

enter image description here

Then, using a repeat node, we'll iterate over every face in that selection:

enter image description here

I send my base geo into my repeat zone and out of my repeat zone. I keep track of the count of the repeat, starting at 0, and check the face index of the source geometry so that I can split every triangle, in order, and join them to a running total of that geometry. And the input for the threshold for the second split is set from the original modifier's input.

After that, we have a little clean up. We can realize instances and weld the vertices back together, then repair any normals for triangles that got made upside-down:

enter image description here

A little bit of testing, and I see that precision errors are causing some problems for the comparison tests for edge lengths, where I'm measuring that the distance is greater than 0. I'll change this to 0.001. Inside my "splitTris" node group:

enter image description here

This is certainly more complicated than I'd like. It's entirely possible that there are some errors and some corner cases I haven't considered. Even though I'm providing the file, it's not intended to do the work for you, but as an adjunct to the text and pictures in this answer. The general principle: iterate over faces; measure the positions of long edges to find two triangles; instance new triangles at those positions; do it again on sub-triangles that meet certain criteria. There is a lot of evaluating things in different domains here, sometimes by specifying a domain, sometimes by capturing a domain, sometimes by evaluating on a domain, and these don't always act exactly the same (nor am I perfectly aware of how they differ: there's a lot of trial and error for me in getting Blender to recognize the domains I want to measure.) Hopefully, even if there are some errors, if you understand the overall plan, you'll be capable of addressing them yourself, or of asking question on a sub-problem. Because, frankly, this was a lot of work that I don't want to revisit, and I probably never would have done it save for a sense of duty after asking so many questions to clarify the problem :)

$\endgroup$
6
  • 1
    $\begingroup$ If only it was easier to patch Blender... projects.blender.org/blender/blender/pulls/113427 $\endgroup$ Dec 30, 2023 at 20:53
  • $\begingroup$ @MarkusvonBroady Without fully understanding the proposed commit-- I don't want to invest much effort into understanding things that may never be-- I'm not sure how much help it would be. Making tris or ngons isn't really that hard. But trying to store a bunch of data in different domains: edge lengths, vertex positions, on faces-- ended up being pretty hard. And actually, the normal repair was bizarrely difficult, trial-and-error to get right, to get it to compare something like face normals to face normals. When odds are it doesn't even matter for Mansour's purposes. $\endgroup$
    – Nathan
    Dec 30, 2023 at 23:56
  • $\begingroup$ @MarkusvonBroady And, I'm disappointed in needing the repeat zone. It seems like it should be unnecessary, but I don't see any "triangle vertices" like we have "edge vertices", so I couldn't figure out how do without. Oh well, it probably doesn't really make a noticeable difference, just to my own sense of how things should be done. $\endgroup$
    – Nathan
    Dec 31, 2023 at 0:05
  • 1
    $\begingroup$ There's no "triangle vertices", but there's "corners of face" and "vertex of corner" $\endgroup$ Dec 31, 2023 at 1:15
  • $\begingroup$ @Nathan First I'm sorry for the late reply. Second, I can't begin to thank you for the amount of effort you invested in this, I certainly didn't expect to make anybody spend that much time on this, so thanks again. I'll try to profit from your setup as much as possible, even if it isn't the ideal setup but it will help me understand better working with geometry nodes. I really liked how you used the repeat zone as a foreach loop! Hopefully, we'll get an actual foreach loop node/zone soon. $\endgroup$
    – Mansour
    Jan 2 at 10:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .