procfunc 0.33.1__tar.gz → 0.34.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {procfunc-0.33.1/src/procfunc.egg-info → procfunc-0.34.0}/PKG-INFO +3 -1
- {procfunc-0.33.1 → procfunc-0.34.0}/pyproject.toml +3 -1
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/__init__.py +1 -1
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/color.py +8 -11
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/__init__.py +0 -1
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/util.py +96 -14
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/context.py +0 -40
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/control/__init__.py +2 -5
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/color.py +4 -4
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/construct_standard.py +5 -9
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/util.py +2 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/func.py +21 -17
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/geo.py +10 -55
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/manifest.json +13 -627
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/math.py +72 -4
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/shader.py +0 -39
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/texture.py +99 -97
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/util/bindings_util.py +0 -35
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/attr.py +6 -3
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/extract_materials.py +38 -16
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transpiler/bpy_to_computegraph.py +21 -15
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transpiler/parse_special_cases.py +23 -6
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/bpy_info.py +18 -16
- {procfunc-0.33.1 → procfunc-0.34.0/src/procfunc.egg-info}/PKG-INFO +3 -1
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc.egg-info/requires.txt +2 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_ops.py +28 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/LICENSE.md +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/README.md +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/setup.cfg +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/cli/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/cli/main.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/codegen/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/codegen/codegen.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/codegen/identifiers.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/codegen/repr.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/compute_graph.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/node.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/operators_info.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/compute_graph/proxy.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/compositor.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/construct_nodes.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/construct_operator.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/construct_special_cases.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/execute.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/infer_runtime_data_type.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/execute/realize.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/types.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/util/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/util/bpy_node_info.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/nodes/util/node_function.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/_util.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/addons.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/collection.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/curve.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/file.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/manifest.json +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/mesh.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/modifier.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/object.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/primitives/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/primitives/camera.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/primitives/curve.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/primitives/light.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/primitives/mesh.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/ops/uv.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/random.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/tracer/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/tracer/decorator.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/tracer/patch.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/tracer/proxy.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/tracer/trace.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/cleanup.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/convert.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/distribution.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/infer_distribution.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/parameters.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transforms/util.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transpiler/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transpiler/main.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/transpiler/parse_default_values.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/types.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/__init__.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/bpy_data.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/camera.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/keyframe.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/log.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/manifest.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/pytree.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc/util/teardown.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc.egg-info/SOURCES.txt +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc.egg-info/dependency_links.txt +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc.egg-info/entry_points.txt +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/src/procfunc.egg-info/top_level.txt +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_asset.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_bpy_data_cleanup.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_cli_transpile.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_codegen.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_codegen_matrix.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_compute_graph.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_node_function.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_pytree.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_random.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_trace.py +0 -0
- {procfunc-0.33.1 → procfunc-0.34.0}/tests/test_transforms.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: procfunc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.34.0
|
|
4
4
|
Summary: Function-Oriented Abstractions for Procedural 3D Generation in Python
|
|
5
5
|
License-Expression: BSD-3-Clause
|
|
6
6
|
Project-URL: Homepage, https://github.com/princeton-vl/procfunc
|
|
@@ -16,6 +16,8 @@ Requires-Dist: pytest; extra == "dev"
|
|
|
16
16
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
17
17
|
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
|
|
18
18
|
Requires-Dist: ty; extra == "dev"
|
|
19
|
+
Requires-Dist: imageio; extra == "dev"
|
|
20
|
+
Requires-Dist: matplotlib; extra == "dev"
|
|
19
21
|
Provides-Extra: docs
|
|
20
22
|
Requires-Dist: sphinx; extra == "docs"
|
|
21
23
|
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
@@ -10,6 +10,8 @@ def hsv_color(
|
|
|
10
10
|
saturation: float | None = None,
|
|
11
11
|
value: float | None = None,
|
|
12
12
|
) -> t.Color:
|
|
13
|
+
if hsv is None and (hue is None or saturation is None or value is None):
|
|
14
|
+
raise ValueError("provide hsv=... or all of hue/saturation/value")
|
|
13
15
|
color = t.Color()
|
|
14
16
|
if hsv is not None:
|
|
15
17
|
color.hsv = hsv
|
|
@@ -27,12 +29,9 @@ def rgb_color(
|
|
|
27
29
|
b: float | None = None,
|
|
28
30
|
rgb: np.ndarray | None = None,
|
|
29
31
|
) -> t.Color:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
else:
|
|
34
|
-
color.r, color.g, color.b = r, g, b
|
|
35
|
-
return color
|
|
32
|
+
if rgb is None and (r is None or g is None or b is None):
|
|
33
|
+
raise ValueError("provide rgb=... or all of r/g/b")
|
|
34
|
+
return t.Color(rgb if rgb is not None else (r, g, b))
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
def _srgb_to_linearrgb(c):
|
|
@@ -44,14 +43,12 @@ def _srgb_to_linearrgb(c):
|
|
|
44
43
|
return ((c + 0.055) / 1.055) ** 2.4
|
|
45
44
|
|
|
46
45
|
|
|
47
|
-
def _hex_to_rgb(h: int
|
|
46
|
+
def _hex_to_rgb(h: int):
|
|
48
47
|
r = (h & 0xFF0000) >> 16
|
|
49
48
|
g = (h & 0x00FF00) >> 8
|
|
50
49
|
b = h & 0x0000FF
|
|
51
50
|
return tuple([_srgb_to_linearrgb(c / 0xFF) for c in (r, g, b)])
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
def hex_color(h: int
|
|
55
|
-
|
|
56
|
-
c.r, c.g, c.b = _hex_to_rgb(h, alpha)
|
|
57
|
-
return c
|
|
53
|
+
def hex_color(h: int) -> t.Color:
|
|
54
|
+
return t.Color(_hex_to_rgb(h))
|
|
@@ -3,10 +3,21 @@ import logging
|
|
|
3
3
|
from collections import defaultdict, deque
|
|
4
4
|
from typing import Any, Callable, Generator, Literal, TypeVar
|
|
5
5
|
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
6
8
|
from procfunc.util import pytree
|
|
7
9
|
|
|
8
10
|
from .compute_graph import ComputeGraph
|
|
9
|
-
from .node import
|
|
11
|
+
from .node import (
|
|
12
|
+
ConstantNode,
|
|
13
|
+
FunctionCallNode,
|
|
14
|
+
GetAttributeNode,
|
|
15
|
+
InputPlaceholderNode,
|
|
16
|
+
MethodCallNode,
|
|
17
|
+
Node,
|
|
18
|
+
ProceduralNode,
|
|
19
|
+
SubgraphCallNode,
|
|
20
|
+
)
|
|
10
21
|
|
|
11
22
|
logger = logging.getLogger(__name__)
|
|
12
23
|
|
|
@@ -40,6 +51,7 @@ def traverse_breadth_first(
|
|
|
40
51
|
|
|
41
52
|
visited = set()
|
|
42
53
|
frontier = deque((None, name, node) for name, node in graph.outputs.items())
|
|
54
|
+
visited.update(id(node) for _, _, node in frontier)
|
|
43
55
|
# logger.debug(f"{traverse_breadth_first.__name__} {graph.name} {len(frontier)=}")
|
|
44
56
|
|
|
45
57
|
def res(parent, name, child):
|
|
@@ -61,10 +73,6 @@ def traverse_breadth_first(
|
|
|
61
73
|
if not isinstance(node, Node):
|
|
62
74
|
continue
|
|
63
75
|
|
|
64
|
-
if id(node) in visited:
|
|
65
|
-
continue
|
|
66
|
-
visited.add(id(node))
|
|
67
|
-
|
|
68
76
|
yield res(parent, name, node)
|
|
69
77
|
|
|
70
78
|
children = list(pytree.PyTree(node.args).items()) + list(
|
|
@@ -75,6 +83,7 @@ def traverse_breadth_first(
|
|
|
75
83
|
continue
|
|
76
84
|
if id(arg) in visited:
|
|
77
85
|
continue
|
|
86
|
+
visited.add(id(arg))
|
|
78
87
|
frontier.append((node, key, arg))
|
|
79
88
|
|
|
80
89
|
|
|
@@ -201,22 +210,95 @@ def usages_per_node(
|
|
|
201
210
|
return dict(usages)
|
|
202
211
|
|
|
203
212
|
|
|
204
|
-
def
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
213
|
+
def _value_equal(a: Any, b: Any) -> bool:
|
|
214
|
+
"""Array-safe equality for non-node values (constants, attrs, defaults)."""
|
|
215
|
+
if a is b:
|
|
216
|
+
return True
|
|
217
|
+
if isinstance(a, np.ndarray) or isinstance(b, np.ndarray):
|
|
218
|
+
return np.array_equal(a, b)
|
|
219
|
+
if isinstance(a, dict) and isinstance(b, dict):
|
|
220
|
+
return a.keys() == b.keys() and all(_value_equal(a[k], b[k]) for k in a)
|
|
221
|
+
if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):
|
|
222
|
+
return (
|
|
223
|
+
type(a) is type(b)
|
|
224
|
+
and len(a) == len(b)
|
|
225
|
+
and all(_value_equal(x, y) for x, y in zip(a, b))
|
|
226
|
+
)
|
|
227
|
+
try:
|
|
228
|
+
return bool(a == b)
|
|
229
|
+
except (ValueError, TypeError):
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _args_equal(a: Any, b: Any, memo: dict[tuple[int, int], bool]) -> bool:
|
|
234
|
+
"""Structural equality of an args/kwargs tree: same container shape, with
|
|
235
|
+
node-valued leaves compared recursively and other leaves by value."""
|
|
236
|
+
tree_a = pytree.PyTree(a)
|
|
237
|
+
tree_b = pytree.PyTree(b)
|
|
238
|
+
if tree_a.spec != tree_b.spec:
|
|
208
239
|
return False
|
|
209
|
-
for
|
|
210
|
-
|
|
240
|
+
for leaf_a, leaf_b in zip(tree_a.values(), tree_b.values()):
|
|
241
|
+
a_is_node = isinstance(leaf_a, Node)
|
|
242
|
+
b_is_node = isinstance(leaf_b, Node)
|
|
243
|
+
if a_is_node != b_is_node:
|
|
211
244
|
return False
|
|
212
|
-
if
|
|
213
|
-
if not
|
|
245
|
+
if a_is_node:
|
|
246
|
+
if not _nodes_equal(leaf_a, leaf_b, memo):
|
|
214
247
|
return False
|
|
215
|
-
elif
|
|
248
|
+
elif not _value_equal(leaf_a, leaf_b):
|
|
216
249
|
return False
|
|
217
250
|
return True
|
|
218
251
|
|
|
219
252
|
|
|
253
|
+
def _nodes_equal(node1: Node, node2: Node, memo: dict[tuple[int, int], bool]) -> bool:
|
|
254
|
+
if node1 is node2:
|
|
255
|
+
return True
|
|
256
|
+
if type(node1) is not type(node2):
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
key = (id(node1), id(node2))
|
|
260
|
+
cached = memo.get(key)
|
|
261
|
+
if cached is not None:
|
|
262
|
+
return cached
|
|
263
|
+
memo[key] = True # optimistic, breaks cycles in shared DAGs
|
|
264
|
+
|
|
265
|
+
result = True
|
|
266
|
+
if isinstance(node1, SubgraphCallNode):
|
|
267
|
+
result = graph_nodes_equal(node1.subgraph, node2.subgraph)
|
|
268
|
+
if result and isinstance(node1, FunctionCallNode):
|
|
269
|
+
result = node1.func is node2.func
|
|
270
|
+
if result and isinstance(node1, MethodCallNode):
|
|
271
|
+
result = node1.method_name == node2.method_name
|
|
272
|
+
if result and isinstance(node1, GetAttributeNode):
|
|
273
|
+
result = node1.attribute_name == node2.attribute_name
|
|
274
|
+
if result and isinstance(node1, ProceduralNode):
|
|
275
|
+
result = node1.node_type == node2.node_type and _value_equal(
|
|
276
|
+
node1.attrs, node2.attrs
|
|
277
|
+
)
|
|
278
|
+
if result and isinstance(node1, ConstantNode):
|
|
279
|
+
result = _value_equal(node1.value, node2.value)
|
|
280
|
+
if result and isinstance(node1, InputPlaceholderNode):
|
|
281
|
+
result = node1.input_name == node2.input_name and _value_equal(
|
|
282
|
+
node1.default_value, node2.default_value
|
|
283
|
+
)
|
|
284
|
+
if result:
|
|
285
|
+
result = _args_equal(node1.args, node2.args, memo) and _args_equal(
|
|
286
|
+
node1.kwargs, node2.kwargs, memo
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
memo[key] = result
|
|
290
|
+
return result
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def graph_nodes_equal(graph1: ComputeGraph, graph2: ComputeGraph) -> bool:
|
|
294
|
+
nodes1 = list(traverse_depth_first(graph1))
|
|
295
|
+
nodes2 = list(traverse_depth_first(graph2))
|
|
296
|
+
if len(nodes1) != len(nodes2):
|
|
297
|
+
return False
|
|
298
|
+
memo: dict[tuple[int, int], bool] = {}
|
|
299
|
+
return all(_nodes_equal(node1, node2, memo) for node1, node2 in zip(nodes1, nodes2))
|
|
300
|
+
|
|
301
|
+
|
|
220
302
|
def transform_nodetree(
|
|
221
303
|
root: Node,
|
|
222
304
|
transform_fn: Callable[[Node], Any],
|
|
@@ -13,24 +13,6 @@ class ProcfuncContext:
|
|
|
13
13
|
num_cpu_cores: int
|
|
14
14
|
current_trace_level: int | None # compared against to TraceLevel int values
|
|
15
15
|
|
|
16
|
-
warn_mode_avoid_normal_bump: Literal["ignore", "warn", "throw"]
|
|
17
|
-
"""
|
|
18
|
-
Set to 'throw' for strict usage. Using a normal map / bump map / BSDF vector input _can_ be useful,
|
|
19
|
-
but its always better to do it via the Displacement output of the shader (so that it at least can also be done as displacement)
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
warn_mode_avoid_implicit_vector: Literal["ignore", "warn", "throw"]
|
|
23
|
-
"""
|
|
24
|
-
Set to 'throw' to force the user to specify exactly what vector to sample.
|
|
25
|
-
This prevents materials from being incorrect when on a moving object, or ignoring uv coordinates
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
warn_mode_avoid_io_nodes: Literal["ignore", "warn", "throw"]
|
|
29
|
-
"""
|
|
30
|
-
Set to 'throw' to prevent floating Value Vector Color nodes, or strange output nodes like AOV in shader
|
|
31
|
-
Intent is to force nodegroups to be more functional - all inputs and outputs go through nodegroup interface
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
16
|
warn_mode_empty_geonodes: Literal["ignore", "warn", "throw"]
|
|
35
17
|
"""
|
|
36
18
|
Controls behavior when a geometry node graph produces no mesh geometry (e.g. unconnected inputs).
|
|
@@ -44,16 +26,10 @@ class ProcfuncContext:
|
|
|
44
26
|
|
|
45
27
|
def set_strict(self):
|
|
46
28
|
"""Set all warning modes to 'throw'"""
|
|
47
|
-
self.warn_mode_avoid_normal_bump = "throw"
|
|
48
|
-
self.warn_mode_avoid_implicit_vector = "throw"
|
|
49
|
-
self.warn_mode_avoid_io_nodes = "throw"
|
|
50
29
|
self.warn_mode_empty_geonodes = "throw"
|
|
51
30
|
|
|
52
31
|
def set_warn(self):
|
|
53
32
|
"""Set all warning modes to 'warn'"""
|
|
54
|
-
self.warn_mode_avoid_normal_bump = "warn"
|
|
55
|
-
self.warn_mode_avoid_implicit_vector = "warn"
|
|
56
|
-
self.warn_mode_avoid_io_nodes = "warn"
|
|
57
33
|
self.warn_mode_empty_geonodes = "warn"
|
|
58
34
|
|
|
59
35
|
|
|
@@ -61,27 +37,11 @@ class ProcfuncContext:
|
|
|
61
37
|
|
|
62
38
|
warn_modes = ["ignore", "warn", "throw"]
|
|
63
39
|
|
|
64
|
-
_warn_mode_avoid_normal_bump = os.environ.get(
|
|
65
|
-
"PROCFUNC_WARN_MODE_AVOID_NORMAL_BUMP", "ignore"
|
|
66
|
-
)
|
|
67
|
-
assert _warn_mode_avoid_normal_bump in warn_modes
|
|
68
|
-
|
|
69
|
-
warn_mode_avoid_implicit_vector = os.environ.get(
|
|
70
|
-
"PROCFUNC_WARN_MODE_AVOID_IMPLICIT_VECTOR", "ignore"
|
|
71
|
-
)
|
|
72
|
-
assert warn_mode_avoid_implicit_vector in warn_modes
|
|
73
|
-
|
|
74
|
-
warn_mode_avoid_io_nodes = os.environ.get("PROCFUNC_WARN_MODE_AVOID_IO_NODES", "ignore")
|
|
75
|
-
assert warn_mode_avoid_io_nodes in warn_modes
|
|
76
|
-
|
|
77
40
|
_warn_mode_empty_geonodes = os.environ.get("PROCFUNC_WARN_MODE_EMPTY_GEONODES", "warn")
|
|
78
41
|
assert _warn_mode_empty_geonodes in warn_modes
|
|
79
42
|
|
|
80
43
|
globals = ProcfuncContext(
|
|
81
44
|
num_cpu_cores=int(os.environ.get("PROCFUNC_NUM_CPU_CORES", 0)),
|
|
82
|
-
warn_mode_avoid_normal_bump=_warn_mode_avoid_normal_bump, # type: ignore[invalid-assignment]
|
|
83
|
-
warn_mode_avoid_implicit_vector=warn_mode_avoid_implicit_vector, # type: ignore[invalid-assignment]
|
|
84
|
-
warn_mode_avoid_io_nodes=warn_mode_avoid_io_nodes, # type: ignore[invalid-assignment]
|
|
85
45
|
warn_mode_empty_geonodes=_warn_mode_empty_geonodes, # type: ignore[invalid-assignment]
|
|
86
46
|
current_trace_level=None,
|
|
87
47
|
)
|
|
@@ -127,12 +127,9 @@ def choice(
|
|
|
127
127
|
) -> T:
|
|
128
128
|
"""
|
|
129
129
|
Args:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
options: list of callables to choose from
|
|
133
|
-
chosen: if not None, use this value instead of choosing randomly. Cannot be traced, but may appear in the output of the tracer.
|
|
130
|
+
choice_rng: random number generator
|
|
131
|
+
choice_options: list of (value, weight) tuples; weights are normalized to a probability distribution
|
|
134
132
|
chosen_idx: if not None, use this index instead of choosing randomly. Cannot be traced, but may appear in the output of the tracer.
|
|
135
|
-
**child_kwargs: keyword arguments to pass to the chosen callable
|
|
136
133
|
|
|
137
134
|
TODO: this function should really take args and kwargs as tuple & dict, not via expansion
|
|
138
135
|
but this requires our Node to handle cases with pytrees as inputs. Currently it would fail to execute the children if they are hidden in a pytree
|
|
@@ -39,7 +39,7 @@ def mix_rgb(
|
|
|
39
39
|
clamp_factor: bool = True,
|
|
40
40
|
) -> nt.ProcNode[pt.Color]:
|
|
41
41
|
"""
|
|
42
|
-
Uses a Mix Node with
|
|
42
|
+
Uses a Mix Shader Node with data_type='RGBA'.
|
|
43
43
|
|
|
44
44
|
NOTE: separated from float/vector mix() due to extra arguments
|
|
45
45
|
|
|
@@ -80,7 +80,7 @@ def combine_rgb(
|
|
|
80
80
|
blue: nt.SocketOrVal[float] = 0.0,
|
|
81
81
|
) -> nt.ProcNode[pt.Color]:
|
|
82
82
|
"""
|
|
83
|
-
Uses a CombineColor Shader Node.
|
|
83
|
+
Uses a CombineColor Shader Node in RGB mode.
|
|
84
84
|
|
|
85
85
|
See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
|
|
86
86
|
"""
|
|
@@ -97,7 +97,7 @@ def combine_hsv(
|
|
|
97
97
|
value: nt.SocketOrVal[float] = 0.0,
|
|
98
98
|
) -> nt.ProcNode[pt.Color]:
|
|
99
99
|
"""
|
|
100
|
-
Uses a CombineColor Shader Node.
|
|
100
|
+
Uses a CombineColor Shader Node in HSV mode.
|
|
101
101
|
|
|
102
102
|
See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
|
|
103
103
|
"""
|
|
@@ -115,7 +115,7 @@ def combine_hsl(
|
|
|
115
115
|
lightness: nt.SocketOrVal[float] = 0.0,
|
|
116
116
|
) -> nt.ProcNode[pt.Color]:
|
|
117
117
|
"""
|
|
118
|
-
Uses a
|
|
118
|
+
Uses a CombineColor Shader Node in HSL mode.
|
|
119
119
|
|
|
120
120
|
See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
|
|
121
121
|
"""
|
|
@@ -320,26 +320,22 @@ def _construct_procnode_standard(
|
|
|
320
320
|
for input_name, input_py in kwargs.items():
|
|
321
321
|
input_result = input_results[input_name]
|
|
322
322
|
if input_result is None:
|
|
323
|
-
# Strict-None policy: None means "leave disconnected" and is only
|
|
324
|
-
# allowed for sockets with no default_value attr at all (Geometry,
|
|
325
|
-
# Shader, Matrix, Virtual) - never rely on Blender's internal
|
|
326
|
-
# defaults, whose values may change across versions. A disabled or
|
|
327
|
-
# missing socket name is a binding bug and propagates as ValueError.
|
|
328
323
|
to_socket = get_input_socket_to_connect_to(
|
|
329
324
|
bl_node_tree, bl_node, input_name, None
|
|
330
325
|
)
|
|
331
|
-
# IMAGE default_value is a datablock pointer; None faithfully means "no image assigned"
|
|
332
326
|
if (
|
|
333
327
|
to_socket.is_multi_input
|
|
334
328
|
or not hasattr(to_socket, "default_value")
|
|
335
|
-
or to_socket.
|
|
329
|
+
or to_socket.hide_value
|
|
330
|
+
or to_socket.default_value is None
|
|
336
331
|
):
|
|
337
332
|
continue
|
|
338
333
|
raise ValueError(
|
|
339
334
|
f"Node {bl_node.name!r} input {to_socket.name!r} (socket type "
|
|
340
335
|
f"{to_socket.type}) received None. Explicitly pass a value; None is "
|
|
341
|
-
f"only allowed for
|
|
342
|
-
f"
|
|
336
|
+
f"only allowed for disconnected implicit-field sockets (hide_value), "
|
|
337
|
+
f"datablock pointers, or sockets with no default_value attribute "
|
|
338
|
+
f"(e.g. Geometry/Shader)."
|
|
343
339
|
)
|
|
344
340
|
to_socket = get_input_socket_to_connect_to(
|
|
345
341
|
bl_node_tree, bl_node, input_name, input_result
|
|
@@ -327,6 +327,8 @@ def assign_default_value(
|
|
|
327
327
|
target_socket.default_value = t.Vector(input_val)
|
|
328
328
|
case bni.NodeDataType.FLOAT:
|
|
329
329
|
target_socket.default_value = float(input_val)
|
|
330
|
+
case bni.NodeDataType.INT:
|
|
331
|
+
target_socket.default_value = int(input_val)
|
|
330
332
|
case bni.NodeDataType.FLOAT_MATRIX:
|
|
331
333
|
# matrix values travel as numpy arrays in the compute graph;
|
|
332
334
|
# coerce back to mathutils.Matrix for bpy
|
|
@@ -6,7 +6,6 @@ from procfunc.nodes import types as nt
|
|
|
6
6
|
from procfunc.nodes.util.bindings_util import (
|
|
7
7
|
ContextualNode,
|
|
8
8
|
RuntimeResolveDataType,
|
|
9
|
-
raise_io_error,
|
|
10
9
|
)
|
|
11
10
|
from procfunc.nodes.util.bpy_node_info import NodeDataType
|
|
12
11
|
|
|
@@ -92,6 +91,7 @@ def boolean_or(
|
|
|
92
91
|
a: nt.SocketOrVal[bool],
|
|
93
92
|
b: nt.SocketOrVal[bool],
|
|
94
93
|
) -> nt.ProcNode[bool]:
|
|
94
|
+
"""Uses a BooleanMath Function Node with operation='OR'."""
|
|
95
95
|
return nt.ProcNode.from_nodetype(
|
|
96
96
|
node_type="FunctionNodeBooleanMath",
|
|
97
97
|
inputs={("Boolean", 0): a, ("Boolean", 1): b},
|
|
@@ -103,6 +103,7 @@ def boolean_and(
|
|
|
103
103
|
a: nt.SocketOrVal[bool],
|
|
104
104
|
b: nt.SocketOrVal[bool],
|
|
105
105
|
) -> nt.ProcNode[bool]:
|
|
106
|
+
"""Uses a BooleanMath Function Node with operation='AND'."""
|
|
106
107
|
return nt.ProcNode.from_nodetype(
|
|
107
108
|
node_type="FunctionNodeBooleanMath",
|
|
108
109
|
inputs={("Boolean", 0): a, ("Boolean", 1): b},
|
|
@@ -114,6 +115,7 @@ def boolean_xor(
|
|
|
114
115
|
a: nt.SocketOrVal[bool],
|
|
115
116
|
b: nt.SocketOrVal[bool],
|
|
116
117
|
) -> nt.ProcNode[bool]:
|
|
118
|
+
"""Uses a BooleanMath Function Node with operation='XOR'."""
|
|
117
119
|
return nt.ProcNode.from_nodetype(
|
|
118
120
|
node_type="FunctionNodeBooleanMath",
|
|
119
121
|
inputs={("Boolean", 0): a, ("Boolean", 1): b},
|
|
@@ -125,7 +127,7 @@ def boolean_not(
|
|
|
125
127
|
a: nt.SocketOrVal[bool],
|
|
126
128
|
) -> nt.ProcNode[bool]:
|
|
127
129
|
"""
|
|
128
|
-
Uses a
|
|
130
|
+
Uses a BooleanMath Function Node with operation='NOT'.
|
|
129
131
|
|
|
130
132
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/math/boolean_math.html
|
|
131
133
|
"""
|
|
@@ -275,6 +277,7 @@ def less_than(
|
|
|
275
277
|
a: TCompareNumeric,
|
|
276
278
|
b: TCompareNumeric,
|
|
277
279
|
) -> nt.ProcNode[bool]:
|
|
280
|
+
"""Uses a Compare Function Node with operation='LESS_THAN'."""
|
|
278
281
|
return _compare(a, b, operation="LESS_THAN")
|
|
279
282
|
|
|
280
283
|
|
|
@@ -282,6 +285,7 @@ def less_equal(
|
|
|
282
285
|
a: TCompareNumeric,
|
|
283
286
|
b: TCompareNumeric,
|
|
284
287
|
) -> nt.ProcNode[bool]:
|
|
288
|
+
"""Uses a Compare Function Node with operation='LESS_EQUAL'."""
|
|
285
289
|
return _compare(a, b, operation="LESS_EQUAL")
|
|
286
290
|
|
|
287
291
|
|
|
@@ -289,6 +293,7 @@ def greater_than(
|
|
|
289
293
|
a: TCompareNumeric,
|
|
290
294
|
b: TCompareNumeric,
|
|
291
295
|
) -> nt.ProcNode[bool]:
|
|
296
|
+
"""Uses a Compare Function Node with operation='GREATER_THAN'."""
|
|
292
297
|
return _compare(a, b, operation="GREATER_THAN")
|
|
293
298
|
|
|
294
299
|
|
|
@@ -296,6 +301,7 @@ def greater_equal(
|
|
|
296
301
|
a: TCompareNumeric,
|
|
297
302
|
b: TCompareNumeric,
|
|
298
303
|
) -> nt.ProcNode[bool]:
|
|
304
|
+
"""Uses a Compare Function Node with operation='GREATER_EQUAL'."""
|
|
299
305
|
return _compare(a, b, operation="GREATER_EQUAL")
|
|
300
306
|
|
|
301
307
|
|
|
@@ -311,6 +317,7 @@ def equal(
|
|
|
311
317
|
b: TCompareEqual,
|
|
312
318
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
313
319
|
) -> nt.ProcNode[bool]:
|
|
320
|
+
"""Uses a Compare Function Node with operation='EQUAL'."""
|
|
314
321
|
return _compare(a, b, epsilon, operation="EQUAL")
|
|
315
322
|
|
|
316
323
|
|
|
@@ -319,6 +326,7 @@ def not_equal(
|
|
|
319
326
|
b: TCompareEqual,
|
|
320
327
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
321
328
|
) -> nt.ProcNode[bool]:
|
|
329
|
+
"""Uses a Compare Function Node with operation='NOT_EQUAL'."""
|
|
322
330
|
return _compare(a, b, epsilon, operation="NOT_EQUAL")
|
|
323
331
|
|
|
324
332
|
|
|
@@ -332,6 +340,7 @@ def vector_elementwise_less_than(
|
|
|
332
340
|
a: nt.SocketOrVal[pt.Vector],
|
|
333
341
|
b: nt.SocketOrVal[pt.Vector],
|
|
334
342
|
) -> nt.ProcNode[bool]:
|
|
343
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='LESS_THAN'."""
|
|
335
344
|
return _compare(a, b, operation="LESS_THAN", data_type=NodeDataType.FLOAT_VECTOR)
|
|
336
345
|
|
|
337
346
|
|
|
@@ -339,6 +348,7 @@ def vector_elementwise_less_equal(
|
|
|
339
348
|
a: nt.SocketOrVal[pt.Vector],
|
|
340
349
|
b: nt.SocketOrVal[pt.Vector],
|
|
341
350
|
) -> nt.ProcNode[bool]:
|
|
351
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='LESS_EQUAL'."""
|
|
342
352
|
return _compare(a, b, operation="LESS_EQUAL", data_type=NodeDataType.FLOAT_VECTOR)
|
|
343
353
|
|
|
344
354
|
|
|
@@ -346,6 +356,7 @@ def vector_elementwise_greater_than(
|
|
|
346
356
|
a: nt.SocketOrVal[pt.Vector],
|
|
347
357
|
b: nt.SocketOrVal[pt.Vector],
|
|
348
358
|
) -> nt.ProcNode[bool]:
|
|
359
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='GREATER_THAN'."""
|
|
349
360
|
return _compare(a, b, operation="GREATER_THAN", data_type=NodeDataType.FLOAT_VECTOR)
|
|
350
361
|
|
|
351
362
|
|
|
@@ -353,6 +364,7 @@ def vector_elementwise_greater_equal(
|
|
|
353
364
|
a: nt.SocketOrVal[pt.Vector],
|
|
354
365
|
b: nt.SocketOrVal[pt.Vector],
|
|
355
366
|
) -> nt.ProcNode[bool]:
|
|
367
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='GREATER_EQUAL'."""
|
|
356
368
|
return _compare(
|
|
357
369
|
a, b, operation="GREATER_EQUAL", data_type=NodeDataType.FLOAT_VECTOR
|
|
358
370
|
)
|
|
@@ -363,6 +375,7 @@ def vector_elementwise_equal(
|
|
|
363
375
|
b: nt.SocketOrVal[pt.Vector],
|
|
364
376
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
365
377
|
) -> nt.ProcNode[bool]:
|
|
378
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='EQUAL'."""
|
|
366
379
|
return _compare(
|
|
367
380
|
a, b, epsilon, operation="EQUAL", data_type=NodeDataType.FLOAT_VECTOR
|
|
368
381
|
)
|
|
@@ -373,6 +386,7 @@ def vector_elementwise_not_equal(
|
|
|
373
386
|
b: nt.SocketOrVal[pt.Vector],
|
|
374
387
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
375
388
|
) -> nt.ProcNode[bool]:
|
|
389
|
+
"""Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='NOT_EQUAL'."""
|
|
376
390
|
return _compare(
|
|
377
391
|
a, b, epsilon, operation="NOT_EQUAL", data_type=NodeDataType.FLOAT_VECTOR
|
|
378
392
|
)
|
|
@@ -383,6 +397,7 @@ def color_equal(
|
|
|
383
397
|
b: nt.SocketOrVal[pt.Color],
|
|
384
398
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
385
399
|
) -> nt.ProcNode[bool]:
|
|
400
|
+
"""Uses a Compare Function Node with data_type='RGBA', operation='EQUAL'."""
|
|
386
401
|
return _compare(a, b, epsilon, operation="EQUAL", data_type=NodeDataType.RGBA)
|
|
387
402
|
|
|
388
403
|
|
|
@@ -391,6 +406,7 @@ def color_not_equal(
|
|
|
391
406
|
b: nt.SocketOrVal[pt.Color],
|
|
392
407
|
epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
|
|
393
408
|
) -> nt.ProcNode[bool]:
|
|
409
|
+
"""Uses a Compare Function Node with data_type='RGBA', operation='NOT_EQUAL'."""
|
|
394
410
|
return _compare(a, b, epsilon, operation="NOT_EQUAL", data_type=NodeDataType.RGBA)
|
|
395
411
|
|
|
396
412
|
|
|
@@ -398,6 +414,7 @@ def color_brighter(
|
|
|
398
414
|
a: nt.SocketOrVal[pt.Color],
|
|
399
415
|
b: nt.SocketOrVal[pt.Color],
|
|
400
416
|
) -> nt.ProcNode[bool]:
|
|
417
|
+
"""Uses a Compare Function Node with data_type='RGBA', operation='BRIGHTER'."""
|
|
401
418
|
return _compare(a, b, operation="BRIGHTER", data_type=NodeDataType.RGBA)
|
|
402
419
|
|
|
403
420
|
|
|
@@ -405,6 +422,7 @@ def color_darker(
|
|
|
405
422
|
a: nt.SocketOrVal[pt.Color],
|
|
406
423
|
b: nt.SocketOrVal[pt.Color],
|
|
407
424
|
) -> nt.ProcNode[bool]:
|
|
425
|
+
"""Uses a Compare Function Node with data_type='RGBA', operation='DARKER'."""
|
|
408
426
|
return _compare(a, b, operation="DARKER", data_type=NodeDataType.RGBA)
|
|
409
427
|
|
|
410
428
|
|
|
@@ -447,8 +465,6 @@ def input_bool(boolean: bool = False) -> t.ProcNode[bool]:
|
|
|
447
465
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/boolean.html
|
|
448
466
|
"""
|
|
449
467
|
|
|
450
|
-
raise_io_error("input_bool", logger=logger)
|
|
451
|
-
|
|
452
468
|
return t.ProcNode.from_nodetype(
|
|
453
469
|
node_type="FunctionNodeInputBool",
|
|
454
470
|
inputs={},
|
|
@@ -463,8 +479,6 @@ def input_color(value: tuple = (0.5, 0.5, 0.5, 1.0)) -> t.ProcNode[pt.Color]:
|
|
|
463
479
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/color.html
|
|
464
480
|
"""
|
|
465
481
|
|
|
466
|
-
raise_io_error("input_color", logger=logger)
|
|
467
|
-
|
|
468
482
|
return t.ProcNode.from_nodetype(
|
|
469
483
|
node_type="FunctionNodeInputColor",
|
|
470
484
|
inputs={},
|
|
@@ -479,8 +493,6 @@ def input_int(integer: int = 0) -> t.ProcNode[int]:
|
|
|
479
493
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/integer.html
|
|
480
494
|
"""
|
|
481
495
|
|
|
482
|
-
raise_io_error("input_int", logger=logger)
|
|
483
|
-
|
|
484
496
|
return t.ProcNode.from_nodetype(
|
|
485
497
|
node_type="FunctionNodeInputInt",
|
|
486
498
|
inputs={},
|
|
@@ -495,8 +507,6 @@ def input_rotation(rotation_euler: tuple = (0.0, 0.0, 0.0)) -> t.ProcNode[pt.Vec
|
|
|
495
507
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/rotation.html
|
|
496
508
|
"""
|
|
497
509
|
|
|
498
|
-
raise_io_error("input_rotation", logger=logger)
|
|
499
|
-
|
|
500
510
|
return t.ProcNode.from_nodetype(
|
|
501
511
|
node_type="FunctionNodeInputRotation",
|
|
502
512
|
inputs={},
|
|
@@ -517,8 +527,6 @@ def input_special_characters() -> InputSpecialCharactersResult:
|
|
|
517
527
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/text/special_characters.html
|
|
518
528
|
"""
|
|
519
529
|
|
|
520
|
-
raise_io_error("input_special_characters", logger=logger)
|
|
521
|
-
|
|
522
530
|
node = nt.ProcNode.from_nodetype(
|
|
523
531
|
node_type="FunctionNodeInputSpecialCharacters",
|
|
524
532
|
inputs={},
|
|
@@ -536,8 +544,6 @@ def input_string(string: str = "") -> nt.ProcNode[str]:
|
|
|
536
544
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/string.html
|
|
537
545
|
"""
|
|
538
546
|
|
|
539
|
-
raise_io_error("input_string", logger=logger)
|
|
540
|
-
|
|
541
547
|
return nt.ProcNode.from_nodetype(
|
|
542
548
|
node_type="FunctionNodeInputString",
|
|
543
549
|
inputs={},
|
|
@@ -552,8 +558,6 @@ def input_vector(vector: tuple = (0.0, 0.0, 0.0)) -> nt.ProcNode[pt.Vector]:
|
|
|
552
558
|
See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/input/constant/vector.html
|
|
553
559
|
"""
|
|
554
560
|
|
|
555
|
-
raise_io_error("input_vector", logger=logger)
|
|
556
|
-
|
|
557
561
|
return nt.ProcNode.from_nodetype(
|
|
558
562
|
node_type="FunctionNodeInputVector",
|
|
559
563
|
inputs={},
|
|
@@ -693,7 +697,7 @@ def random_boolean(
|
|
|
693
697
|
seed: nt.SocketOrVal[int] = 0,
|
|
694
698
|
) -> nt.ProcNode[bool]:
|
|
695
699
|
"""
|
|
696
|
-
Uses a
|
|
700
|
+
Uses a RandomValue Function Node with data_type='BOOLEAN'.
|
|
697
701
|
"""
|
|
698
702
|
return nt.ProcNode.from_nodetype(
|
|
699
703
|
node_type="FunctionNodeRandomValue",
|