blender/tests/python/sculpt_brush_render_tests.py

159 lines
4.1 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
import argparse
import os
import sys
def set_view3d_context_override(context_override):
"""
Set context override to become the first viewport in the active workspace
The ``context_override`` is expected to be a copy of an actual current context
obtained by `context.copy()`
"""
for area in context_override["screen"].areas:
if area.type != 'VIEW_3D':
continue
for space in area.spaces:
if space.type != 'VIEW_3D':
continue
for region in area.regions:
if region.type != 'WINDOW':
continue
context_override["area"] = area
context_override["region"] = region
def generate_stroke(context):
"""
Generate stroke for the bpy.ops.sculpt.brush_stroke operator
The generated stroke covers the full plane diagonal.
"""
from mathutils import Vector
template = {
"name": "stroke",
"mouse": (0.0, 0.0),
"mouse_event": (0, 0),
"location": (0.0, 0.0, 0.0),
"is_start": True,
"pressure": 1.0,
"time": 1.0,
"size": 1.0,
"x_tilt": 0,
"y_tilt": 0
}
num_steps = 250
start = Vector((context['area'].width, context['area'].height))
end = Vector((0, 0))
delta = (end - start) / (num_steps - 1)
stroke = []
for i in range(num_steps):
step = template.copy()
step["mouse"] = start + delta * i
step["mouse_event"] = start + delta * i
stroke.append(step)
return stroke
def setup():
"""
Prepare the scene for rendering - generates objects then performs a stroke
"""
import bpy
context = bpy.context
# Create an undo stack explicitly. This isn't created by default in background mode.
bpy.ops.ed.undo_push()
# Forcibly flip the object out of and back into sculpt mode to avoid poll errors due to non-initialized
# tool runtime data.
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='SCULPT')
context_override = context.copy()
set_view3d_context_override(context_override)
with context.temp_override(**context_override):
bpy.ops.sculpt.brush_stroke(stroke=generate_stroke(context_override), override_location=True)
# Multires workaround - we need to leave sculpt mode currently to flush MDISP data so that the
# render actually works.
bpy.ops.object.mode_set(mode='OBJECT')
try:
import bpy
inside_blender = True
except ImportError:
inside_blender = False
if inside_blender:
try:
setup()
except Exception as e:
print(e)
sys.exit(1)
def get_arguments(filepath, output_filepath):
dirname = os.path.dirname(filepath)
args = [
"--background",
"--factory-startup",
"--enable-autoexec",
"--debug-memory",
"--debug-exit-on-error",
filepath,
"-E", "BLENDER_WORKBENCH",
"-P", os.path.realpath(__file__),
"-o", output_filepath,
"-f", "1",
"-F", "PNG"]
return args
def create_argparse():
parser = argparse.ArgumentParser(
description="Run test script for each blend file in TESTDIR, comparing the render result with known output."
)
parser.add_argument("--blender", required=True)
parser.add_argument("--testdir", required=True)
parser.add_argument("--outdir", required=True)
parser.add_argument("--oiiotool", required=True)
parser.add_argument("--batch", default=False, action="store_true")
return parser
def main():
parser = create_argparse()
args = parser.parse_args()
from modules import render_report
report = render_report.Report("Sculpt", args.outdir, args.oiiotool)
report.set_pixelated(True)
report.set_fail_threshold(2.0 / 255.0)
report.set_fail_percent(1.5)
report.set_reference_dir("reference")
ok = report.run(args.testdir, args.blender, get_arguments, batch=args.batch)
sys.exit(not ok)
if not inside_blender and __name__ == "__main__":
main()