
Tự động hóa render farm bằng Python: những gì có thể viết script hôm nay
Tổng quan
Phần chậm nhất của một lần render trên cloud thường là mọi thứ xung quanh chính việc render: scene lỗi vì một texture vẫn trỏ tới ổ đĩa cục bộ, lần tải lên phải làm lại từ đầu, những khung hình đã về mà không ai kiểm tra xem có về đủ hay không. Câu hỏi hữu ích là script Python thực sự với tới được đâu.
Chúng tôi vận hành Super Renders Farm, một render farm (hệ thống máy tính kết xuất) được quản lý toàn diện, và chúng tôi muốn nói chính xác về ranh giới này, vì phần tự động hóa dựng trên một đường đi không tồn tại sẽ hỏng ngay đêm chạy không người trông đầu tiên. Vì vậy, đây là bản nói thẳng ngay từ đầu. Việc chuyển tệp dự án lên farm có thể viết script: S3 access (Cloud Direct Connect trong tài khoản của bạn) cấp cho bạn một access key để AWS CLI dùng sao chép tệp tới và từ SRF Space của bạn. Việc gửi job thì không: job được gửi từ web dashboard, từ Client App, hoặc từ plugin gửi job bên trong 3ds Max, Maya hay Cinema 4D. Chúng tôi không cung cấp dịch vụ SFTP hay FTP, không có API hay SDK công khai, và không có endpoint gửi job nào để bạn gọi từ code. API công khai cho việc gửi job theo lập trình nằm trong lộ trình của chúng tôi; hiện chưa có, và không phần nào bên dưới phụ thuộc vào nó.
Lưu ý cho những bạn đã đọc trang này trước đây: phiên bản trước mô tả việc chuyển tệp bằng script qua SFTP. Đường đó không được cung cấp trên farm của chúng tôi; việc chuyển tệp bằng script nay đi qua S3 access, được trình bày bên dưới.
Như vậy Python vẫn còn rất nhiều việc để làm. Mọi thứ trước khi tải lên, chính việc tải lên, và mọi thứ sau khi các khung hình về tới ổ đĩa của bạn đều có thể viết script. Về bản đồ khái niệm của render headless và không người trông, hãy xem hướng dẫn quy trình render farm headless không cần người trông của chúng tôi; bài này dừng ở mức code.
Ranh giới nằm ở đâu trên một farm được quản lý
Trên farm của chúng tôi, pipeline chia thành bốn chặng.
- Trước khi tải lên: của bạn, hoàn toàn viết script được. Kiểm tra scene bên trong DCC, sửa đường dẫn, đóng gói, kiểm tra pre-flight, checksum.
- Tải lên: viết script được với S3 access, hoặc làm thủ công. AWS CLI sao chép thư mục dự án tới SRF Space của bạn từ một script. Các cách thủ công là tải lên qua web và SuperRenders Client App. Tải lên qua web không có giới hạn dung lượng cứng, nhưng không tiếp tục được nếu tab bị đóng, nên với bất cứ thứ gì lớn hơn vài gigabyte, hoặc khi kết nối không ổn định, hãy dùng Client App (tiếp tục được, chia khối song song) hoặc S3 access. Một lần tải lên qua trình duyệt sẽ chậm khi vượt khoảng 2 GB và không ổn định khi vượt khoảng 5 GB trên kết nối gia đình.
- Gửi job: thủ công. Bạn gửi job từ web dashboard, Client App hoặc plugin gửi job, và farm chạy Scene Analysis trên dự án đã tải lên trước khi job bị tính phí.
- Sau khi render: lại là của bạn. Khi bật tự động tải về của Client App, các khung hình được đưa về một thư mục cục bộ ngay khi từng khung hoàn tất, hoặc một script kéo chúng về qua S3. Từ lúc một khung hình nằm trên ổ đĩa của bạn, mọi bước kiểm tra, encode, sao chép và thông báo đều là script cục bộ.
Vì vậy hình dạng thực tế là tự động hóa ở cả hai đầu của một bước thủ công ngắn, và các script bên dưới giúp bước đó nhanh và khó làm sai. Bài giải thích của chúng tôi về render farm được quản lý toàn diện là gì trình bày những việc mô hình được quản lý xử lý thay bạn.
Ba làn: kiểm tra scene và tải lên S3 có thể script hóa, gửi job thủ công, rồi kiểm tra khung hình và encode có thể script hóa
Tự động hóa nằm ở cả hai đầu của một bước thủ công ngắn: kiểm tra, pre-flight, manifest và tải lên ở phía bạn, gửi job bằng tay, rồi xác minh và hậu xử lý những gì trả về.
Bước 1: Kiểm tra scene bên trong DCC
Theo kinh nghiệm của chúng tôi, phần lớn job render thất bại không phải do lỗi renderer. Đó là những lỗ hổng đóng gói: một texture nằm trên ổ đĩa mà farm không bao giờ nhìn thấy, một tệp tham chiếu chưa được thu thập, một cache nằm cao hơn thư mục gốc dự án một cấp. Worker chỉ mở được những gì nằm trong thư mục đã tải lên, nên script đầu tiên thuộc về bên trong DCC, nơi nó đọc được danh sách phụ thuộc của chính scene.
Mọi DCC lớn đều mở phần này qua Python: maya.cmds trong Maya, pymxs trong 3ds Max, module c4d trong Cinema 4D, hou trong Houdini, bpy trong Blender. Hãy chạy bước thu thập của chính DCC trước (Resource Collector trong 3ds Max, hoặc Archive rồi giải nén archive mà nó ghi ra; Save Project with Assets trong Cinema 4D; trong Blender, giữ asset dưới thư mục của tệp .blend và chạy Make Paths Relative). Bước thu thập gom tệp; script của bạn chứng minh kết quả. Phiên bản Blender chạy trong workspace Scripting hoặc headless với blender -b scene.blend --python check_paths.py:
# check_paths.py: runs inside Blender, reads the open .blend, touches nothing remote
import os
import sys
import bpy
def inside(path, root):
try:
a, b = os.path.normcase(path), os.path.normcase(root)
return os.path.commonpath([a, b]) == b
except ValueError:
return False # different drive on Windows
def main():
if not bpy.data.filepath:
if bpy.app.background:
sys.exit("save the .blend first")
print("save the .blend first")
return
bpy.ops.file.make_paths_relative() # rewrite paths under the .blend's folder to // form
blend_dir = os.path.dirname(bpy.data.filepath)
refs = [("image", i) for i in bpy.data.images
if i.source == "FILE" and not i.packed_file] # skip generated, sequence, UDIM, packed
refs += [("library", lib) for lib in bpy.data.libraries]
refs += [("cache", c) for c in bpy.data.cache_files] # Alembic and USD caches
refs += [("volume", v) for v in bpy.data.volumes] # OpenVDB volumes
issues = []
for kind, block in refs:
full = os.path.abspath(bpy.path.abspath(block.filepath))
if not os.path.exists(full):
issues.append((f"missing {kind}", block.name, block.filepath))
elif not inside(full, blend_dir):
issues.append(("outside project", block.name, block.filepath))
for kind, name, path in issues:
print(f"{kind:16} {name:32} {path}")
if not issues:
bpy.ops.wm.save_mainfile() # keep the relative paths only when the scene is clean
if bpy.app.background:
sys.exit(1 if issues else 0)
main()
Mẫu này áp dụng cho mọi DCC: phân giải mọi tham chiếu tệp, đánh dấu thứ gì bị thiếu, và đánh dấu bất cứ thứ gì phân giải ra ngoài thư mục gốc dự án.
Một số dự án không thể chuyển sang đường dẫn tương đối, vì thư viện scatter, thư viện người và một số cache chứa đường dẫn tuyệt đối bên trong. Với những dự án đó, tùy chọn Auto keep local path của Client App giữ nguyên cấu trúc thư mục tuyệt đối khi tải lên, và khi đường dẫn phía farm phải khác đường dẫn cục bộ của bạn, tiện ích Simulate Local Path của chúng tôi tái tạo đường dẫn mà scene mong đợi. Khi đó script của bạn kiểm tra "mọi thứ nằm dưới các gốc bạn giữ lại" thay vì "mọi thứ nằm dưới gốc dự án". Với 3ds Max, hướng dẫn cách đóng gói tệp 3ds Max của chúng tôi đi qua từng bước thu thập.
Bước 2: Kiểm tra pre-flight thư mục dự án
Bước kiểm tra trong DCC hiểu scene; bước kiểm tra thư mục hiểu phần tải lên. Nó bắt những vấn đề nằm trên đĩa: không có tệp scene, một archive ai đó thả vào, tệp 0 byte do sao chép bị gián đoạn, đường dẫn dài đến mức làm vấp các ứng dụng Windows cũ hơn.
Kiểm tra archive quan trọng hơn vẻ ngoài của nó. Farm không giải nén archive (.zip, .rar, .7z, .tar, .tar.gz), nên không có gì bên trong archive được render. Hãy tải lên thư mục dự án ở dạng chưa nén, với tệp scene và mọi asset được tham chiếu nằm đúng chỗ.
#!/usr/bin/env python3
"""preflight.py: check a project folder before upload. Reads local disk only."""
import json
import sys
from pathlib import Path
SCENE_SUFFIXES = {".max", ".ma", ".mb", ".c4d", ".blend", ".hip", ".hiplc", ".aep"}
ARCHIVE_SUFFIXES = {".zip", ".rar", ".7z", ".tar", ".tgz"} # the farm does not extract these
SINGLE_BROWSER_UPLOAD_GB = 2 # above this, use the Client App or S3 access instead
LONG_PATH = 240 # headroom under the classic 260-character Windows limit
def preflight(root: Path) -> dict:
files = [p for p in root.rglob("*") if p.is_file()]
scenes = [p for p in files if p.suffix.lower() in SCENE_SUFFIXES]
total = sum(p.stat().st_size for p in files)
problems, warnings = [], []
if not scenes:
problems.append("no scene file found in the folder")
for p in files:
rel = p.relative_to(root)
if p.suffix.lower() in ARCHIVE_SUFFIXES or p.name.lower().endswith(".tar.gz"):
problems.append(f"archive will not be unpacked: {rel}")
if p.stat().st_size == 0:
warnings.append(f"zero-byte file: {rel}")
if len(str(p)) > LONG_PATH:
warnings.append(f"long path ({len(str(p))} chars): {rel}")
if total > SINGLE_BROWSER_UPLOAD_GB * 1024**3:
warnings.append("over ~2 GB: use the Client App or S3 access, not one browser upload")
return {"root": str(root), "files": len(files), "gigabytes": round(total / 1024**3, 2),
"scenes": [str(p.relative_to(root)) for p in scenes],
"problems": problems, "warnings": warnings}
if __name__ == "__main__":
report = preflight(Path(sys.argv[1]).resolve())
print(json.dumps(report, indent=2))
sys.exit(1 if report["problems"] else 0)
Mã thoát khác 0 chính là điểm mấu chốt. Hãy nối script vào bất cứ công cụ nào vốn đã chạy vào cuối ngày làm việc của artist (một công cụ publish, một save hook, một nút "ready for farm") để một dự án có vấn đề không bao giờ tới được bước tải lên. Cảnh báo (warning) chỉ được in ra; vấn đề (problem) thì chặn lại.
Bước 3: Ghi manifest để biết chính xác mình đã gửi gì
Khi một dự án vượt qua pre-flight, hãy ghi lại nó. Manifest liệt kê mọi tệp cùng kích thước và hash SHA-256, được ghi bên cạnh dự án chứ không nằm bên trong để nó không bao giờ trở thành một phần của lần tải lên. Nó trả lời ba câu hỏi mà nếu không sẽ tốn cả một buổi chiều: phiên bản scene nào đã render, đã thay đổi gì kể từ lần gửi trước, và thư mục trên đĩa có còn khớp với những gì đã được tải lên hay không.
# manifest.py: hash a project folder and compare two snapshots. Local files only.
import hashlib
import json
import time
from pathlib import Path
def sha256(path: Path, chunk: int = 8 * 1024 * 1024) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
while block := f.read(chunk):
h.update(block)
return h.hexdigest()
def write_manifest(root: Path, out: Path) -> dict:
files = [{"path": p.relative_to(root).as_posix(), "bytes": p.stat().st_size, "sha256": sha256(p)}
for p in sorted(root.rglob("*")) if p.is_file()]
manifest = {"project": root.name, "created": time.strftime("%Y-%m-%dT%H:%M:%S"), "files": files}
out.write_text(json.dumps(manifest, indent=2))
return manifest
def diff_manifests(old: dict, new: dict):
a = {f["path"]: f["sha256"] for f in old["files"]}
b = {f["path"]: f["sha256"] for f in new["files"]}
changed = sorted(k for k in a.keys() & b.keys() if a[k] != b[k])
return sorted(b.keys() - a.keys()), sorted(a.keys() - b.keys()), changed
Hãy lưu manifest theo shot và phiên bản (shot010_v003.manifest.json) và phần diff trở thành một dòng tóm tắt: "hai texture đã đổi, một cache được thêm, không có gì bị xóa".
Viết script chuyển tệp bằng AWS CLI
S3 access (Cloud Direct Connect trong tài khoản của bạn) cho phép bạn tạo một access key, rồi kết nối Cyberduck (giao thức: Amazon S3) hoặc AWS CLI với SRF Space của bạn để tải tệp lên và tải về. Cyberduck phù hợp với người muốn có trình duyệt tệp; AWS CLI là công cụ mà một script điều khiển được. S3 access chỉ di chuyển tệp: nó không phải dịch vụ SFTP hay FTP, và không gửi job.
Việc thiết lập chỉ làm một lần trên mỗi máy. Trong tài khoản của bạn, mở Cloud Direct Connect, tạo một access key, và sao chép Access Key ID, Secret Access Key cùng Remote Directory. Sau đó lưu key vào một AWS profile có tên:
aws configure --profile srf # both keys; region ap-southeast-1; output format blank or json
export AWS_PROFILE=srf # the AWS CLI and boto3 both read this
Hãy tải thư mục dự án ở dạng chưa nén, chính thư mục đã vượt qua pre-flight, vào Remote Directory của bạn:
aws s3 cp ./shot010_v003 "s3://<your Remote Directory>/shot010_v003/" --recursive
aws s3 sync nhận cùng nguồn và đích nhưng không cần --recursive, và chỉ sao chép những tệp mới hoặc đã thay đổi theo kích thước hoặc dấu thời gian, nên chạy lại sau một lần truyền bị gián đoạn sẽ bỏ qua những gì đã tới nơi. Các tệp lớn được tự động chia thành nhiều phần và tải lên song song. Các tệp tải lên theo cách này xuất hiện trong SRF Space của bạn và có thể được gửi job như mọi lần tải lên khác. Một lưu ý cho pre-flight: khi một dự án đồng bộ tới các render node, những tệp khớp *.ini, *.db, *.tmp, *.temp, *.lnk, *.swap và *.partial, cùng mọi thư mục rendertemp/, sẽ bị bỏ qua, nên scene không được phụ thuộc vào chúng.
Phần Python chỉ là một lớp bọc mỏng: chạy pre-flight, từ chối tải lên nếu có vấn đề, rồi giao thư mục cho AWS CLI.
# upload_project.py: pre-flight, then copy the folder to your SRF Space with the AWS CLI.
import os
import subprocess
import sys
from pathlib import Path
from preflight import preflight # the Step 2 script
def upload(project: Path, remote_dir: str) -> None:
report = preflight(project)
if report["problems"]:
sys.exit("pre-flight failed: " + "; ".join(report["problems"]))
target = f"s3://{remote_dir.removeprefix('s3://').strip('/')}/{project.name}/"
subprocess.run(["aws", "s3", "sync", str(project), target,
"--region", "ap-southeast-1"], check=True)
if __name__ == "__main__":
upload(Path(sys.argv[1]).resolve(), os.environ["SRF_REMOTE_DIR"])
Nếu bạn muốn ở lại trong Python, upload_file của boto3 làm cùng việc đó với bucket và prefix trong Remote Directory của bạn, dùng cùng profile và region.
Cùng key này dùng được theo chiều ngược lại. Kết quả render nằm trong thư mục SuperRendersOutput/<jobId>/ của Space của bạn (aws s3 ls "s3://<your Remote Directory>/SuperRendersOutput/" liệt kê các thư mục job), và một lệnh kéo một job về thư mục cục bộ:
aws s3 sync "s3://<your Remote Directory>/SuperRendersOutput/<jobId>/" ./renders/shot010_v003/
Hãy đối xử với key như một mật khẩu:
- Bất cứ ai giữ key đều truy cập được SRF Space của bạn. Giữ nó trong một AWS profile hoặc trong các biến môi trường
AWS_ACCESS_KEY_IDvàAWS_SECRET_ACCESS_KEYtrên máy chạy phần tải lên, không bao giờ để trong chính script. - Đừng bao giờ commit nó vào repository hay dán vào cấu hình pipeline dùng chung. Hãy giữ cả Remote Directory trong một biến môi trường, như ở trên.
- Mỗi tài khoản có một key, và key không hết hạn. Nếu bạn nghĩ key đã bị lộ, hoặc cần thay đổi, hãy liên hệ đội hỗ trợ của chúng tôi.
Phần còn lại thủ công là việc gửi job. Sau khi tải lên, bạn vẫn gửi job từ web dashboard, Client App hoặc một plugin DCC.
Bước 4: Làm cho bước bàn giao gửi job ngắn gọn và lặp lại được
Gửi job là việc một người bấm qua một biểu mẫu, nên hãy để biểu mẫu là phần dễ nhất. Hãy để bước kiểm tra cũng ghi một phiếu bàn giao nhỏ bên cạnh manifest: tệp scene, camera, dải khung hình, độ phân giải, định dạng đầu ra, render engine, và thư mục cục bộ nơi các khung hình sẽ về. Người gửi job sao chép giá trị thay vì phải nhớ, và watcher ở Bước 5 đọc cùng phiếu đó, nên hai bên không thể mâu thuẫn.
Ba quy ước giúp chuỗi này dễ tự động hóa hơn:
- Một thư mục cho mỗi shot và phiên bản (
shot010_v003/), với tệp scene ở gốc. Pre-flight, manifest, đích tải lên và phiếu bàn giao đều bám theo cái tên đó. - Số khung hình có đệm số 0 trong tên đầu ra (
shot010.1001.exr). Watcher không thể xác minh một dải mà nó không phân tích được. - Một thư mục tải về dự đoán được cho mỗi job. Client App tải về một đường dẫn mặc định đặt trong phần cài đặt, và bạn có thể ghi đè đường dẫn cho từng job khi gửi. Hãy trỏ nó tới thư mục render riêng của shot.
Trong 3ds Max, Maya và Cinema 4D, plugin gửi job đọc dải khung hình, đường dẫn đầu ra và thiết lập render từ scene đang mở, điền sẵn biểu mẫu job và tự chạy bước kiểm tra asset. Blender, Houdini và After Effects không có plugin trong DCC, nên các job đó đi qua Client App hoặc web dashboard. Dù cách nào, Scene Analysis cũng chạy trước khi job bị tính phí; các script của bạn giúp cổng đó chặn bạn ít lần hơn.
Bước 5: Xác minh các khung hình trả về
Khi Client App đang chạy và tự động tải về được bật (mặc định), mỗi khung hình được tải về máy của bạn ngay khi hoàn tất trên farm; với S3 access, lần chạy aws s3 sync của chính bạn sẽ điền vào một thư mục cục bộ. Dù cách nào, câu hỏi trở thành "làm sao tôi biết tất cả đã về nguyên vẹn". Một watcher trả lời điều đó chỉ từ các tệp cục bộ: một khung hình chỉ được coi là hoàn tất khi kích thước của nó ngừng thay đổi giữa hai lần kiểm tra và header của tệp hợp lệ.
# watch_frames.py: verify frames arriving in a local folder. Reads local disk only.
import re
import time
from pathlib import Path
MAGIC = {".exr": b"\x76\x2f\x31\x01", ".png": b"\x89PNG\r\n\x1a\n"}
def header_ok(path: Path) -> bool:
magic = MAGIC.get(path.suffix.lower())
with open(path, "rb") as f:
head = f.read(8)
return head.startswith(magic) if magic else len(head) > 0
def watch(job_dir: Path, first: int, last: int, poll: int = 60, give_up_hours: float = 24,
name_re: str = r"\.(\d{4,})\.(exr|png)$") -> list:
# name_re: default matches any frame-numbered file. Anchor it to one pass's file
# prefix (e.g. r"^shot010_beauty\.(\d{4,})\.(exr)$") when the job writes render
# elements or AOVs as separate files, so this watcher tracks a single pass.
pattern = re.compile(name_re, re.IGNORECASE)
expected = set(range(first, last + 1))
last_size, done = {}, {}
deadline = time.time() + give_up_hours * 3600
while True:
for p in job_dir.rglob("*"):
m = pattern.search(p.name) if p.is_file() else None
if not m or int(m.group(1)) not in expected or int(m.group(1)) in done:
continue
size = p.stat().st_size
if size > 0 and last_size.get(p) == size and header_ok(p):
done[int(m.group(1))] = p # stable across two polls, valid header
last_size[p] = size
missing = sorted(expected - done.keys())
print(f"{len(done)}/{len(expected)} frames verified, {len(missing)} outstanding")
if not missing:
return [done[f] for f in sorted(done)]
if time.time() > deadline:
raise TimeoutError(f"frames still missing: {missing[:20]}")
time.sleep(poll)
Việc tìm kiếm là đệ quy, nên các khung hình được tìm thấy theo tên bất kể cách tổ chức thư mục con của lần tải về. Khi job hiển thị là đã hoàn tất mà watcher vẫn báo còn thiếu, hãy dùng Sync output trên job đó trong Client App, chức năng này tải lại các khung hình còn thiếu (hoặc chạy lại aws s3 sync), rồi để watcher chạy lại; làm tương tự nếu kích thước của một khung hình trông ngắn hơn bình thường, vì một lần tải về dở dang bị đứng cũng có thể trông ổn định. Nếu bạn thích sự kiện hơn là polling, gói watchdog bọc các thông báo thay đổi tệp của hệ điều hành; dù chọn cách nào cũng hãy giữ bước kiểm tra độ ổn định. Nếu một job ghi render element hoặc AOV thành các tệp riêng, hãy chạy một watcher cho mỗi pass, nếu không một pass đã xong có thể che mất một khung hình beauty còn thiếu có cùng số thứ tự.
Bước 6: Các bước hậu render cục bộ
Khi watcher trả về một danh sách đã xác minh, phần còn lại là code pipeline thông thường:
import subprocess
def encode_review(frames_dir, pattern, start, out, fps=24): # pattern e.g. "shot010.%04d.png"
subprocess.run(["ffmpeg", "-y", "-framerate", str(fps), "-start_number", str(start),
"-i", f"{frames_dir}/{pattern}", "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
"-c:v", "libx264", "-pix_fmt", "yuv420p", "-crf", "18", str(out)], check=True)
Một vài thói quen đáng học theo:
- Encode từ các khung hình theo hệ hiển thị (display-referred). PNG hoặc JPEG có thể đi thẳng vào một video review. EXR tuyến tính cần pipeline màu của bạn (thường là một phép biến đổi OCIO) trước, nếu không video sẽ trông tối và phẳng.
- Lưu manifest cùng các khung hình. Sáu tháng sau, "những texture nào đã tạo nên bản render này" chỉ cách một tệp.
- Thông báo bằng dữ kiện. Số khung hình, số khung hình cần sync, tổng dung lượng, đường dẫn video review, đăng lên chat hoặc công cụ theo dõi của studio.
- Giữ bản sao của riêng bạn làm kho lưu trữ chính thức. Các tệp trên farm của chúng tôi được giữ chừng nào còn cần để chạy job của bạn và để bạn tải kết quả về, không có thời hạn tự động xóa cố định, và chúng tôi xóa bất cứ khi nào bạn yêu cầu. Đó không phải kế hoạch sao lưu; kho lưu trữ cục bộ của bạn mới là kế hoạch sao lưu.
Lập lịch cho các phần chạy cục bộ
Không phần nào ở trên cần một scheduler mới. Cron trên Linux, launchd trên macOS hay Task Scheduler trên Windows có thể chạy pre-flight, manifest và phần tải lên bằng AWS CLI cho các dự án được đánh dấu "ready" mỗi buổi tối, để tệp đã nằm trong SRF Space của bạn trước khi có ai ngồi xuống gửi job. Watcher có thể bắt đầu ngay sau khi gửi job, hoặc chạy như một trình quét trên danh sách theo dõi được nạp từ các phiếu bàn giao ở Bước 4.
Một phụ thuộc cần tính trước: tự động tải về chỉ diễn ra khi Client App đang chạy trên một máy đang thức và có mạng. Trên Windows, nó cài một background service giữ cho việc truyền tiếp tục sau khi đóng cửa sổ chính. Hãy chạy nó, hoặc aws s3 sync đã lên lịch của bạn, trên một máy bật suốt đêm.
Tóm tắt: nên tự động hóa gì, và bằng cách nào
| Giai đoạn | Viết script được trên farm của chúng tôi hiện nay? | Cách làm |
|---|---|---|
| Kiểm tra scene (đường dẫn thiếu và tuyệt đối) | Có | Python bên trong DCC (bpy, maya.cmds, pymxs, c4d, hou) |
| Kiểm tra pre-flight thư mục dự án | Có | Script cục bộ; chặn khi có archive, thiếu scene, tệp 0 byte |
| Manifest và diff thay đổi | Có | SHA-256 cho từng tệp, JSON bên cạnh dự án |
| Tải lên farm | Có, với S3 access | AWS CLI (aws s3 cp --recursive hoặc aws s3 sync) với key từ Cloud Direct Connect; các cách thủ công là tải lên qua web (chậm khi vượt khoảng 2 GB, không ổn định khi vượt khoảng 5 GB) và Client App (tiếp tục được, chia khối song song) |
| Gửi job | Không | Web dashboard, Client App, hoặc plugin trong 3ds Max, Maya, Cinema 4D; API công khai nằm trong lộ trình |
| Tải về các khung hình đã xong | Có, với S3 access, hoặc được xử lý giúp bạn | aws s3 sync từ SuperRendersOutput/<jobId>/; hoặc tự động tải về của Client App, từng khung hình một; hoặc tải về qua web |
| Xác minh khung hình | Có | Watcher cục bộ: kích thước ổn định, header hợp lệ, đủ dải khung hình |
| Encode, lưu trữ, thông báo | Có | ffmpeg, sao chép tệp, chat hoặc công cụ theo dõi của bạn |
Hãy tự động hóa cả hai đầu, giữ phần giữa ngắn và có chủ đích, và xác minh mọi thứ trả về. Nếu phần lớn dự án của bạn là scene Blender, trang Blender cloud render farm của chúng tôi cho biết các job đó chạy ra sao ở phía chúng tôi, còn tài liệu Client App và tài liệu plugin gửi job mô tả chi tiết các bước thủ công.
FAQ
Q: Tôi có thể tải dự án lên render farm từ một script Python không?
A: Có, với S3 access. Tạo một access key dưới Cloud Direct Connect trong tài khoản của bạn, cấu hình AWS CLI với key đó (region ap-southeast-1), và để script của bạn chạy aws s3 cp --recursive hoặc aws s3 sync trên thư mục dự án chưa nén vào Remote Directory của bạn. Hãy chạy bước kiểm tra pre-flight trước để một dự án hỏng không bao giờ được tải lên. Việc gửi job sau đó vẫn làm thủ công.
Q: Tôi nên dùng S3 access hay Client App? A: Dùng S3 access khi việc truyền tệp cần chạy từ một script hoặc một scheduler, hoặc khi nhóm của bạn đã quen với một S3 client như Cyberduck. Dùng Client App khi có người tải lên bằng tay: nó tiếp tục các lần truyền lớn sau khi mất kết nối, gửi job, và tự động tải về các khung hình khi từng khung hoàn tất. Hai cách kết hợp tốt với nhau: S3 access cho việc truyền tệp bằng script, Client App cho việc gửi job.
Q: Có API hay SDK để gửi job render từ pipeline của tôi không? A: Hiện chưa có. Job được gửi từ web dashboard, Client App, hoặc plugin gửi job trong 3ds Max, Maya hay Cinema 4D. API công khai cho việc gửi job theo lập trình nằm trong lộ trình của chúng tôi nhưng chưa khả dụng, vì vậy hãy xây phần tự động hóa quanh các chặng bạn kiểm soát. Nếu pipeline của bạn đang bị chặn vì thiếu nó, hãy cho đội hỗ trợ của chúng tôi biết trường hợp sử dụng.
Q: Farm có cung cấp truy cập SFTP hoặc FTP cho các lần truyền lớn không? A: Không. Chúng tôi không chạy dịch vụ SFTP hay FTP cho việc tải lên, tải về hoặc máy thuê. Các dự án lớn đi qua Client App, vốn tải lên theo từng khối song song và tiếp tục được, hoặc qua S3 access với Cyberduck hay AWS CLI. Các khung hình đã xong quay về qua tự động tải về của Client App, tải về qua web, hoặc S3 access.
Q: Làm sao tôi biết tất cả khung hình đã về?
A: Chạy một watcher trên thư mục nơi Client App tự động tải job về, hoặc nơi aws s3 sync của bạn ghi ra. Chỉ tính một khung hình là xong khi kích thước của nó ổn định qua hai lần kiểm tra và header hợp lệ, rồi so sánh tập đã xác minh với dải mong đợi. Nếu job đã hoàn tất mà vẫn thiếu khung hình, hãy dùng Sync output trong Client App hoặc chạy lại lệnh sync.
Q: Tôi có nên nén zip dự án trước khi tải lên để tiết kiệm thời gian không? A: Không. Farm không giải nén archive (.zip, .rar, .7z, .tar, .tar.gz), nên không có gì bên trong archive được render. Hãy tải lên thư mục dự án ở dạng chưa nén, với tệp scene và mọi asset được tham chiếu nằm đúng chỗ, dù bạn dùng đường tải lên nào.
Q: Các khung hình đã render được giữ trên farm trong bao lâu? A: Không có thời hạn tự động xóa cố định. Các tệp được giữ chừng nào còn cần để chạy job của bạn và để bạn tải kết quả về, và chúng tôi xóa bất cứ khi nào bạn yêu cầu. Hãy coi nơi lưu trữ của riêng bạn là kho lưu trữ chính thức, và dùng tự động tải về của Client App để các khung hình về ổ đĩa của bạn ngay khi từng khung hoàn tất.
About Alice Harper
Blender and V-Ray specialist. Passionate about optimizing render workflows, sharing tips, and educating the 3D community to achieve photorealistic results faster.



