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.
How can I find the mapping between generated vertices(or faces) and original face id in geometry nodes or python?
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.
How can I find the mapping between generated vertices(or faces) and original face id in geometry nodes or python?
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:
orig face
$= 15$. Still exactly what's intended.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.