Fix: Node Tools: Image data-block inputs broken

- Because these data-blocks don't use the copy-on-eval system,
  they need special handling in the system that creates evaluated
  data-blocks for use inside the node tool execution.
- The UI didn't account for the missing support of string name referenced
  data-blocks in `template_id`. It already did for font sockets a few lines up
  though. Fix the same problem for sound inputs.

Pull Request: https://projects.blender.org/blender/blender/pulls/158301
This commit is contained in:
Hans Goudey 2026-05-07 17:22:55 -04:00 • committed by Gitea
parent b68a2f3921
commit 7ca5713d99
3 changed files with 90 additions and 11 deletions

View file

@ -553,20 +553,37 @@ static void draw_property_for_socket(DrawGroupInputsContext &ctx,
break;
}
case SOCK_SOUND: {
template_id(&row, &ctx.C, socket_props_ptr, "value", nullptr, "SOUND_OT_open", nullptr);
PropertyRNA *prop = RNA_struct_find_property(socket_props_ptr, "value");
if (prop && RNA_property_type(prop) == PROP_POINTER) {
template_id(&row, &ctx.C, socket_props_ptr, "value", nullptr, "SOUND_OT_open", nullptr);
}
else {
/* #template_id only supports pointer properties currently. Node tools store
* data-block pointers in strings currently. */
row.prop_search(socket_props_ptr, "value", ctx.bmain_ptr, "images", name, ICON_IMAGE_DATA);
}
break;
}
case SOCK_IMAGE: {
template_id(&row,
&ctx.C,
socket_props_ptr,
"value",
"image.new",
"image.open",
nullptr,
ui::TEMPLATE_ID_FILTER_ALL,
false,
name);
PropertyRNA *prop = RNA_struct_find_property(socket_props_ptr, "value");
if (prop && RNA_property_type(prop) == PROP_POINTER) {
template_id(&row,
&ctx.C,
socket_props_ptr,
"value",
"image.new",
"image.open",
nullptr,
ui::TEMPLATE_ID_FILTER_ALL,
false,
name);
}
else {
/* #template_id only supports pointer properties currently. Node tools store
* data-block pointers in strings currently. */
row.prop_search(socket_props_ptr, "value", ctx.bmain_ptr, "images", name, ICON_IMAGE_DATA);
}
break;
}
case SOCK_MENU: {

View file

@ -4330,6 +4330,9 @@ static const ID *get_only_evaluated_id(const Depsgraph &depsgraph, const ID &id_
const ID *GeoNodesOperatorDepsgraphs::get_evaluated_id(const ID &id_orig) const
{
if (!ID_TYPE_USE_COPY_ON_EVAL(GS(id_orig.name))) {
return &id_orig;
}
if (const Depsgraph *graph = this->active) {
if (const ID *id = get_only_evaluated_id(*graph, id_orig)) {
return id;

View file

@ -165,6 +165,65 @@ class TestNodeTool(unittest.TestCase):
self.assertAlmostEqual(center_y, 10.0, places=4)
self.assertAlmostEqual(center_z, 0.0, places=4)
def test_image_input_sample_texture(self):
from bpy.types import WindowManager
# Build a 32x32 image: left half white, right half black.
size = 32
image = bpy.data.images.new("TestImage", width=size, height=size)
white = [1.0, 1.0, 1.0, 1.0]
black = [0.0, 0.0, 0.0, 1.0]
row = (white * (size // 2)) + (black * (size // 2))
pixels = row * size
image.pixels.foreach_set(pixels)
image.update()
bpy.ops.mesh.primitive_plane_add()
plane = bpy.context.active_object
tree = create_object_mode_mesh_tool_tree(
"TestNodeToolImage", "geometry.test_node_tool_image"
)
tree.interface.new_socket("Geometry", in_out='INPUT', socket_type='NodeSocketGeometry')
image_socket = tree.interface.new_socket(
"Image", in_out='INPUT', socket_type='NodeSocketImage')
tree.interface.new_socket("Geometry", in_out='OUTPUT', socket_type='NodeSocketGeometry')
group_input = tree.nodes.new("NodeGroupInput")
group_output = tree.nodes.new("NodeGroupOutput")
uv_attr = tree.nodes.new("GeometryNodeInputNamedAttribute")
uv_attr.data_type = 'FLOAT_VECTOR'
uv_attr.inputs["Name"].default_value = "UVMap"
image_texture = tree.nodes.new("GeometryNodeImageTexture")
# Avoid edge interpolation/wrap effects so the leftmost vertices sample pure white.
image_texture.interpolation = 'Closest'
image_texture.extension = 'EXTEND'
store_attr = tree.nodes.new("GeometryNodeStoreNamedAttribute")
store_attr.data_type = 'FLOAT'
store_attr.inputs["Name"].default_value = "sampled_value"
tree.links.new(group_input.outputs["Geometry"], store_attr.inputs["Geometry"])
tree.links.new(group_input.outputs["Image"], image_texture.inputs["Image"])
tree.links.new(uv_attr.outputs["Attribute"], image_texture.inputs["Vector"])
tree.links.new(image_texture.outputs["Color"], store_attr.inputs["Value"])
tree.links.new(store_attr.outputs["Geometry"], group_output.inputs["Geometry"])
WindowManager.register_node_group_operators()
bpy.ops.geometry.test_node_tool_image(
'EXEC_DEFAULT',
inputs={image_socket.identifier: {"value": image.name}},
)
value_attr = plane.data.attributes["sampled_value"]
left_vertex_indices = [i for i, v in enumerate(plane.data.vertices) if v.co.x < 0.0]
self.assertGreater(len(left_vertex_indices), 0)
for i in left_vertex_indices:
self.assertAlmostEqual(value_attr.data[i].value, 1.0, places=2)
if __name__ == "__main__":
import sys