kopia lustrzana https://github.com/carson-katri/geometry-script
Porównaj commity
7 Commity
da99654edb
...
6952ec507a
Autor | SHA1 | Data |
---|---|---|
Alfredo | 6952ec507a | |
Alfredo | e380e6f9db | |
Alfredo | f0d43fb92d | |
Alfredo | 5cf07a1af5 | |
Carson Katri | 8a1b4c4321 | |
Carson Katri | 6c25f12729 | |
Carson Katri | 56d61980ad |
|
@ -1,34 +1,42 @@
|
|||
import bpy
|
||||
import typing
|
||||
from collections import deque, Counter
|
||||
|
||||
def _arrange(node_tree, padding: typing.Tuple[float, float] = (50, 25)):
|
||||
# Organize the nodes into columns based on their links.
|
||||
columns: typing.List[typing.List[typing.Any]] = []
|
||||
def contains_link(node, column):
|
||||
return any(
|
||||
any(
|
||||
any(link.from_node == node for link in input.links)
|
||||
for input in n.inputs
|
||||
)
|
||||
for n in column
|
||||
)
|
||||
for node in reversed(node_tree.nodes):
|
||||
if (x := next(
|
||||
filter(
|
||||
lambda x: contains_link(node, x[1]),
|
||||
enumerate(columns)
|
||||
),
|
||||
None
|
||||
)) is not None:
|
||||
if x[0] > 0:
|
||||
columns[x[0] - 1].append(node)
|
||||
else:
|
||||
columns.insert(x[0], [node])
|
||||
|
||||
def topo_sort(graph):
|
||||
in_degree = {u: 0 for u in graph}
|
||||
for u in graph:
|
||||
for v in graph[u]:
|
||||
in_degree[v] += 1
|
||||
queue = deque([u for u in in_degree if in_degree[u] == 0])
|
||||
topo_order = []
|
||||
while queue:
|
||||
u = queue.popleft()
|
||||
topo_order.append(u)
|
||||
for v in graph[u]:
|
||||
in_degree[v] -= 1
|
||||
if in_degree[v] == 0:
|
||||
queue.append(v)
|
||||
return topo_order
|
||||
|
||||
graph = { node:set() for node in node_tree.nodes }
|
||||
node_input_link_count = Counter()
|
||||
for link in node_tree.links:
|
||||
graph[link.from_node].add(link.to_node)
|
||||
node_input_link_count[link.to_socket] += 1
|
||||
sorted_nodes = topo_sort(graph)
|
||||
|
||||
column_index = {}
|
||||
for node in reversed(sorted_nodes):
|
||||
column_index[node] = max([ column_index[adj_node] for adj_node in graph[node] ], default=-1) + 1
|
||||
if column_index[node] == len(columns):
|
||||
columns.append([node])
|
||||
else:
|
||||
if len(columns) == 0:
|
||||
columns.append([node])
|
||||
else:
|
||||
columns[len(columns) - 1].append(node)
|
||||
columns[column_index[node]].append(node)
|
||||
columns = reversed(columns)
|
||||
|
||||
# Arrange the columns, computing the size of the node manually so arrangement can be done without UI being visible.
|
||||
UI_SCALE = bpy.context.preferences.view.ui_scale
|
||||
|
@ -46,7 +54,7 @@ def _arrange(node_tree, padding: typing.Tuple[float, float] = (50, 25)):
|
|||
output_count = len(list(filter(lambda i: i.enabled, node.outputs)))
|
||||
parent_props = [prop.identifier for base in type(node).__bases__ for prop in base.bl_rna.properties]
|
||||
properties_count = len([prop for prop in node.bl_rna.properties if prop.identifier not in parent_props])
|
||||
unset_vector_count = len(list(filter(lambda i: i.enabled and i.type == 'VECTOR' and len(i.links) == 0, node.inputs)))
|
||||
unset_vector_count = len(list(filter(lambda i: i.enabled and i.type == 'VECTOR' and node_input_link_count[i] == 0, node.inputs)))
|
||||
node_height = (
|
||||
NODE_HEADER_HEIGHT \
|
||||
+ (output_count * NODE_LINK_HEIGHT) \
|
||||
|
|
|
@ -66,9 +66,10 @@ class Attribute:
|
|||
Creates a "Store Named Attribute" node with the correct arguments passed, and returns the modified `Geometry`.
|
||||
"""
|
||||
from geometry_script import store_named_attribute
|
||||
if 'domain' not in kwargs:
|
||||
kwargs['domain'] = self.domain
|
||||
return store_named_attribute(
|
||||
data_type=self.data_type,
|
||||
domain=self.domain,
|
||||
geometry=geometry,
|
||||
name=self.name,
|
||||
value=value,
|
||||
|
|
52
api/tree.py
52
api/tree.py
|
@ -16,6 +16,8 @@ from .static.sample_mode import *
|
|||
from .static.simulation import *
|
||||
from .arrange import _arrange
|
||||
|
||||
IS_BLENDER_4 = bpy.app.version[0] >= 4
|
||||
|
||||
def _as_iterable(x):
|
||||
if isinstance(x, Type):
|
||||
return [x,]
|
||||
|
@ -24,8 +26,16 @@ def _as_iterable(x):
|
|||
except TypeError:
|
||||
return [x,]
|
||||
|
||||
get_node_inputs = lambda x: [i for i in x.interface.items_tree if i.item_type == 'SOCKET' and i.in_out == 'INPUT']
|
||||
get_node_outputs = lambda x: [i for i in x.interface.items_tree if i.item_type == 'SOCKET' and i.in_out == 'OUTPUT']
|
||||
def get_node_inputs(x):
|
||||
if IS_BLENDER_4:
|
||||
return [i for i in x.interface.items_tree if i.item_type == 'SOCKET' and i.in_out == 'INPUT']
|
||||
else:
|
||||
return x.inputs
|
||||
def get_node_outputs(x):
|
||||
if IS_BLENDER_4:
|
||||
return [i for i in x.interface.items_tree if i.item_type == 'SOCKET' and i.in_out == 'OUTPUT']
|
||||
else:
|
||||
return x.outputs
|
||||
|
||||
def tree(name):
|
||||
tree_name = name
|
||||
|
@ -39,7 +49,8 @@ def tree(name):
|
|||
else:
|
||||
node_group = bpy.data.node_groups.new(tree_name, 'GeometryNodeTree')
|
||||
|
||||
node_group.is_modifier = True
|
||||
if IS_BLENDER_4:
|
||||
node_group.is_modifier = True
|
||||
|
||||
# Clear the node group before building
|
||||
for node in node_group.nodes:
|
||||
|
@ -48,10 +59,16 @@ def tree(name):
|
|||
node_inputs = get_node_inputs(node_group)
|
||||
input_count = sum(map(lambda p: len(p.annotation.__annotations__) if issubclass(p.annotation, InputGroup) else 1, list(signature.parameters.values())))
|
||||
for node_input in node_inputs[input_count:]:
|
||||
node_group.interface.remove(node_input)
|
||||
if IS_BLENDER_4:
|
||||
node_group.interface.remove(node_input)
|
||||
else:
|
||||
node_group.inputs.remove(node_input)
|
||||
|
||||
for group_output in get_node_outputs(node_group):
|
||||
node_group.interface.remove(group_output)
|
||||
if IS_BLENDER_4:
|
||||
node_group.interface.remove(group_output)
|
||||
else:
|
||||
node_group.outputs.remove(group_output)
|
||||
|
||||
# Setup the group inputs
|
||||
group_input_node = node_group.nodes.new('NodeGroupInput')
|
||||
|
@ -80,7 +97,10 @@ def tree(name):
|
|||
for i, node_input in enumerate(node_inputs):
|
||||
if node_input.bl_socket_idname != list(inputs.values())[i][0].socket_type:
|
||||
for ni in node_inputs:
|
||||
node_group.interface.remove(ni)
|
||||
if IS_BLENDER_4:
|
||||
node_group.interface.remove(ni)
|
||||
else:
|
||||
node_group.inputs.remove(ni)
|
||||
break
|
||||
builder_inputs = {}
|
||||
|
||||
|
@ -91,7 +111,10 @@ def tree(name):
|
|||
node_inputs[i].name = input_name
|
||||
node_input = node_inputs[i]
|
||||
else:
|
||||
node_input = node_group.interface.new_socket(socket_type=arg[1][0].socket_type, name=input_name, in_out='INPUT')
|
||||
if IS_BLENDER_4:
|
||||
node_input = node_group.interface.new_socket(socket_type=arg[1][0].socket_type, name=input_name, in_out='INPUT')
|
||||
else:
|
||||
node_input = node_group.inputs.new(arg[1][0].socket_type, input_name)
|
||||
if arg[1][1] != inspect.Parameter.empty:
|
||||
node_input.default_value = arg[1][1]
|
||||
if arg[1][2] is not None:
|
||||
|
@ -118,14 +141,20 @@ def tree(name):
|
|||
for i, (k, v) in enumerate(outputs.items()):
|
||||
if not issubclass(type(v), Type):
|
||||
v = Type(value=v)
|
||||
node_group.interface.new_socket(socket_type=v.socket_type, name=k, in_out='OUTPUT')
|
||||
if IS_BLENDER_4:
|
||||
node_group.interface.new_socket(socket_type=v.socket_type, name=k, in_out='OUTPUT')
|
||||
else:
|
||||
node_group.outputs.new(v.socket_type, k)
|
||||
node_group.links.new(v._socket, group_output_node.inputs[i])
|
||||
else:
|
||||
for i, result in enumerate(_as_iterable(outputs)):
|
||||
if not issubclass(type(result), Type):
|
||||
result = Type(value=result)
|
||||
# raise Exception(f"Return value '{result}' is not a valid 'Type' subclass.")
|
||||
node_group.interface.new_socket(socket_type=result.socket_type, name='Result', in_out='OUTPUT')
|
||||
if IS_BLENDER_4:
|
||||
node_group.interface.new_socket(socket_type=result.socket_type, name='Result', in_out='OUTPUT')
|
||||
else:
|
||||
node_group.outputs.new(result.socket_type, 'Result')
|
||||
node_group.links.new(result._socket, group_output_node.inputs[i])
|
||||
|
||||
_arrange(node_group)
|
||||
|
@ -133,7 +162,10 @@ def tree(name):
|
|||
# Return a function that creates a NodeGroup node in the tree.
|
||||
# This lets @trees be used in other @trees via simple function calls.
|
||||
def group_reference(*args, **kwargs):
|
||||
result = geometrynodegroup(node_tree=node_group, *args, **kwargs)
|
||||
if IS_BLENDER_4:
|
||||
result = geometrynodegroup(node_tree=node_group, *args, **kwargs)
|
||||
else:
|
||||
result = group(node_tree=node_group, *args, **kwargs)
|
||||
group_outputs = []
|
||||
for group_output in result._socket.node.outputs:
|
||||
group_outputs.append(Type(group_output))
|
||||
|
|
Ładowanie…
Reference in New Issue