From 093262acf8c695c56fe49156a9e800bff74c2fd9 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Sat, 20 Jun 2026 11:36:15 -0400 Subject: [PATCH] fix: carry material through the GN SDF remesh with Set Material GN-generated geometry carries no material, so the input mesh's material was dropped on remesh and the result rendered default white -- a real user gotcha. build_remesh_via_sdf now re-applies the input material inside the tree via a GeometryNodeSetMaterial node on the GridToMesh output (the GN-native fix; verified to carry through on both builds: eval mesh materials=['Clay']). Added a material-present assertion (the source material must appear on the evaluated mesh) alongside the existing vertex-delta check, and a Materials gotcha note in the README. Verified headless on Blender 4.5.10 LTS and 5.1.1. Signed-off-by: fOuttaMyPaint --- examples/gn-sdf-remesh/README.md | 5 +++++ examples/gn-sdf-remesh/gn_sdf_remesh.py | 24 +++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/examples/gn-sdf-remesh/README.md b/examples/gn-sdf-remesh/README.md index 1c31377..6f577b1 100644 --- a/examples/gn-sdf-remesh/README.md +++ b/examples/gn-sdf-remesh/README.md @@ -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 diff --git a/examples/gn-sdf-remesh/gn_sdf_remesh.py b/examples/gn-sdf-remesh/gn_sdf_remesh.py index 2769095..c05907e 100644 --- a/examples/gn-sdf-remesh/gn_sdf_remesh.py +++ b/examples/gn-sdf-remesh/gn_sdf_remesh.py @@ -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') @@ -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(): @@ -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):