5
$\begingroup$

Here's my nodes setup that converts each quad face to 16 vertices. For example, face 19 is converted to vertex 81 233 234 77…13.

enter image description here

How can I find the mapping between generated vertices(or faces) and original face id in geometry nodes or python?

$\endgroup$
1
  • $\begingroup$ What kind of format do you want them in? For what purpose? Is just knowing the numbers enough, or do you need them as csv list or something? Also, in your example, there are extra faces in between the 9-square groupings you've highlighted, are those important? $\endgroup$
    – Kuboå
    Commented Dec 9, 2022 at 1:52

1 Answer 1

11
+50
$\begingroup$

As a starting point, capture the original face index:

Put your Doo Sabin algorithm after that (lower on the modifier stack). Python can access evaluated data without the need to apply the modifiers, like so:

import bpy
from bpy import context as C
from collections import defaultdict

face_to_eval_faces = defaultdict(set)
dg = C.evaluated_depsgraph_get()
ev_ob = C.object.evaluated_get(dg)
for i, wrapper in enumerate(ev_ob.data.attributes['orig face'].data):
    face_to_eval_faces[wrapper.value].add(i)
    
print(list(face_to_eval_faces[15]))

This lists all faces (their indices) in the evaluated geometry that "come from" the original face with index $15$. However, that's more than 9 faces, why? Let's see step by step:

  1. Subdivide - face #15 is subdivided into 4 faces, each inheriting its attributes without a change. So far so good.
  2. Dual Mesh - the 4 faces are converted to 4 vertices, each inheriting the attribute of the face that spawned it, so for those vertices orig face $= 15$. Still exactly what's intended.
  3. Subdivide - again each face spawns more faces, but this time the attribute of interest is held by vertices! This is a problem, it causes an interpolation. Integer interpolation means that a spawned face will take a random¹ integer based on its neighbors. So the 9 "internal" faces (marked red on the images below) you're interested in have all neighbors with the same attribute, and therefore the randomness doesn't matter, but some of the "external" faces will still randomly get the attribute $15$, polluting your results. What you can do then is use my answer from this thread:

geometry nodes - doo sabin

In which I color the "internal" faces red, so you can just check which face is red:

So replace your 4 node setup with 2 geonodes modifiers from that thread, then add yet another geonode modifier to convert the attribute to Face domain:

And finally run a script that checks if the face is red (the shader code from the linked answer isn't very clear about it, but the red area has the doo sabin equal zero):

import bpy
from bpy import context as C, data as D
from collections import defaultdict

face_to_eval_faces = defaultdict(set)

dg = C.evaluated_depsgraph_get()
ev_ob = C.object.evaluated_get(dg)
for i, wrapper in enumerate(ev_ob.data.attributes['orig face'].data):
    if ev_ob.data.attributes['doo sabin'].data[i].value != 0:
        continue  # you don't care about the shared geo
    face_to_eval_faces[wrapper.value].add(i)
    
print(list(face_to_eval_faces[15]))
[196, 287, 175, 180, 212, 60, 61, 62, 63]

This lists 9 correct indices for the original face:

From there all you have to do is the verts instead:

import bpy
from bpy import context as C, data as D
from collections import defaultdict

face_to_eval_verts = defaultdict(set)

dg = C.evaluated_depsgraph_get()
ev_ob = C.object.evaluated_get(dg)
for i, wrapper in enumerate(ev_ob.data.attributes['orig face'].data):
    if ev_ob.data.attributes['doo sabin'].data[i].value != 0:
        continue  # you don't care about the shared geo
    face_to_eval_verts[wrapper.value].update(ev_ob.data.polygons[i].vertices)
    
print(list(face_to_eval_verts[15]))

I'm too cool to check if they all match, but probably 😎

[65, 132, 70, 135, 17, 210, 177, 276, 146, 277, 209, 278, 145, 178, 279, 63]

¹ – it's not actually random, but since the behavior is not documented, not obvious, and probably hard to argue about once you read the source (if it's e.g. based on a hash you could argue it actually is random), IMHO it makes it unreasonable to treat it differently than as random.

$\endgroup$
2
  • $\begingroup$ I wasn't too cool, however, to find out an easier approach which probably was just storing another boolean attribute on vertices added by the subdivision (check domain size before subdivision and set boolean based on index being equal or greater) which would be a much simpler setup. $\endgroup$ Commented Dec 10, 2022 at 21:38
  • $\begingroup$ Yes! I read your answer when I searched for the algorithm, didn't think I could use it here. Thanks! $\endgroup$
    – June Wang
    Commented Dec 16, 2022 at 14:05

You must log in to answer this question.

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