動畫的 GLB 或 GLTF 模型儲存幾何和動畫資料,而不是一個包含現成圖像的資料夾。若要建立縮圖或影格序列,您需要在特定時間點評估模型的動畫,並將每個產生的場景渲染為圖像。本教學說明如何使用 Aspose.3D for Python via .NET 在 Python 中渲染 GLB 動畫影格。您將載入動畫模型,選取一段剪輯,取樣其時間軸,並將每個影格儲存為編號的 PNG 圖像。您可以將產生的圖像用作模型預覽,或作為獨立影像序列工作流程的輸入。

安裝 Aspose.3D for Python via .NET

使用 pip 安裝 package:

pip install aspose-3d

您還需要:

  • 一個動畫的 .glb 檔案或帶有相應緩衝區和紋理的 .gltf 檔案。
  • 符合 Aspose.3D 硬體需求的渲染環境。請參閱 system requirements。
  • 相機位置能在取樣時間軸上保持動畫物件在視野內。

將動畫剪輯渲染為 PNG 幀

將以下程式碼儲存為 render_glb_animation_frames.py,並從包含 animated_model.glb 的資料夾中執行它。

import hashlib
import math
from pathlib import Path

import aspose.threed as a3d
from aspose.pydrawing import Color, Size
from aspose.pydrawing.imaging import ImageFormat
from aspose.threed.entities import Camera
from aspose.threed.utilities import Vector3

INPUT_FILE = Path("animated_model.glb")
OUTPUT_DIR = Path("frames")
FRAMES_PER_SECOND = 5
IMAGE_WIDTH = 800
IMAGE_HEIGHT = 600

def main():
    if not INPUT_FILE.is_file():
        raise FileNotFoundError(f"Input model not found: {INPUT_FILE}")

scene = a3d.Scene.from_file(str(INPUT_FILE))
    clips = list(scene.animation_clips)
    if not clips:
        raise RuntimeError("The input model has no animation clips.")

clip = clips[0]
    duration = float(clip.stop - clip.start)
    if duration <= 0:
        raise ValueError("The selected animation has no positive time range.")

# Use the same camera position for every frame.
    camera = Camera()
    camera_node = scene.root_node.create_child_node("PreviewCamera", camera)
    camera_node.transform.translation = Vector3(3, 2, 6)
    camera.look_at = Vector3.ORIGIN

options = a3d.ImageRenderOptions()
    options.background_color = Color.white
    options.asset_directories.append(str(INPUT_FILE.resolve().parent))

OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    frame_count = max(1, math.ceil(duration * FRAMES_PER_SECOND))
    hashes = set()

for frame_index in range(frame_count):
        timestamp = float(clip.start) + frame_index / FRAMES_PER_SECOND
        clip.apply_to(timestamp)

frame_path = OUTPUT_DIR / f"frame_{frame_index:04d}.png"
        scene.render(
            camera,
            str(frame_path),
            Size(IMAGE_WIDTH, IMAGE_HEIGHT),
            ImageFormat.png,
            options,
        )

if not frame_path.is_file() or frame_path.stat().st_size == 0:
            raise RuntimeError(f"Rendering did not create a usable PNG: {frame_path}")

hashes.add(hashlib.sha256(frame_path.read_bytes()).digest())
        print(f"Frame {frame_index + 1}/{frame_count}: {frame_path} at {timestamp:.3f}s")

if frame_count > 1 and len(hashes) == 1:
        print("WARNING: All PNG files are byte-identical. Check animation state and camera view.")

print(f"Created {frame_count} PNG file(s) in {OUTPUT_DIR}/")

if __name__ == "__main__":
    main()

執行方式:

python render_glb_animation_frames.py

預期輸出: 一個名為 frames 的目錄,內含如 frame_0000.png、frame_0001.png 和 frame_0002.png 等圖像。當渲染器正確捕獲已套用的動畫狀態時,圖像會顯示模型在動畫中的連續幀。

框架渲染程式碼的工作方式

載入場景並選擇動畫剪輯

Scene.from_file() 方法打开模型,而 scene.animation_clips 提供对其包含的动画剪辑的访问。示例使用第一个剪辑并读取其 start 和 stop 属性以确定时间范围。没有动画剪辑的模型无法通过此方法生成动画序列。

有關剪輯選擇和節點變換的更多詳細資訊,請參閱 Load and Evaluate GLB/GLTF Animations in Python。

在規則間隔抽樣時間軸

腳本每秒使用五個樣本。如果剪輯持續兩秒,則在剪輯從零開始時,會在 0.0 到 1.8 秒的時間戳上請求十個幀。排除精確的終點可避免為循環回到起始姿勢的動畫產生多餘的最後一幀。

clip.apply_to(timestamp) 方法會在每個時間戳上套用所選的動畫剪輯。與僅評估單一關鍵幀序列不同,此步驟旨在於圖像渲染之前更新動畫場景。

從單一相機渲染更新的場景

此範例在固定位置新增相機,並在每個畫格呼叫 scene.render()。它還設定 800 × 600 像素的影像大小與 PNG 輸出格式。將相機固定可使逐畫格差異更容易檢查。

The Aspose.3D 場景渲染指南 說明如何將 3D 視圖儲存為圖像。對於動畫序列,請確認每張圖像都反映了預期的時間戳記。如果連續的幀顯示相同的姿勢,請檢查渲染路徑是否使用了當前的動畫狀態。

一致地為每個 PNG 框架命名

frame_0000.png 模式在按檔名排序時保持圖像的順序。它適用於生成預覽縮圖或將輸出傳遞給單獨的圖像序列或影片工作流程。此腳本不會建立影片或動畫 GIF。

腳本還會比較檔案雜湊值,以在所有輸出檔案位元相同時發出警告。不同的雜湊值本身並不能證明動畫已正確渲染;請並排檢查具代表性的幀。

獲取免費臨時許可證

您可以申請免費 30 天的臨時許可證來使用 Aspose.3D for Python via .NET 渲染 GLB 和 GLTF 動畫幀,且不受評估限制。要在您的 Python 應用程式中套用許可證,請參閱 Aspose.3D 授權指南。

免費學習資源

探索以下資源,以深入了解使用 Aspose.3D for Python via .NET 加載動畫 3D 模型、處理動畫剪輯以及渲染 3D 場景:

結論

您可以透過取樣動畫時間軸並在每個選取的時間戳記渲染場景來產生幀圖像。使用編號的 PNG 來建立縮圖、比較姿勢,或為其他工具準備圖像序列。如果您需要數值動畫資料而非圖像,請參閱關鍵影格評估教學。若有渲染問題,請造訪Aspose.3D support forum。