using UnityEngine;
using System.Collections;
/// <summary>
/// UnityRecorderTurntable
///
/// 功能說明:
/// 配合 Unity Recorder 截圖工具,讓指定物件像「轉盤」一樣,每一幀旋轉固定角度,方便輸出 360 度物件旋轉連續圖片。
/// 1. 輸出商品 360 度旋轉圖
/// 2. 輸出角色或模型的環繞展示圖
/// 3. 製作 36 張、72 張等固定角度的圖片序列
/// 4. 搭配 Unity Recorder 輸出 PNG Sequence
///
/// 使用說明:
/// 1. 將此腳本檔案命名為:UnityRecorderTurntable.cs
/// 2. 將腳本掛在要旋轉的物件上,也可以建立一個空物件作為旋轉中心,再把模型放到空物件底下,然後把腳本掛在空物件。
/// 3. 在 Inspector 中設定:
/// - Total Images:總共要輸出的圖片張數,例如 36。
/// - Start Y:第一張圖片的 Y 軸角度,例如 180。
/// - Turn Direction:旋轉方向,-1 代表反向,1 代表正向。
/// - Wait Frames:開始旋轉前等待幾個 Frame,讓 Unity Recorder 進入錄製狀態。
/// 4. 建議 Unity Recorder 設定為輸出 Image Sequence,例如 PNG。
/// 5. 建議 Recorder 的錄製幀數與 Total Images 對應,避免錄到多餘畫面。
///
/// 注意事項:
/// 1. Total Images 不可以小於或等於 0。
/// 2. Turn Direction 如果設定為 0,物件將不會旋轉。
/// 3. 本腳本只負責旋轉物件,不會自動啟動或停止 Unity Recorder。
/// 4. 如果第一張角度沒有對準,可以調整 Wait Frames。
/// </summary>
public class UnityRecorderTurntable : MonoBehaviour
{
[Header("1. 旋轉規格")]
[Tooltip("總共要輸出的圖片張數。例如 36 代表每 10 度輸出一張。")]
public int totalImages = 36;
[Tooltip("第一張圖片的 Y 軸起始角度。例如 180 代表從 Y 軸 180 度開始拍攝。")]
public float startY = 180f;
[Tooltip("旋轉方向。-1 代表反向旋轉,1 代表正向旋轉。請避免設定為 0。")]
[Range(-1, 1)]
public int turnDirection = -1;
[Header("2. 同步校準")]
[Tooltip("開始旋轉前等待幾個 Frame,讓 Unity Recorder 先進入錄製狀態。若第一張沒有對準,可嘗試調整此數值。")]
public int waitFrames = 2;
[Header("3. 錄製設定")]
[Tooltip("鎖定 Unity 的擷取幀率。搭配 Unity Recorder 輸出圖片序列時,可以讓每一幀穩定對應一張圖片。")]
public int captureFramerate = 30;
// 每一張圖片之間要旋轉的角度。
// 例如 totalImages = 36,則每張間隔為 360 / 36 = 10 度。
private float _stepSize;
void Start()
{
// 檢查圖片數量是否正確。
// 如果 totalImages 小於或等於 0,會造成 360 / totalImages 的除法錯誤。
if (totalImages <= 0)
{
Debug.LogError("<color=red>【錯誤】Total Images 必須大於 0。</color>");
return;
}
// 檢查旋轉方向。
// turnDirection 為 0 時,雖然不會報錯,但物件會完全不旋轉。
if (turnDirection == 0)
{
Debug.LogWarning("<color=orange>【警告】Turn Direction 目前是 0,物件將不會旋轉。</color>");
}
// 計算每一張圖片之間的旋轉角度。
_stepSize = 360f / totalImages;
// 設定物件的起始角度。
// 第一張圖片理論上會使用這個角度。
transform.eulerAngles = new Vector3(0f, startY, 0f);
// 鎖定 Unity 的擷取幀率。
// 這對 Unity Recorder 輸出圖片序列很重要,
// 可以讓每一個 yield return null 對應到穩定的一幀。
Time.captureFramerate = captureFramerate;
// 啟動逐幀旋轉流程。
StartCoroutine(RecordSequence());
Debug.Log(
$"<color=cyan>【初始化】Total Images: {totalImages}, Start Y: {startY}, " +
$"Turn Direction: {turnDirection}, Wait Frames: {waitFrames}, Step: {_stepSize}</color>"
);
}
/// <summary>
/// 逐幀旋轉流程。
///
/// 流程說明:
/// 1. 先等待 waitFrames,讓 Unity Recorder 進入錄製狀態。
/// 2. 保持起始角度一幀,讓 Recorder 拍下第一張。
/// 3. 從第 2 張開始,每一幀旋轉一次。
/// 4. 直到完成 totalImages 張角度。
/// </summary>
IEnumerator RecordSequence()
{
// A. 熱身階段:
// 等待 Unity Recorder 或截圖系統準備好。
// 如果第一張圖片不是你想要的角度,可以調整 waitFrames。
for (int i = 0; i < waitFrames; i++)
{
yield return null;
}
// B. 捕捉第一張:
// 此時物件仍維持在 startY 角度。
// yield return null 代表等待一幀,
// 讓 Recorder 有機會拍下目前這個起始角度。
yield return null;
Debug.Log("<color=green>【第一張已拍完,開始旋轉】</color>");
// C. 旋轉階段:
// 從 i = 1 開始,因為 i = 0 已經是第一張起始角度。
for (int i = 1; i < totalImages; i++)
{
// 計算目前這一張的目標 Y 軸角度。
// 例如:
// totalImages = 36
// _stepSize = 10
// startY = 180
// turnDirection = -1
// i = 1 時,targetY = 170
// i = 2 時,targetY = 160
float targetY = startY + (i * _stepSize * turnDirection);
// 直接設定物件角度。
// 這種方式比使用 Time.deltaTime 旋轉更適合逐幀輸出圖片,
// 因為每一張圖片的角度都是固定且可預測的。
transform.eulerAngles = new Vector3(0f, targetY, 0f);
// 等待一幀,讓 Recorder 拍下這個角度。
yield return null;
}
Debug.Log("<color=yellow>【完成】Turntable 圖片序列旋轉流程已結束。</color>");
// 注意:
// 本腳本不會自動停止 Unity Recorder,也不會自動停止 Play Mode。
// 建議在 Unity Recorder 中設定固定錄製幀數,
// 或在需要時自行加入停止 Play Mode 的程式。
}
}