Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
66 lines
3.3 KiB
Python
66 lines
3.3 KiB
Python
"""Generate a World readback input fixture; do not run acceptance checks."""
|
|
import bpy
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
source, destination = sys.argv[sys.argv.index("--") + 1:]
|
|
bpy.ops.wm.open_mainfile(filepath=str(Path(source).resolve()))
|
|
scene = bpy.context.scene
|
|
world = scene.world.copy() if scene.world else bpy.data.worlds.new("B4WorldReadback")
|
|
world.name = "B4WorldReadback"
|
|
scene.world = world
|
|
if world.node_tree is None: world.use_nodes = True
|
|
tree = world.node_tree
|
|
tree.nodes.clear()
|
|
scene.render.engine = "BLENDER_EEVEE"
|
|
def background(name, strength):
|
|
node = tree.nodes.new("ShaderNodeBackground")
|
|
node.name = name
|
|
node.inputs["Strength"].default_value = strength
|
|
return node
|
|
def environment(name, color):
|
|
node = tree.nodes.new("ShaderNodeTexEnvironment")
|
|
node.name = name
|
|
node.image = bpy.data.images.new(name, width=1, height=1)
|
|
node.image.pixels[:] = color
|
|
node.image.pack()
|
|
return node
|
|
background("B4_unused_first", 17.0)
|
|
active = background("B4_active", 2.5)
|
|
texture = environment("B4_active_environment", (0.25, 0.5, 0.75, 1.0))
|
|
output = tree.nodes.new("ShaderNodeOutputWorld")
|
|
output.is_active_output = True
|
|
tree.links.new(active.outputs["Background"], output.inputs["Surface"])
|
|
tree.links.new(texture.outputs["Color"], active.inputs["Color"])
|
|
background("B4_unused_last", 99.0)
|
|
environment("B4_unused_environment", (1.0, 0.0, 0.0, 1.0))
|
|
driver = tree.nodes.new("ShaderNodeValue")
|
|
driver.name = "B4_strength_driver"
|
|
driver.outputs[0].default_value = 7.5
|
|
mesh = next((obj for obj in scene.objects if obj.type == "MESH"), None)
|
|
if mesh and not any(obj.type == "MESH" and any(obj.data.materials) for obj in scene.objects):
|
|
material = bpy.data.materials.new("B4FixtureMaterial")
|
|
material.diffuse_color = (0.65, 0.65, 0.65, 1.0)
|
|
if mesh.data.materials: mesh.data.materials[0] = material
|
|
else: mesh.data.materials.append(material)
|
|
if scene.camera:
|
|
scene.camera.data.lens = 52.0
|
|
scene.camera.data.clip_start = 0.125
|
|
scene.camera.data.clip_end = 2500.0
|
|
for light_object in (obj for obj in scene.objects if obj.type == "LIGHT"):
|
|
light_object.data.energy = 650.0
|
|
light_object.data.shadow_soft_size = 0.35
|
|
if light_object.data.type == 'AREA': light_object.data.size = 2.0
|
|
scene.render.resolution_x, scene.render.resolution_y, scene.render.resolution_percentage = 1280, 720, 80
|
|
scene.render.image_settings.file_format = 'PNG'
|
|
destination = Path(destination).resolve()
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
bpy.ops.wm.save_as_mainfile(filepath=str(destination), check_existing=False)
|
|
facts = {"kind": "input_fixture", "source": str(Path(source).resolve()), "fixture": str(destination),
|
|
"world": world.name, "expectedStrength": 2.5, "expectedImage": texture.image.name,
|
|
"inactiveStrengths": [17.0, 99.0], "driver": driver.name, "camera": scene.camera.name if scene.camera else None,
|
|
"lights": [obj.name for obj in scene.objects if obj.type == "LIGHT"],
|
|
"materialObjects": [obj.name for obj in scene.objects if obj.type == "MESH" and any(obj.data.materials)],
|
|
"resolution": [scene.render.resolution_x, scene.render.resolution_y, scene.render.resolution_percentage], "format": scene.render.image_settings.file_format}
|
|
destination.with_suffix(".json").write_text(json.dumps(facts, indent=2) + "\n")
|