File size: 2,428 Bytes
f2003dc
85388bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f2003dc
 
 
 
85388bf
 
 
f2003dc
85388bf
 
 
 
f2003dc
 
85388bf
 
 
 
f2003dc
85388bf
 
 
f2003dc
85388bf
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import json
import math
from functools import lru_cache
import os
from pathlib import Path
import shutil
import subprocess

from PIL import Image, ImageDraw

ROOT = Path(__file__).resolve().parents[1]


def blender():
    path = os.environ.get("BLENDER_BIN") or shutil.which("blender")
    local = Path("/Applications/Blender.app/Contents/MacOS/Blender")
    if not path and local.exists():
        path = str(local)
    if not path:
        raise RuntimeError("Install Blender or set BLENDER_BIN to render refinement evidence.")
    return path


@lru_cache(maxsize=1)
def check_renderer():
    subprocess.run([blender(), "--background", "--factory-startup", "--python-exit-code", "1",
                    "--python-expr", "import numpy; import _cycles; import io_scene_gltf2.blender.imp.mesh; "
                    "print('GLTF renderer ready; CPU denoising:', _cycles.with_openimagedenoise)"],
                   check=True, timeout=60, capture_output=True, text=True)


def render(model, folder, components=False, *, material_mode="original"):
    if material_mode not in {"original", "clay", "basecolor"}:
        raise ValueError("material_mode must be original, clay or basecolor")
    model, folder = Path(model), Path(folder)
    folder.mkdir(parents=True, exist_ok=True)
    command = [blender(), "--background", "--factory-startup", "--python-exit-code", "1",
               "--python", str(ROOT / "scripts/render_views.py"), "--",
               "--input", str(model), "--output", str(folder), "--material-mode", material_mode]
    if components:
        command.append("--components")
    with (folder / "render.log").open("w") as log:
        subprocess.run(command, stdout=log, stderr=subprocess.STDOUT, check=True, timeout=300)
    manifest = json.loads((folder / "render-manifest.json").read_text())
    paths = [(folder / item["file"], item["label"]) for item in manifest["images"]]
    if not paths:
        raise RuntimeError("Blender produced no review images.")
    sheet = Image.new("RGB", (384 * 3, 410 * math.ceil(len(paths) / 3)), "#20252b")
    draw = ImageDraw.Draw(sheet)
    for index, (path, label) in enumerate(paths):
        x, y = index % 3 * 384, index // 3 * 410
        with Image.open(path) as image:
            sheet.paste(image.convert("RGB"), (x, y + 26))
        draw.text((x + 10, y + 7), label, fill="white")
    sheet.save(folder / "contact.png")
    return folder / "contact.png"