procfunc 0.35.1__tar.gz → 0.36.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.
Files changed (113) hide show
  1. {procfunc-0.35.1/src/procfunc.egg-info → procfunc-0.36.0}/PKG-INFO +2 -2
  2. {procfunc-0.35.1 → procfunc-0.36.0}/README.md +1 -1
  3. {procfunc-0.35.1 → procfunc-0.36.0}/pyproject.toml +1 -0
  4. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/__init__.py +2 -1
  5. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/codegen/codegen.py +8 -3
  6. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/codegen/repr.py +4 -1
  7. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/operators_info.py +12 -0
  8. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/context.py +16 -0
  9. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/control/__init__.py +7 -1
  10. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/__init__.py +2 -0
  11. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/color.py +16 -1
  12. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/compositor.py +227 -30
  13. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_special_cases.py +121 -31
  14. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_standard.py +2 -2
  15. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/infer_runtime_data_type.py +10 -0
  16. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/func.py +15 -2
  17. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/geo.py +200 -67
  18. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/manifest.json +1107 -39
  19. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/math.py +63 -19
  20. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/shader.py +235 -18
  21. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/texture.py +131 -28
  22. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/types.py +18 -1
  23. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/util/bindings_util.py +1 -0
  24. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/util/bpy_node_info.py +0 -14
  25. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/util/node_function.py +67 -7
  26. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/_util.py +18 -13
  27. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/addons.py +11 -6
  28. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/curve.py +2 -1
  29. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/file.py +26 -14
  30. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/manifest.json +43 -0
  31. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/mesh.py +6 -5
  32. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/modifier.py +83 -14
  33. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/object.py +1 -1
  34. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/primitives/camera.py +3 -2
  35. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/primitives/curve.py +3 -2
  36. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/primitives/light.py +5 -4
  37. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/primitives/mesh.py +21 -10
  38. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transpiler/bpy_to_computegraph.py +29 -158
  39. procfunc-0.36.0/src/procfunc/transpiler/parse_attrs.py +137 -0
  40. procfunc-0.36.0/src/procfunc/transpiler/parse_special_cases.py +467 -0
  41. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/teardown.py +8 -0
  42. {procfunc-0.35.1 → procfunc-0.36.0/src/procfunc.egg-info}/PKG-INFO +2 -2
  43. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc.egg-info/SOURCES.txt +2 -0
  44. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_codegen.py +59 -0
  45. procfunc-0.36.0/tests/test_control.py +52 -0
  46. procfunc-0.36.0/tests/test_node_function.py +131 -0
  47. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_ops.py +166 -67
  48. procfunc-0.36.0/tests/test_teardown.py +99 -0
  49. procfunc-0.35.1/src/procfunc/transpiler/parse_special_cases.py +0 -158
  50. procfunc-0.35.1/tests/test_node_function.py +0 -28
  51. procfunc-0.35.1/tests/test_teardown.py +0 -51
  52. {procfunc-0.35.1 → procfunc-0.36.0}/LICENSE.md +0 -0
  53. {procfunc-0.35.1 → procfunc-0.36.0}/setup.cfg +0 -0
  54. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/cli/__init__.py +0 -0
  55. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/cli/main.py +0 -0
  56. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/codegen/__init__.py +0 -0
  57. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/codegen/identifiers.py +0 -0
  58. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/color.py +0 -0
  59. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/__init__.py +0 -0
  60. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/compute_graph.py +0 -0
  61. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/node.py +0 -0
  62. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/proxy.py +0 -0
  63. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/compute_graph/util.py +0 -0
  64. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_nodes.py +0 -0
  65. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_operator.py +0 -0
  66. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/execute.py +0 -0
  67. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/realize.py +0 -0
  68. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/execute/util.py +0 -0
  69. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/nodes/util/__init__.py +0 -0
  70. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/__init__.py +0 -0
  71. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/attr.py +0 -0
  72. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/collection.py +0 -0
  73. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/primitives/__init__.py +0 -0
  74. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/ops/uv.py +0 -0
  75. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/random.py +0 -0
  76. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/tracer/__init__.py +0 -0
  77. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/tracer/decorator.py +0 -0
  78. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/tracer/patch.py +0 -0
  79. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/tracer/proxy.py +0 -0
  80. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/tracer/trace.py +0 -0
  81. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/__init__.py +0 -0
  82. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/cleanup.py +0 -0
  83. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/convert.py +0 -0
  84. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/distribution.py +0 -0
  85. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/extract_materials.py +0 -0
  86. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/infer_distribution.py +0 -0
  87. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/parameters.py +0 -0
  88. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transforms/util.py +0 -0
  89. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transpiler/__init__.py +0 -0
  90. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transpiler/main.py +0 -0
  91. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/transpiler/parse_default_values.py +0 -0
  92. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/types.py +0 -0
  93. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/__init__.py +0 -0
  94. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/bpy_data.py +0 -0
  95. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/bpy_info.py +0 -0
  96. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/camera.py +0 -0
  97. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/keyframe.py +0 -0
  98. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/log.py +0 -0
  99. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/manifest.py +0 -0
  100. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc/util/pytree.py +0 -0
  101. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc.egg-info/dependency_links.txt +0 -0
  102. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc.egg-info/entry_points.txt +0 -0
  103. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc.egg-info/requires.txt +0 -0
  104. {procfunc-0.35.1 → procfunc-0.36.0}/src/procfunc.egg-info/top_level.txt +0 -0
  105. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_asset.py +0 -0
  106. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_bpy_data_cleanup.py +0 -0
  107. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_cli_transpile.py +0 -0
  108. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_codegen_matrix.py +0 -0
  109. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_compute_graph.py +0 -0
  110. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_pytree.py +0 -0
  111. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_random.py +0 -0
  112. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_trace.py +0 -0
  113. {procfunc-0.35.1 → procfunc-0.36.0}/tests/test_transforms.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: procfunc
