From bb8df75a8dfa864e8444b3844f30534a1e9b39a0 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Thu, 18 Jun 2026 23:38:15 -0400 Subject: [PATCH 1/2] fix: set id_type before assigning Scene id in driver_namespace example The drivers skill's driver_namespace worked example assigned var.targets[0].id = bpy.context.scene without first setting id_type='SCENE'. A SINGLE_PROP target id pointer defaults to OBJECT, so the bare assignment raises TypeError: DriverTarget.id expected a Object type, not Scene on both 4.5.10 LTS and 5.1.1. Added the id_type line (matching snippet driver-with-custom-function.py) and clarified the SINGLE_PROP prose. Verified: driver now attaches and location.z evaluates to [0.0, 2.425, 4.9985] across frames 1/50/100 on both builds. Signed-off-by: fOuttaMyPaint --- skills/drivers-and-app-handlers/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skills/drivers-and-app-handlers/SKILL.md b/skills/drivers-and-app-handlers/SKILL.md index a894567..4912085 100644 --- a/skills/drivers-and-app-handlers/SKILL.md +++ b/skills/drivers-and-app-handlers/SKILL.md @@ -69,7 +69,7 @@ fcurve.driver.expression = 'src_x * 2.0' Common variable types: -- `'SINGLE_PROP'`: read any RNA property. Set `targets[0].id = some_id` and `targets[0].data_path = 'some.path'`. +- `'SINGLE_PROP'`: read any RNA property. Set `targets[0].id = some_id` and `targets[0].data_path = 'some.path'`. The target id pointer defaults to the `OBJECT` type; to point at a non-object datablock (a Scene, Material, etc.) set `targets[0].id_type` first, e.g. `targets[0].id_type = 'SCENE'`, otherwise the `id =` assignment raises `TypeError`. - `'TRANSFORMS'`: read a transform channel. Set `transform_type` (`LOC_X`, `ROT_Y`, `SCALE_Z`, etc.). - `'ROTATION_DIFF'`: angle between two bones in radians. - `'LOC_DIFF'`: distance between two object locations. @@ -107,6 +107,7 @@ fcurve.driver.type = 'SCRIPTED' var = fcurve.driver.variables.new() var.name = 't' var.type = 'SINGLE_PROP' +var.targets[0].id_type = 'SCENE' # required before assigning a non-Object id var.targets[0].id = bpy.context.scene var.targets[0].data_path = 'frame_current' From e4bb0ca11275289f757f65c208c678eb186a96bd Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Thu, 18 Jun 2026 23:38:16 -0400 Subject: [PATCH 2/2] fix: mesh SDF grids with GridToMesh, not VolumeToMesh, in GN example build_remesh_via_sdf wired MeshToSDFGrid's 'SDF Grid' output (a grid/float socket) into VolumeToMesh's 'Volume' input (a geometry socket). That link is is_valid=False, so VolumeToMesh received no data and the evaluated modifier produced 0 vertices on both 4.5.10 LTS and 5.1.1, at every Voxel Size/Band Width/Threshold combination tried. Root cause: VolumeToMesh meshes a volume geometry (as produced by MeshToVolume), not a bare grid. Switched to GeometryNodeGridToMesh (Grid input is type-compatible) with threshold=0.0 (SDF zero-level). Verified: cube remesh now yields 10088 verts (5.1.1) / 9602 (4.5.10), zrange (-1.0, 1.0). Updated the heading and node-reference table accordingly. Signed-off-by: fOuttaMyPaint --- skills/geometry-nodes-python/SKILL.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/skills/geometry-nodes-python/SKILL.md b/skills/geometry-nodes-python/SKILL.md index c399dd4..d6b6a95 100644 --- a/skills/geometry-nodes-python/SKILL.md +++ b/skills/geometry-nodes-python/SKILL.md @@ -155,7 +155,8 @@ The argument is the exact RNA `bl_idname` of the node class. A few you'll reach | Mix | `ShaderNodeMix` | | Noise Texture | `ShaderNodeTexNoise` | | Mesh to SDF Grid (4.3+) | `GeometryNodeMeshToSDFGrid` | -| SDF Grid to Mesh / Volume to Mesh | `GeometryNodeVolumeToMesh` | +| Grid to Mesh (meshes an SDF/grid) | `GeometryNodeGridToMesh` | +| Volume to Mesh (meshes a volume geometry) | `GeometryNodeVolumeToMesh` | | Repeat Input / Output | `GeometryNodeRepeatInput`, `GeometryNodeRepeatOutput` | | For Each Element Input / Output (4.3+) | `GeometryNodeForeachGeometryElementInput`, `GeometryNodeForeachGeometryElementOutput` | @@ -274,13 +275,19 @@ def has_for_each_element(): 6. **Building the tree without group input/output nodes**. The tree's interface sockets only matter once you have `NodeGroupInput` and `NodeGroupOutput` instances connected to actual nodes inside the tree. -## Worked example: replicate the "Mesh to SDF then Volume to Mesh" pipeline +## Worked example: replicate the "Mesh to SDF then Grid to Mesh" pipeline + +An SDF grid is meshed with **Grid to Mesh** (`GeometryNodeGridToMesh`), not **Volume to +Mesh**. The `Mesh to SDF Grid` output is a *grid* socket; `Volume to Mesh` takes a *volume +geometry* socket (what `Mesh to Volume` produces), so wiring the SDF grid into it is an +invalid connection that silently yields no geometry. `Grid to Mesh` has the matching grid +input. For an SDF the surface is at distance 0, so use `threshold=0.0`. ```python import bpy -def build_remesh_via_sdf(voxel_size=0.05, threshold=0.5): +def build_remesh_via_sdf(voxel_size=0.05, threshold=0.0): tree = bpy.data.node_groups.new(name="SDFRemesh", type='GeometryNodeTree') tree.interface.new_socket(name="Geometry", in_out='INPUT', socket_type='NodeSocketGeometry') @@ -289,19 +296,19 @@ def build_remesh_via_sdf(voxel_size=0.05, threshold=0.5): grp_in = tree.nodes.new('NodeGroupInput') grp_out = tree.nodes.new('NodeGroupOutput') mesh_to_sdf = tree.nodes.new('GeometryNodeMeshToSDFGrid') - volume_to_mesh = tree.nodes.new('GeometryNodeVolumeToMesh') + grid_to_mesh = tree.nodes.new('GeometryNodeGridToMesh') mesh_to_sdf.inputs["Voxel Size"].default_value = voxel_size - volume_to_mesh.inputs["Threshold"].default_value = threshold + grid_to_mesh.inputs["Threshold"].default_value = threshold # isosurface at the SDF zero-level grp_in.location = (-400, 0) mesh_to_sdf.location = (-150, 0) - volume_to_mesh.location = (150, 0) + grid_to_mesh.location = (150, 0) grp_out.location = (400, 0) tree.links.new(grp_in.outputs["Geometry"], mesh_to_sdf.inputs["Mesh"]) - tree.links.new(mesh_to_sdf.outputs["SDF Grid"], volume_to_mesh.inputs["Volume"]) - tree.links.new(volume_to_mesh.outputs["Mesh"], grp_out.inputs["Geometry"]) + tree.links.new(mesh_to_sdf.outputs["SDF Grid"], grid_to_mesh.inputs["Grid"]) + tree.links.new(grid_to_mesh.outputs["Mesh"], grp_out.inputs["Geometry"]) return tree ```