feat: add render graph driven renderer architecture

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-27 02:53:44 +00:00
co-authored by heaust
parent 8a8369706b
commit d4e8634f67
290 changed files with 48804 additions and 1995 deletions
+106
View File
@@ -0,0 +1,106 @@
# SPDX-License-Identifier: GPL-3.0-or-later
"""Create deterministic, project-authored Blender node-editor reference fixtures."""
import argparse
import sys
from pathlib import Path
import bpy
FIXTURES = (
"shader-basic-linked-near", "shader-basic-linked-far",
"shader-selected-active-hover-near", "shader-collapsed-near",
"common-frame-reroute-near", "shader-widget-rich-near",
"shader-socket-gallery-near", "geometry-socket-gallery-near",
)
def arguments():
parser = argparse.ArgumentParser()
parser.add_argument("--fixture", choices=FIXTURES, required=True)
parser.add_argument("--save", type=Path)
return parser.parse_args(sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
def add(nodes, node_type, name, x, y):
node = nodes.new(node_type)
node.name = name
node.label = name
node.location = (x, y)
return node
def shader_tree(fixture):
material = bpy.data.materials.new("fxnode-reference")
material.use_nodes = True
tree = material.node_tree
tree.nodes.clear()
nodes, links = tree.nodes, tree.links
output = add(nodes, "ShaderNodeOutputMaterial", "Material Output", 520, 0)
principled = add(nodes, "ShaderNodeBsdfPrincipled", "Principled BSDF", 160, 0)
noise = add(nodes, "ShaderNodeTexNoise", "Noise Texture", -440, 160)
ramp = add(nodes, "ShaderNodeValToRGB", "Color Ramp", -140, 180)
links.new(noise.outputs["Fac"], ramp.inputs["Fac"])
links.new(ramp.outputs["Color"], principled.inputs["Base Color"])
links.new(principled.outputs["BSDF"], output.inputs["Surface"])
if fixture == "shader-collapsed-near":
noise.hide = True
ramp.hide = True
elif fixture == "common-frame-reroute-near":
frame = add(nodes, "NodeFrame", "Texture controls", -500, 100)
noise.parent = frame
reroute = add(nodes, "NodeReroute", "Reroute", 60, 260)
links.new(ramp.outputs["Color"], reroute.inputs[0])
links.new(reroute.outputs[0], principled.inputs["Base Color"])
elif fixture == "shader-widget-rich-near":
add(nodes, "ShaderNodeMix", "Mix", -140, -240)
add(nodes, "ShaderNodeMath", "Math", 160, -280)
elif fixture == "shader-socket-gallery-near":
add(nodes, "ShaderNodeTexCoord", "Texture Coordinate", -700, -260)
add(nodes, "ShaderNodeVectorMath", "Vector Math", -400, -260)
add(nodes, "ShaderNodeValue", "Value", -100, -320)
add(nodes, "ShaderNodeRGB", "Color", 160, -320)
nodes.active = principled
principled.select = True
return tree
def geometry_tree():
obj = bpy.data.objects.new("fxnode-geometry", bpy.data.meshes.new("fxnode-mesh"))
bpy.context.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
modifier = obj.modifiers.new("fxnode-reference", "NODES")
tree = bpy.data.node_groups.new("fxnode-geometry", "GeometryNodeTree")
modifier.node_group = tree
nodes = tree.nodes
for node_type, name, x, y in (
("GeometryNodeInputPosition", "Position", -600, 200),
("GeometryNodeMeshCube", "Mesh Cube", -600, -100),
("GeometryNodeSetPosition", "Set Position", -200, 80),
("GeometryNodeTransform", "Transform Geometry", 160, 80),
("GeometryNodeJoinGeometry", "Join Geometry", 500, 80),
):
add(nodes, node_type, name, x, y)
return tree
def main():
args = arguments()
if bpy.app.version[:2] != (4, 5):
raise RuntimeError(f"Blender 4.5.x required, found {bpy.app.version_string}")
bpy.ops.wm.read_factory_settings(use_empty=True)
tree = geometry_tree() if args.fixture == "geometry-socket-gallery-near" else shader_tree(args.fixture)
for area in bpy.context.screen.areas:
if area.type == "NODE_EDITOR":
area.spaces.active.pin = True
area.spaces.active.geometry_nodes_type = "MODIFIER" if tree.bl_idname == "GeometryNodeTree" else "MODIFIER"
with bpy.context.temp_override(area=area):
bpy.ops.node.view_all()
if args.fixture == "shader-basic-linked-far":
bpy.ops.view2d.zoom_out(zoomfacx=3.0, zoomfacy=3.0)
if args.save:
bpy.ops.wm.save_as_mainfile(filepath=str(args.save.resolve()))
if __name__ == "__main__":
main()