3
- Version: 0.35.1
3
+ Version: 0.36.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
@@ -37,7 +37,7 @@ Dynamic: license-file
37
37
 
38
38
  This repository contains only the Primitives API, Transpiler and Tracer from our research paper.
39
39
 
40
- The pre-made procedural generators are coming soon as part of [infinigen](https://github.com/princeton-vl/infinigen).
40
+ Please see the infinigen2 [documentation](https://infinigen.cs.princeton.edu/docs/latest/) and [sourcecode](https://github.com/princeton-vl/infinigen/tree/3f58bb886bb1bda681d41240344fe3126ac0e9bd/src/infinigen2) to access the paper's library of new procedural generators
41
41
 
42
42
  ### Installation
43
43
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  This repository contains only the Primitives API, Transpiler and Tracer from our research paper.
10
10
 
11
- The pre-made procedural generators are coming soon as part of [infinigen](https://github.com/princeton-vl/infinigen).
11
+ Please see the infinigen2 [documentation](https://infinigen.cs.princeton.edu/docs/latest/) and [sourcecode](https://github.com/princeton-vl/infinigen/tree/3f58bb886bb1bda681d41240344fe3126ac0e9bd/src/infinigen2) to access the paper's library of new procedural generators
12
12
 
13
13
  ### Installation
14
14
 
@@ -52,6 +52,7 @@ procfunc = ["nodes/manifest.json", "ops/manifest.json"]
52
52
 
53
53
  [tool.pytest.ini_options]
54
54
  testpaths = "tests"
55
+ markers = ["render: requires a render-capable Blender environment"]
55
56
 
56
57
  [tool.ruff]
57
58
  exclude = ["examples", "experiments"]
@@ -2,7 +2,7 @@
2
2
  # ensure this gets imported first so that mathutils etc is available even if later modules dont import bpy
3
3
  import bpy
4
4
 
5
- __version__ = "0.35.1"
5
+ __version__ = "0.36.0"
6
6
 
7
7
  from numpy.random import Generator as RNG
8
8
 
@@ -54,6 +54,7 @@ from .nodes import ProcNode, Shader, NodeDataType
54
54
  from .tracer import trace, autowrap_module, add_search_scope
55
55
  from .util.manifest import module_path
56
56
 
57
+ bpy.context.preferences.edit.use_global_undo = False
57
58
  autowrap_module(random)
58
59
  autowrap_module(color)
59
60
  add_search_scope(nodes)
@@ -240,9 +240,12 @@ def _operator_call_operands(
240
240
 
241
241
  operands = [bound.arguments[name] for name in operand_names]
242
242
 
243
- # a default epsilon stays tolerant unlike exact ==/!=, so require exact operands
244
- if template in _EPSILON_EQUALITY_TEMPLATES and not all(
245
- _is_exact_compare_operand(v) for v in operands
243
+ operator_type = FUNCTIONS_TO_OPERATORS.get(node.func)
244
+ native_equality = operator_type in (OperatorType.EQUAL, OperatorType.NOT_EQUAL)
245
+ if (
246
+ template in _EPSILON_EQUALITY_TEMPLATES
247
+ and not native_equality
248
+ and not all(_is_exact_compare_operand(v) for v in operands)
246
249
  ):
247
250
  return None
248
251
 
@@ -713,6 +716,8 @@ def _resolve_func(func: Any) -> tuple[str | None, str]:
713
716
  raise NotImplementedError(f"Unsupported function: {func}")
714
717
  elif module == "builtins":
715
718
  return None, func.__name__
719
+ elif module == "_operator":
720
+ return "import operator", f"operator.{func.__name__}"
716
721
  elif module.startswith("procfunc."):
717
722
  callsite = "pf." + module[len("procfunc.") :] + "." + func.__name__
718
723
  importstring = "import procfunc as pf"
@@ -27,7 +27,8 @@ def repr_type(x: Any) -> str:
27
27
  if origin is Union or origin is types.UnionType:
28
28
  first_args = get_args(args[0])
29
29
  if (
30
- get_origin(args[0]) is nt.ProcNode
30
+ len(args) == 2
31
+ and get_origin(args[0]) is nt.ProcNode
31
32
  and first_args
32
33
  and first_args[0] is args[1]
33
34
  ):
@@ -82,6 +83,8 @@ def repr_value(value: Any) -> str:
82
83
 
83
84
  if isinstance(value, np.random.Generator):
84
85
  return "np.random.default_rng()"
86
+ elif get_origin(value) in (Union, types.UnionType, nt.ProcNode):
87
+ return repr_type(value)
85
88
  elif isinstance(value, type):
86
89
  return repr_type(value)
87
90
  elif isinstance(value, np.ndarray):
@@ -7,6 +7,7 @@ class OperatorType(Enum):
7
7
  SUB = "sub"
8
8
  MUL = "mul"
9
9
  DIV = "div"
10
+ FLOOR_DIV = "floordiv"
10
11
  TRUEDIV = "truediv"
11
12
  POW = "pow"
12
13
  MOD = "mod"
@@ -17,6 +18,8 @@ class OperatorType(Enum):
17
18
  EQUAL = "eq"
18
19
  NOT_EQUAL = "ne"
19
20
  NOT = "invert"
21
+ NEG = "neg"
22
+ POS = "pos"
20
23
  LSHIFT = "lshift"
21
24
  RSHIFT = "rshift"
22
25
  BIT_AND = "and"
@@ -34,6 +37,7 @@ OPERATOR_TEMPLATES = {
34
37
  OperatorType.SUB: "{} - {}",
35
38
  OperatorType.MUL: "{} * {}",
36
39
  OperatorType.DIV: "{} / {}",
40
+ OperatorType.FLOOR_DIV: "{} // {}",
37
41
  OperatorType.POW: "{} ** {}",
38
42
  OperatorType.MOD: "{} % {}",
39
43
  OperatorType.LESS_THAN: "{} < {}",
@@ -42,6 +46,9 @@ OPERATOR_TEMPLATES = {
42
46
  OperatorType.GREATER_THAN_EQUAL: "{} >= {}",
43
47
  OperatorType.EQUAL: "{} == {}",
44
48
  OperatorType.NOT_EQUAL: "{} != {}",
49
+ OperatorType.NOT: "~{}",
50
+ OperatorType.NEG: "-{}",
51
+ OperatorType.POS: "+{}",
45
52
  OperatorType.VECTOR_PACK: "({}, {}, {})",
46
53
  OperatorType.NOOP: "{}",
47
54
  OperatorType.LSHIFT: "{} << {}",
@@ -57,6 +64,7 @@ OPERATORS_TO_FUNCTIONS = {
57
64
  OperatorType.SUB: operator.sub,
58
65
  OperatorType.MUL: operator.mul,
59
66
  OperatorType.DIV: operator.truediv,
67
+ OperatorType.FLOOR_DIV: operator.floordiv,
60
68
  OperatorType.MOD: operator.mod,
61
69
  OperatorType.POW: operator.pow,
62
70
  OperatorType.LESS_THAN: operator.lt,
@@ -65,6 +73,9 @@ OPERATORS_TO_FUNCTIONS = {
65
73
  OperatorType.GREATER_THAN_EQUAL: operator.ge,
66
74
  OperatorType.EQUAL: operator.eq,
67
75
  OperatorType.NOT_EQUAL: operator.ne,
76
+ OperatorType.NOT: operator.invert,
77
+ OperatorType.NEG: operator.neg,
78
+ OperatorType.POS: operator.pos,
68
79
  OperatorType.LSHIFT: operator.lshift,
69
80
  OperatorType.RSHIFT: operator.rshift,
70
81
  OperatorType.BIT_AND: operator.and_,
@@ -80,6 +91,7 @@ REFLECTABLE_OPERATORS = {
80
91
  OperatorType.SUB,
81
92
  OperatorType.MUL,
82
93
  OperatorType.DIV,
94
+ OperatorType.FLOOR_DIV,
83
95
  OperatorType.MOD,
84
96
  OperatorType.POW,
85
97
  OperatorType.LSHIFT,
@@ -19,6 +19,14 @@ class ProcfuncContext:
19
19
  'ignore' silently returns an empty mesh, 'warn' logs a warning, 'throw' raises an error.
20
20
  """
21
21
 
22
+ warn_mode_transpile_dropped_attrs: Literal["ignore", "warn", "throw"]
23
+ """
24
+ Controls behavior when transpiling a bpy node whose attributes carry render-affecting
25
+ state procfunc has no binding for, so the transpiled result would render differently
26
+ (e.g. a non-identity texture_mapping on a ShaderNodeTex* node).
27
+ 'ignore' drops it silently, 'warn' logs a warning, 'throw' raises an error.
28
+ """
29
+
22
30
  record_node_definitions: bool = False
23
31
  """
24
32
  Record the user-space file/line/function that constructed each ProcNode, used only to
@@ -34,10 +42,12 @@ class ProcfuncContext:
34
42
  def set_strict(self):
35
43
  """Set all warning modes to 'throw'"""
36
44
  self.warn_mode_empty_geonodes = "throw"
45
+ self.warn_mode_transpile_dropped_attrs = "throw"
37
46
 
38
47
  def set_warn(self):
39
48
  """Set all warning modes to 'warn'"""
40
49
  self.warn_mode_empty_geonodes = "warn"
50
+ self.warn_mode_transpile_dropped_attrs = "warn"
41
51
 
42
52
 
43
53
  # Global context instance
@@ -47,9 +57,15 @@ warn_modes = ["ignore", "warn", "throw"]
47
57
  _warn_mode_empty_geonodes = os.environ.get("PROCFUNC_WARN_MODE_EMPTY_GEONODES", "warn")
48
58
  assert _warn_mode_empty_geonodes in warn_modes
49
59
 
60
+ _warn_mode_transpile_dropped_attrs = os.environ.get(
61
+ "PROCFUNC_WARN_MODE_TRANSPILE_DROPPED_ATTRS", "throw"
62
+ )
63
+ assert _warn_mode_transpile_dropped_attrs in warn_modes
64
+
50
65
  globals = ProcfuncContext(
51
66
  num_cpu_cores=int(os.environ.get("PROCFUNC_NUM_CPU_CORES", 0)),
52
67
  warn_mode_empty_geonodes=_warn_mode_empty_geonodes, # type: ignore[invalid-assignment]
68
+ warn_mode_transpile_dropped_attrs=_warn_mode_transpile_dropped_attrs, # type: ignore[invalid-assignment]
53
69
  current_trace_level=None,
54
70
  record_node_definitions=os.environ.get("PROCFUNC_RECORD_NODE_DEFINITIONS", "0")
55
71
  == "1",
@@ -33,6 +33,7 @@ def choice_idx(rng: np.random.Generator, weights: list[float]) -> int:
33
33
  def _peekthrough_execute_all_choices(
34
34
  choice_options: list[tuple[Callable[..., T], float]],
35
35
  chosen_idx: int,
36
+ choice_rng: cg.Node,
36
37
  args: tuple,
37
38
  kwargs: dict,
38
39
  ) -> cg.Proxy:
@@ -43,6 +44,7 @@ def _peekthrough_execute_all_choices(
43
44
  evald.append((res, weight))
44
45
 
45
46
  new_kwargs = dict(
47
+ choice_rng=choice_rng,
46
48
  choice_options=evald,
47
49
  chosen_idx=chosen_idx,
48
50
  )
@@ -67,6 +69,7 @@ class ChoiceResultProxy(cg.Proxy):
67
69
  return _peekthrough_execute_all_choices(
68
70
  self.node.kwargs["choice_options"],
69
71
  self.node.kwargs["chosen_idx"],
72
+ self.node.kwargs["choice_rng"],
70
73
  args,
71
74
  kwargs,
72
75
  )
@@ -92,13 +95,16 @@ def _choice_create_custom_tracer_wrapper(
92
95
  @functools.wraps(choice)
93
96
  def wrapper(
94
97
  choice_rng: RngProxy,
95
- choice_options: list[tuple[T, float]] | None = None,
98
+ choice_options: list[tuple[T, float]],
96
99
  chosen_idx: int | None = None,
97
100
  ):
98
101
  choice_values, choice_weights = zip(*choice_options)
99
102
  if chosen_idx is None:
100
103
  chosen_idx = choice_idx(choice_rng.rng, choice_weights)
101
104
 
105
+ if patcher.trace_level < TraceLevel.RANDOM_CONTROL:
106
+ return choice_values[chosen_idx]
107
+
102
108
  unwrapped_options = [
103
109
  (pytree.PyTree(v).map(_unwrap_proxy).obj(), w) for v, w in choice_options
104
110
  ]
@@ -28,6 +28,7 @@ from .execute.execute import (
28
28
  )
29
29
  from .execute.util import NODE_OPERATOR_TABLE
30
30
  from .types import (
31
+ HandleType,
31
32
  ProcNode,
32
33
  Shader,
33
34
  SocketOrVal,
@@ -51,6 +52,7 @@ __all__ = [
51
52
  "ProcNode",
52
53
  "Shader",
53
54
  "SocketOrVal",
55
+ "HandleType",
54
56
  "NodeDataType",
55
57
  "NodeGroupType",
56
58
  "SocketType",
@@ -61,16 +61,31 @@ def rgb_curve(
61
61
  fac: nt.SocketOrVal[float],
62
62
  color: nt.SocketOrVal[pt.Color],
63
63
  curves: list[np.ndarray] | np.ndarray | None = None,
64
+ handle_types: list[list[nt.HandleType]] | None = None,
65
+ use_clip: bool = True,
66
+ extend: Literal["HORIZONTAL", "EXTRAPOLATED"] = "EXTRAPOLATED",
67
+ clip_min: tuple[float, float] | None = None,
68
+ clip_max: tuple[float, float] | None = None,
64
69
  ) -> nt.ProcNode:
65
70
  """
66
71
  Uses a RGBCurve Shader Node.
67
72
 
73
+ `handle_types[i]` contains the handles for the i-th curve, and
74
+ `handle_types[i][j]` is the handle type for `curves[i][j]`.
75
+
68
76
  See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/color/rgb_curves.html
69
77
  """
70
78
  return nt.ProcNode.from_nodetype(
71
79
  node_type="ShaderNodeRGBCurve",
72
80
  inputs={"Fac": fac, "Color": color},
73
- attrs={"curves": curves},
81
+ attrs={
82
+ "curves": curves,
83
+ "handle_types": handle_types,
84
+ "use_clip": use_clip,
85
+ "extend": extend,
86
+ "clip_min": clip_min,
87
+ "clip_max": clip_max,
88
+ },
74
89
  )
75
90
 
76
91