Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/gn-sdf-remesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ NODES modifier and evaluated via the depsgraph.
socket, so wiring the grid there is an invalid link that yields no geometry). `Grid to Mesh`
has the matching grid input.

**Materials gotcha:** geometry generated by Geometry Nodes carries **no** material, so the
input mesh's material is dropped on remesh (the result renders with the default white). Re-apply
it inside the tree with a **Set Material** node (`GeometryNodeSetMaterial`) on the remeshed
output — this example does that and asserts the material survives onto the evaluated mesh.

## Run

```bash
Expand Down
24 changes: 19 additions & 5 deletions examples/gn-sdf-remesh/gn_sdf_remesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
def get_eevee_engine_id():
return 'BLENDER_EEVEE' if bpy.app.version >= (5, 0, 0) else 'BLENDER_EEVEE_NEXT'

def build_remesh_via_sdf(voxel_size=0.1, threshold=0.0):
def build_remesh_via_sdf(voxel_size=0.1, threshold=0.0, material=None):
tree = bpy.data.node_groups.new("SDFRemesh", 'GeometryNodeTree')
tree.interface.new_socket(name="Geometry", in_out='INPUT', socket_type='NodeSocketGeometry')
tree.interface.new_socket(name="Geometry", in_out='OUTPUT', socket_type='NodeSocketGeometry')
Expand All @@ -30,7 +30,15 @@ def build_remesh_via_sdf(voxel_size=0.1, threshold=0.0):
grid_to_mesh.inputs["Threshold"].default_value = threshold
tree.links.new(gi.outputs["Geometry"], mesh_to_sdf.inputs["Mesh"])
link = tree.links.new(mesh_to_sdf.outputs["SDF Grid"], grid_to_mesh.inputs["Grid"])
tree.links.new(grid_to_mesh.outputs["Mesh"], go.inputs["Geometry"])
# GN-generated geometry carries no material, so the input mesh's material is dropped on
# remesh. Re-apply it inside the tree with a Set Material node (the GN-native fix).
out_socket = grid_to_mesh.outputs["Mesh"]
if material is not None:
set_mat = tree.nodes.new('GeometryNodeSetMaterial')
set_mat.inputs["Material"].default_value = material
tree.links.new(out_socket, set_mat.inputs["Geometry"])
out_socket = set_mat.outputs["Geometry"]
tree.links.new(out_socket, go.inputs["Geometry"])
return tree, link.is_valid

def build():
Expand Down Expand Up @@ -89,13 +97,19 @@ def main():

obj = build()
base = len(obj.data.vertices)
tree, link_valid = build_remesh_via_sdf()
src_mat = obj.data.materials[0] if obj.data.materials else None
tree, link_valid = build_remesh_via_sdf(material=src_mat)
obj.modifiers.new("sdf", 'NODES').node_group = tree
dg = bpy.context.evaluated_depsgraph_get(); ev = obj.evaluated_get(dg)
m = ev.to_mesh(); evc = len(m.vertices); ev.to_mesh_clear()
print(f"link_valid={link_valid} base_vcount={base} eval_vcount={evc}")
m = ev.to_mesh(); evc = len(m.vertices)
mat_names = [mm.name for mm in m.materials if mm is not None]
ev.to_mesh_clear()
print(f"link_valid={link_valid} base_vcount={base} eval_vcount={evc} materials={mat_names}")
if not (link_valid and evc > 0 and evc != base):
print("ERROR: SDF remesh produced no/unchanged geometry", file=sys.stderr); return 3
# the Set Material node must carry the input material onto the remeshed result
if src_mat is not None and src_mat.name not in mat_names:
print(f"ERROR: material '{src_mat.name}' dropped by remesh", file=sys.stderr); return 6

if args.output:
if not render_still(obj, args.output, args.engine):
Expand Down
Loading