Blender 원본 검사와 승인 경계를 지키는 로컬 렌더 실행기 추가
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
"""작은 3D 영상과 같은 논리 프레임의 서로 다른 Scene을 실제로 확인한다."""
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
import run
|
||||
from test_runner import fixture, production_fixture, endpoint_fixture, ROOT
|
||||
from test_runner import write
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="설치 정보가 아닌 실제 렌더·디코드 검사")
|
||||
parser.add_argument("--blender", required=True)
|
||||
parser.add_argument("--ffmpeg", required=True)
|
||||
parser.add_argument("--ffprobe", required=True)
|
||||
parser.add_argument("--engine", choices=("CYCLES", "BLENDER_EEVEE"), default="CYCLES")
|
||||
args = parser.parse_args()
|
||||
folder, project, artifacts, job = fixture()
|
||||
if args.engine == "BLENDER_EEVEE":
|
||||
artifacts["08-scenes"]["payload"]["preview"]["render_profile"].update(engine="BLENDER_EEVEE", device="GPU")
|
||||
write(ROOT / job["artifact"], artifacts["08-scenes"])
|
||||
source = ROOT / job["source"]
|
||||
# fixture의 검사 전 바이트는 생성 원본이 아니다. 실패 흔적은 별도 파일로 보존한다.
|
||||
source.rename(source.with_suffix(".uninspected"))
|
||||
run.execute([args.blender, "--background", "--factory-startup", "--disable-autoexec", "--python-exit-code", "1", "--python",
|
||||
Path(__file__).with_name("smoke_fixture.py"), "--", source])
|
||||
video = run.render(ROOT, job, args.blender, args.ffmpeg, args.ffprobe)
|
||||
require = run.require
|
||||
require(video["media"]["duration_ms"] == 1000, "검사 영상 길이 불일치")
|
||||
attempt = (ROOT / video["media"]["path"]).parent
|
||||
require(run.digest(attempt / "frame-00000000.png") != run.digest(attempt / "frame-00000009.png"), "3D 움직임이 없습니다")
|
||||
still_job = dict(job, frame=10, start=None, end=None)
|
||||
first = run.render(ROOT, still_job, args.blender, args.ffmpeg, args.ffprobe)
|
||||
second = run.render(ROOT, dict(still_job, scene="SceneB"), args.blender, args.ffmpeg, args.ffprobe)
|
||||
require(first["identity"] != second["identity"] and run.digest(ROOT / first["media"]["path"]) != run.digest(ROOT / second["media"]["path"]),
|
||||
"같은 논리 프레임의 다른 Scene 카메라가 혼입되었습니다")
|
||||
for invalid in (dict(still_job, scene="Missing"), dict(still_job, require_object=["Missing"])):
|
||||
try:
|
||||
run.render(ROOT, invalid, args.blender, args.ffmpeg, args.ffprobe)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("없는 Scene/오브젝트를 거부하지 않았습니다")
|
||||
for change in ("external", "short_scene"):
|
||||
bad_source = source.with_name(change + ".blend")
|
||||
options = ["--external-image", ROOT / first["media"]["path"]] if change == "external" else ["--short-scene"]
|
||||
run.execute([args.blender, "--background", "--factory-startup", "--disable-autoexec", "--python-exit-code", "1", "--python",
|
||||
Path(__file__).with_name("smoke_fixture.py"), "--", bad_source, *options])
|
||||
artifacts["08-scenes"]["payload"]["preview"]["scene_file"]["path"] = bad_source.relative_to(ROOT).as_posix()
|
||||
write(ROOT / job["artifact"], artifacts["08-scenes"])
|
||||
try:
|
||||
run.render(ROOT, dict(job, source=bad_source.relative_to(ROOT).as_posix()), args.blender, args.ffmpeg, args.ffprobe)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("외부 참조/실제 Scene 범위 오류를 거부하지 않았습니다")
|
||||
approved_folder, approved_project, approved_artifacts, approved_job = production_fixture()
|
||||
old_source = ROOT / approved_artifacts["08-scenes"]["payload"]["preview"]["scene_file"]["path"]
|
||||
old_source.rename(old_source.with_suffix(".uninspected"))
|
||||
shutil.copyfile(source, old_source)
|
||||
approved_artifacts["08-scenes"]["payload"]["preview"]["scene_file"].update(sha256=run.digest(old_source), blender_version=video["scene_file"]["blender_version"])
|
||||
write(approved_folder / "stages/08-scenes/r2/artifact.json", approved_artifacts["08-scenes"])
|
||||
production_source = ROOT / approved_job["source"]
|
||||
production_source.rename(production_source.with_suffix(".uninspected"))
|
||||
shutil.copyfile(source, production_source)
|
||||
production = run.render(ROOT, approved_job, args.blender, args.ffmpeg, args.ffprobe)
|
||||
require(production["media"]["kind"] == "image", "승인된 10 기준 PNG가 아닙니다")
|
||||
actual_motion = None
|
||||
for motion in (False, True):
|
||||
target_folder, target_project, target_artifacts, target_job = endpoint_fixture(motion)
|
||||
for stage in ("08-scenes", "10-references", "11-images"):
|
||||
item = target_artifacts[stage]["payload"]
|
||||
result = item["preview"] if stage == "08-scenes" else item["result"]
|
||||
metadata = result["scene_file"] if result else None
|
||||
path = ROOT / (metadata["path"] if metadata else item["request"]["scene_path"])
|
||||
path.rename(path.with_suffix(".uninspected"))
|
||||
shutil.copyfile(source, path)
|
||||
if metadata:
|
||||
metadata.update(sha256=run.digest(path), blender_version=video["scene_file"]["blender_version"])
|
||||
(item["preview"] if stage == "08-scenes" else item["request"])["render_profile"].update(
|
||||
engine=args.engine, device="GPU" if args.engine == "BLENDER_EEVEE" else "CPU")
|
||||
if motion:
|
||||
target_artifacts["12-motion"]["payload"]["request"]["render_profile"].update(
|
||||
engine=args.engine, device="GPU" if args.engine == "BLENDER_EEVEE" else "CPU")
|
||||
for pointer in target_project["stages"]:
|
||||
if pointer["stage_id"] in target_artifacts:
|
||||
write(ROOT / pointer["artifact_path"], target_artifacts[pointer["stage_id"]])
|
||||
actual = run.render(ROOT, target_job, args.blender, args.ffmpeg, args.ffprobe)
|
||||
require(actual["media"]["kind"] == ("video" if motion else "image"), "승인된 11/12 렌더 형식이 다릅니다")
|
||||
if motion:
|
||||
actual_motion = actual["media"]
|
||||
for failure in folder.rglob("failure.json"):
|
||||
require(not list(failure.parent.glob("*.png")), "실패 검사에서 출력 PNG를 썼습니다")
|
||||
print(json.dumps(dict(video=video["media"], first_scene=first["media"], second_scene=second["media"],
|
||||
production_reference=production["media"],
|
||||
production_clip=actual_motion,
|
||||
renderer=video["render_profile"], source=video["scene_file"], result="실제 렌더·디코드·움직임·다중 Scene·승인된 기준 생성·외부 참조 거부 검사 통과"), ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user