回顧昨天的過場動畫工作
我們正在制作一個游戲,目標是通過直播的方式完成整個游戲的開發。在昨天的工作中,我享受了制作過場動畫的過程,所以今天我決定繼續制作多個層次的過場動畫。
昨天我們已經開始了多層次過場動畫的基本制作,并且成功地做出了一個初步版本。這個版本看起來相當不錯,已經具備了一些深度效果,整體效果令人滿意。當然,仍然有一些細節可以進一步調整,使它看起來更加完美。
接下來,我的目標是繼續制作剩下的所有過場動畫,并確保它們的工作方式與目前已經完成的部分一致。這樣,我們就能將每個部分組裝成完整的過場動畫。每個部分都做好之后,接下來可以集中精力讓整體更加連貫和易于使用,甚至今天可能也會做一些這樣的調整。
總之,今天的工作主要是繼續制作和調整過場動畫的各個層次,確保它們都能順利運行,并準備好將它們整合成完整的過場動畫。
game_cutscene.cpp:引入 struct layered_scene 來保存所有的過場動畫數據
目前的工作內容主要是在設計和實現過場動畫的結構。現在的結構非常通用,實際上并沒有做任何特殊的處理,僅僅是把必要的過場動畫信息進行了整理。例如,主要的內容包括層數以及每一層的操作方式。我們可以像這樣簡單地定義一個“層數”變量,表示一共有多少層,比如“層數為8”,然后再在每個具體層中定義相應的操作。
這段代碼基本上已經包含了所需的所有數據結構,也就是過場動畫的全部信息。如果我們想要的話,可以將這部分內容獨立出來,實際上并沒有什么理由不這么做。例如,可以將這部分稱為“過場動畫”或者“分層過場動畫”。我們可以在這個結構中包含每個層的信息,如層數、鏡頭索引等數據。還可以通過查看文件格式和資產類型來進一步優化,比如為每個資產指定一個類型ID。
為了更清晰地組織這些數據,我們可以為每一層指定一個指針,指向包含所有信息的“層放置”數組。這樣,我們就能有一個非常基礎的過場動畫結構。雖然有些部分可能需要擴展,但對于目前的需求,這已經基本足夠了。
另外,我們還可以考慮增加一些其他字段,例如過場動畫的持續時間。可以簡單地為每個過場動畫設置一個持續時間字段,暫時將其設置為一個默認值(例如0到5秒之間),并在后續的調整中進行更改。這樣,我們就能進一步完善過場動畫的時長設置。
game_cutscene.cpp:引入 RenderLayeredScene
現在如果我們想把這個系統轉換成真正可用的形式,也就是說實現對某個具體場景的渲染,我們可以定義一個函數,比如 RenderLayeredScene
,它接收我們定義好的某個分層場景作為輸入。
只需要傳入當前的分層場景對象,再傳入一個歸一化的時間值(T 值),這個時間值表示當前動畫進度的位置,有點類似從 0 到 1 的比例。這些信息其實已經足夠進行渲染。
當然,還有一些額外的數據也可以一并傳入,比如攝像機的起始位置和結束位置,這些都能影響畫面顯示效果。所以我們會把相關的 CameraStart
和 CameraEnd
變量也一并抽出來,用來提供視角的過渡控制。
我們從現有代碼中把這些相關邏輯提取出來,封裝成一個通用函數,這樣每次需要渲染一個分層場景時,就只需要調用這個函數并傳入所需的參數。接著,在調用位置,比如某一幀畫面中,我們只需要調用 RenderLayeredScene
,并傳入當前所需的數據就可以完成渲染。
這個函數需要的參數包括:資源信息、渲染組、當前幀的歸一化時間等。原來用于處理 cutscene 的 T 值邏輯現在就可以直接拿來作為這個歸一化時間值的來源了。
這樣一來,整個 cutscene 系統就實現了高度通用性與模塊化,任何一個場景的渲染,只需要用標準結構傳入數據即可完成繪制,大大提高了代碼的復用性和維護性。
game_cutscene.cpp:定義 layered_scene
我們現在所需要做的,就是正式定義一個分層場景。之前寫的這部分內容,正是用于定義這個分層場景的數據。我們可以直接把這段定義提取出來,單獨放到一個結構體中。之后,我們就能直接在程序中使用這個定義好的場景進行渲染。
我們將所有相關的信息封裝到這個結構體里,包括層數(layer count)是 8、鏡頭編號(shot index)是 1、資源類型(asset type)對應的是開場動畫。剩下的就是填充圖層定位(layer placement)數據,這些數據也已經準備好了,只需要設定一個指針指向這部分信息。
定義好場景之后,就可以在需要渲染的地方傳入這個場景結構體。接下來還需要補充兩個攝像機參數,分別是 CameraStart
和 CameraEnd
,這樣就能在場景切換中進行視角控制了。
將這兩個變量也加入定義中,然后設定對應的值,使得這個場景在播放時能完整運行。這樣,一個完整的分層動畫場景結構就構建完成,可以作為系統中任意 cutscene 的模板,后續其他鏡頭也能以此為基礎進行搭建與替換。
整體思路是把每個鏡頭都變得模塊化、數據驅動,使得系統對 cutscene 的加載和播放更加通用、高效、靈活。
解決問題并從中概括,即面向壓縮的編程
我們一貫采用的編程方式非常直接明確。只要已經清楚接下來要完成的核心任務是什么,就會直接動手去寫實現代碼,這正是之前所做的。首先專注于完成具體功能,等完成后再回過頭來,把那些可以重復使用的部分抽離出來,整理成更通用的結構。
這種方式避免了大量前期冗余的設計討論,也不需要來回斟酌那些在實際問題中根本不重要的細節。只需先解決實際問題,然后再從已完成的解決方案中提煉出通用模式。與其一開始就進行過度設計,不如從具體做起,然后自然演化出更好的架構。
這個方法最適用于我們清楚如何完成某個具體目標的場景。例如,如果已經知道如何編寫一個完整的過場動畫流程,那就直接把這個過場動畫編碼出來。編碼完成后,所需的通用機制自然就會浮現出來,比如分層場景、鏡頭參數、動畫持續時間等。
如果一開始就不知道如何做某件事情,那確實不能采用這種方式。但當我們已經掌握其中一個案例的實現方法,就可以通過這個案例的構建過程,把其他共性部分提取出來,從而構建整個系統的通用結構。這種方式始終是最輕松、最高效的設計方法。
game_cutscene.cpp:清理一些東西
現在已經完成了分層場景的基本結構設計,接下來就是將其整合到現有的渲染邏輯中。我們所需的內容幾乎保持不變,比如傳入的歸一化時間參數仍然照舊,只是現在像鏡頭索引、圖層數量和資源類型這些信息,全部從分層場景結構中提取出來,而不是單獨管理。
對于資源類型 ID,也直接從場景結構中讀取,這樣就實現了邏輯的集中和簡化。通過這種方式,每個場景變得更加獨立和自包含,使得渲染函數只需要接收一個完整的分層場景結構,而不再需要依賴外部零散的參數配置。
剩下需要處理的一些小問題,比如單位轉換相關的 meters 到 pixels 的操作,還有一些代碼細節需要清理。這些目前雖然還不是最理想的狀態,但已經能正常工作,只是后續可能需要讓這部分邏輯更加清晰和一致。
此外,注意到變量類型有些地方原來用的是 signed 類型,而實際上這里更適合用 uint32
這樣的無符號整數,這樣可以避免不必要的類型問題或隱式轉換引起的錯誤。
最后,圖層位置數組的引用方式也需要調整,現在應該從場景結構中讀取,而不是直接訪問之前的局部變量。整理完這些內容之后,基本上就完成了一個可復用的、結構清晰的分層場景渲染系統。
game_cutscene.cpp:引入 scene_layer 和 scene_layer_flags
現在開始處理“距地距離”(distance above ground)的問題,這部分稍微有點棘手。因為在某些圖層中,例如角色固定不動、或具有特殊顯示位置的圖層,目前系統里并沒有一個明確的方法來表達這些“特別”的層。我們之前的方式是簡單地將其遠遠地移動到背景中去,但這種方式不夠明確和靈活。
為了解決這個問題,我們決定為每一層引入更強的表達能力,即每層擁有獨立的參數設置。具體來說,我們把之前混合在一起的隱式數據結構,改成顯式的數據字段。例如:
- 明確設置圖層的位置
p
; - 明確設置圖層的高度
height
; - 為圖層增加一個“標志位”(flags)機制,讓我們能夠在每層上添加類似“處于無限遠”(at infinity)這樣的標記。
于是我們定義了 SceneLayerFlags
,并在里面加上了一個 SCENE_LAYER_FLAG_AT_INFINITY
這個標記。這個標記的意義在于:如果某一層被標記為 at infinity
,那么它的 Z 值不再是一個固定值,而是動態地加上 distance_above_ground
,使其始終處于地面之上的某個相對高度。這樣我們就可以給它設置一個例如 -200 的基礎值,然后用 distance_above_ground
動態疊加,使其看起來始終處于“背景”或者“空中”的效果。
為了實現這個邏輯,我們將原先叫做 layer_placement
的數據結構重命名為更通用的 scene_layers
,因為它現在不再只是描述“放置”,而是包含了更多的狀態信息,如位置、標志等。每一個圖層的數據現在會獨立處理,并從結構中讀取出對應的字段:
layer.p
:圖層的位置;layer.flags
:圖層的標志位;layer.height
:圖層高度(如果有需要可以使用);
我們還使用了宏(macro)來輔助處理標志位的讀取,使代碼更簡潔,雖然這在功能上并不是必須的,只是覺得這樣更方便。
這樣一來,我們的系統就具備了更強的可擴展性和表達能力,可以根據圖層的具體需求設置不同的行為,比如:
- 設置某些圖層始終相對地面浮動;
- 將某些圖層標記為特殊狀態,便于后續邏輯處理;
- 更容易管理不同層之間的顯示深度和邏輯區分。
目前結構已經基本清晰,接下來可以在渲染時直接根據這些參數進行調整,確保每個圖層根據自己的設定被正確渲染。這樣就為后續復雜場景的構建和動畫控制打下了堅實的基礎。
運行游戲并查看我們的場景
現在我們已經完成了基礎構建,接下來要做的就是驗證場景能否正常恢復顯示。最終場景如預期一樣渲染出來了,所有內容看起來都和之前一樣,這正是我們想要的效果。
這意味著現有的結構和功能已經成功實現了可復用的“圖層化場景”渲染邏輯。接下來就可以繼續開展后續工作了。
我們現在可以開始制作其他的場景了。只需要調用剛才完成的渲染函數,并傳入新的圖層場景數據即可渲染一個新的分鏡(cutscene)。這整個過程的重點是:
- 代碼的可復用性已經達成:無需再次編寫一遍渲染邏輯,只需要提供新的數據;
- 邏輯的通用性已經驗證:不論是哪個場景,結構一致的數據都可以通過同一個流程渲染出來;
- 節省了大量重復工作:所有之前寫好的邏輯現在都能被重復使用,極大提升了開發效率。
接下來我們要做的,就是繼續定義其他新的圖層化場景,把它們像之前一樣組織好,然后一一調用同樣的接口進行渲染。這將讓整個劇情系統的分鏡管理變得更清晰、更高效,也更易于后續維護和擴展。
game_cutscene.h:將結構體從 game_cutscene.cpp 移到這里
現在我們要開始構建下一個分鏡場景,方法會和之前完全一樣。我們會按照相同的步驟來搭建。首先我們在代碼結構中,準備好一個新的位置來存放場景定義。
接著我們注意到項目中其實已經存在一個名為 game_cutscenes.h
的頭文件,雖然之前沒有特別注意到它的存在,但既然已經有了這樣一個文件,我們就決定把新的場景定義放到這里去。
這個文件可以很好地作為統一管理所有分鏡場景的地方,將不同的場景注冊和組織起來。這樣每次新增一個分鏡,都可以清晰地放在統一的結構里,后續查閱和修改也會更加方便。
最后,我們創建了一個新的場景,并將其放入結構中。整個過程令人滿意,現在又多了一個明確的、可組織的新場景定義點。
我們正式完成了下一步的準備工作,場景定義文件也變得更加健全,后續只需要繼續添加新的分鏡內容即可。整個系統正逐步走向更加模塊化和規范化的方向。
game_cutscene.cpp:設置以合成更多的鏡頭
現在我們切換到了全屏模式,能夠完整地查看分鏡畫面,并開始像之前一樣進行分鏡的編輯。我們進入了 RenderCutscene
的流程中,接下來的目標是定義一個新的分鏡場景。
整個過程很基礎,沒有復雜的內容。我們復制了之前已有的一段分鏡代碼,作為新的模板,并開始構建一個新的分鏡,當前這個新分鏡被命名為 “Shot 2”。
我們首先進行了基礎的設置,比如用條件判斷語句把不同的鏡頭分開處理,避免變量或設置之間的沖突。雖然目前顯示的還是第一個分鏡的內容,但結構已經準備好,隨時可以替換。
然后我們檢查了是否存在標記為“無限遠”的圖層(此前用于背景固定層的特殊標記),發現當前這個分鏡并沒有這樣的需求,所有圖層都會隨場景一起移動。因此我們移除了所有與“無限遠”相關的設置。
我們暫時還沒有確定這個分鏡中相機的具體運動方式,所以相機移動部分被注釋掉或暫時保留為空。這意味著當前相機在場景中是靜止的,僅顯示分鏡圖層的內容,方便我們逐一查看每個圖層的效果。
接下來我們會繼續調整各個圖層的位置、內容,以及確定相機的運動路徑,從而完成這個新的分鏡場景的搭建。整個流程沿用了前一個分鏡的結構和方法,保持了代碼的可復用性和一致性。
game_cutscene.cpp:編碼 CameraStart 和 CameraEnd 中的 Z 軸運動
我們決定對當前場景的Z軸處理方式進行一次改進。之前我們在渲染過程中把 distance_above_ground
(離地距離)直接硬編碼加到了 pz
值上,比如加了一個 10 - 5.5
這樣的偏移。但現在回頭來看,這樣做其實并不理想。
原因在于,我們希望Z軸的變化成為相機運動的一部分,而不是靜態地被加到某個變量里。硬編碼的Z偏移會限制我們對相機的控制,使得相機的運動不夠靈活且不透明。因此我們做了如下調整:
我們將原本硬編碼的Z軸偏移移除,改為讓相機在 camera_start
到 camera_end
中的Z值承擔這一變化。比如我們希望相機從高度10向下移動到高度5,那么就將相機的Z軸從 0.0
移動到 -5.0
。這樣就可以:
- 把Z軸運動完整地納入相機軌跡中,增強了動畫可控性;
- 不再需要額外處理
distance_above_ground
的加法邏輯; - 避免層疊數據結構之間的耦合,使得相機行為更直觀。
同時我們考慮了一個更簡潔的方案:如果不再手動編碼 distance_above_ground
,那么我們可以直接將它設為0,因為它的意義已經由相機的Z偏移代替了。也就是說,現在這個變量成了一個“純形式值”,在渲染邏輯中不會再被直接引用或參與計算。
最終效果是:
- 所有與相機有關的高度變化現在都歸納進
camera_start
和camera_end
的z
分量; - 圖層的渲染位置則獨立處理,不再混合進相機控制邏輯;
- 渲染系統也變得更干凈、分工更明確;
我們恢復到了之前的渲染狀態,同時為今后每一個分鏡的相機運動留下了更大的自由度和表達能力。每一段Cutscene都可以通過這兩個變量來自由控制前后幀之間的鏡頭移動——這是我們更理想、更合理的做法。
game_cutscene.cpp:合成鏡頭 2
我們現在回到第二個鏡頭的制作,開始對其進行具體的圖層與相機運動調整。
首先我們注意到第一個圖層是靜止的,這很正常,因為當前相機還沒有任何移動。這個鏡頭計劃是一個緩慢的推進鏡頭(slow zoom),所以我們預設相機的Z軸從0
推進到-5
,形成一個比較輕微的推進感。如果感覺推進不夠明顯,也可以進一步加深推進程度,這取決于圖層之間的相對距離。
圖層的空間擺放也進行了初步的設定。第一個圖層,我們計劃將其放在相機前方大約-20米
的位置,并設置較小的縮放比例。因為這個鏡頭是一個近景鏡頭,圖層不多,整體畫面也比較緊湊,推進的效果會更加顯著。為了控制推進的節奏,我們決定將相機的移動距離設為0.5米,模擬一個非常微妙的拉近。
時間上的控制暫時沒有加入,我們計劃在后續調整鏡頭節奏時一并處理。
接下來,我們添加了第二個圖層,它需要位于孩子的前方。初始擺放完成后,進一步微調了位置,使之與整體構圖更協調。隨后檢查是否還有其他圖層,確認還有一層是冰柱(icicles)。
冰柱圖層被放置在畫面頂部,并設定為離相機更近的位置,例如-8米
,以便在推進鏡頭時呈現更強的視差效果(parallax)。這個圖層也上移了一些,以確保它在正確的屏幕位置,增強畫面層次。
檢查后確認該鏡頭僅由三個圖層構成:
- 背景層(遠處)
- 中景層(孩子)
- 近景層(冰柱)
我們接下來開始微調視差效果。觀察中景層的窗戶部分后,決定將其進一步靠近,以增加透視感和空間感。同樣也微調了孩子圖層的位置,讓他更居中地位于窗戶中間,同時略微下調其Y軸,使其構圖更自然。
調整完所有圖層的空間位置后,我們回到相機設置,再次確保相機推進的終點對準孩子的位置,形成一個具有明確視覺焦點的推進鏡頭。
最終這一組調整達到了我們預期的效果:
- 鏡頭推進自然;
- 圖層間深度關系合理;
- 透視與視差增強了空間感;
- 畫面焦點清晰,對準孩子;
- 各圖層構圖協調。
這一版的鏡頭感覺良好,基本達到了視覺與運動的雙重目標。
(近 → 遠) :
- Icicles(前景,最靠近相機,用于增強空間感和運動感)
- Wall and window(中景或前中景,構圖元素)
- Hero and tree(中景或背景主角圖層,是視覺焦點)
缺少雪花…α
目前我們已經完成了一個剪輯,整體看起來效果不錯。這個剪輯場景中只包含了三個圖層,分別是:
- 主角和樹:這個圖層展示的是角色本身以及身邊的一棵樹,我們將這個角色稱為“主角”。
- 墻與窗:第二個圖層中包含了一面墻和一個窗戶,形成了房屋外部的背景元素。
- 冰柱:第三個圖層是一些冰柱(比如從屋檐垂下來的冰錐),被放置在畫面的最前景,以增強縱深感和畫面的層次。
原本計劃中還打算加入一些飄落的雪花,用來進一步豐富場景的動態效果,但我們意識到很可能在資源包中忘記包含雪花圖像,這是一個疏漏,后續可能會單獨補充雪花相關的素材。
不過目前這些靜態圖層的組合已經滿足該場景的需求。剪輯整體結構和過渡都達到了預期,特別是鏡頭緩慢推進到主角身上的動態設計也已經調整得比較滿意。冰柱等元素的位置也經過微調,以增強前景的視覺運動感,畫面層次感更清晰。
總的來說,這個剪輯就是圍繞“主角與樹”“墻與窗”和“冰柱”這三類圖層構建的,整體感覺已經相當不錯。接下來我們將繼續制作下一個剪輯。
game_cutscene.cpp:合成鏡頭 3
我們現在開始制作第三個剪輯,在索引中新增一個場景,重新開始配置。這一幕的背景是室外場景。
這個剪輯相對有趣,但也存在一定挑戰。在設想這個鏡頭時,我們并不確定所采用的透視是否能奏效。這個場景的鏡頭運動方式不是垂直方向,而是橫向移動,這是比較少見的一種處理方式。我們有一段是垂直移動的,還有這一段是水平橫移的。這種處理方式在這種剪輯技術中相對少見,所以我們也不確定是否能很好實現。但如果最后發現無法達到預期效果,那也沒關系,藝術制作中本來就經常要進行反復調整和修改。
我們開始搭建這個剪輯,首先加載天空圖層。天空圖層在理論上是應該靜止的,因為它是實際的天空背景,不應該隨著鏡頭運動。但由于這段鏡頭模擬的是一個“俯視下來的移動鏡頭”(Over-the-top camera move),所以也可能需要讓天空稍微移動來配合這種透視效果,因此我們暫時保留它是否靜止的判斷,等后續調整再看。
接下來我們加載第二層,也就是森林背景。這是位于中景的戶外環境。這時我們發現這類運動可能需要一種“反向運動”機制——也就是說,為了模擬攝像機“俯視移動”的感覺,部分圖層可能要進行反方向的視覺移動來制造真實感。所以我們考慮引入一個新機制,比如設定一個“反向移動標志”,讓某些圖層在剪輯中反向運動,以達到正確的視覺模擬效果。
我們繼續添加更多圖層。當前我們已經加載了一個新圖層,這是我們要模擬的“頂部視角”的一部分。這個視角的設想是——攝像機從上方向下拍攝,然后緩緩移動,使觀眾有一種鏡頭越過人物頭頂的感覺。
現在我們把主角(孩子)的圖層也加入進來。這個角色圖層我們希望它隨著攝像機運動一起移動,而背景圖層可能不動或反向移動,形成視覺上的“鏡頭繞著角色移動”的效果。這意味著角色圖層應該與攝像機保持一致的運動,而背景圖層要模擬出相對運動差。
這個設計思路要求我們后續仔細調試每一層的運動方式,尤其是鏡頭運動過程中,不同圖層產生的視差與節奏必須協調,才能形成理想的透視與動感。整個場景的邏輯是構建一個俯視鏡頭從背景穿越至主角上方,通過合理的圖層組合與運動設計,實現動態的過渡效果。我們將在繼續調整位置和動畫方式的基礎上,進一步測試視覺結果是否符合預期。
game_cutscene.h:將 CounterCameraX 和 CounterCameraY 添加到 scene_layer_flags
我們繼續添加功能,在這里我們引入了一個新的標志變量,用來實現“反向相機運動”。我們先切換回常規視圖,然后開始添加這個新標志。這個標志可以命名為 counter_y
或更明確的 counter_camera
,具體來說我們最終定義為 counter_camera_x
和 counter_camera_y
等。
這個機制的作用是在某些圖層中啟用相機運動的反向偏移,即當相機向一個方向移動時,這些特定圖層會以相反的方向做相應的位移,從而在視覺上看起來像是保持了相對位置不變。這種效果在模擬“鏡頭繞物體運動”時非常重要,尤其是在構建俯視鏡頭(top-down shot)或水平掃動鏡頭時格外有用。
在具體實現中,我們修改了之前統一使用的相機偏移方式。原來我們是通過一個整體的 camera_offset
直接影響位置計算的,現在我們將其拆分為 px
和 py
兩個維度分別處理:
- 對于
px
,我們先減去camera_offset.x
,但根據是否設置了counter_camera_x
,決定是減去還是加上這個偏移值。 - 對于
py
,同樣判斷是否設置了counter_camera_y
,來選擇加減偏移量。
這種方式允許我們對每個圖層單獨控制它是否要應用反向相機運動,而不是所有圖層一視同仁。這樣一來,我們就能很靈活地決定哪些圖層應該隨著鏡頭運動而移動,哪些圖層應該產生相對靜止或反向漂移的效果,從而更精確地模擬真實鏡頭中的透視、空間感與層次深度。
總結:
- 添加了一個新機制
counter_camera_x/y
來支持圖層根據需求執行反向相機運動; - 將位置偏移計算拆分為
x
和y
兩個方向進行; - 每個方向都支持獨立控制是否進行反向偏移;
- 為接下來的復雜鏡頭設計打下基礎,尤其適合處理非線性運動、模擬旋轉或環繞等鏡頭。
game_cutscene.cpp:處理 Z 情況
我們意識到之前的代碼邏輯中忽略了對 Z 軸(深度)方向 的處理,這是一處遺漏。在進行相機偏移的處理時,只考慮了 X 和 Y 方向的位置偏移,忘記對 Z 方向進行處理。
Z 軸的處理非常重要,特別是在模擬景深、遠近視差(Parallax)或推進鏡頭等情況下,Z 方向的位移直接影響圖層在空間上的表現。
于是我們補上了 Z 軸的偏移處理邏輯,即:
RenderGroup->Transform.OffsetP.z = pz - camera_offset.z
這段代碼的意思是將圖層在 Z 方向上的位置也根據相機的 Z 偏移進行相應調整,從而保持統一的相對空間位置。因為當相機在 Z 方向上有運動時,如果不對圖層的 Z 值做補償,畫面中就會出現錯位或不一致的視覺效果。
現在 X、Y、Z 三個方向的偏移都已經正確處理,場景中所有圖層在相機移動時應該能夠保持準確的空間關系,視差效果和鏡頭運動也能按照預期表現。這是構建多圖層鏡頭運動系統中非常關鍵的一步。
game_cutscene.cpp:繼續合成鏡頭 3
我們正在調整一組鏡頭,實現的是一個具有縱深感和前后視差效果的場景過渡,試圖讓背景圖層與相機運動形成反向關系,從而制造出空間感和動態效果。
首先,我們設置背景圖層與相機形成「反向運動」,也就是相機往一個方向移動時,背景圖層以相反方向位移。我們不確定這樣設置是否會完全起作用,但打算嘗試一下看看效果。
接著我們開始微調角色初始位置,讓角色一開始處在畫面較低的位置,并在鏡頭移動過程中逐漸脫離畫面,以此營造出鏡頭拉遠的感覺。同時我們也延長了鏡頭時長,原本是5秒,現在改為10秒甚至20秒,以便讓整個動作更自然、更緩慢,尤其是與后續配音匹配時能留出更多節奏空間。
為了適配鏡頭的拉遠效果,我們調整了背景尺寸,使其大幅擴大,能夠覆蓋整個窗口,避免在鏡頭移動過程中看到邊緣。我們還調整了圖層的深度順序和縮放比例,比如讓某些遠景圖層處于“無限遠”,保證它們不會因為相機前進而發生明顯偏移,從而維持遠景穩定。
隨后我們對畫面進行逐步測試和觀察,發現角色的運動速度過快,無法表現出“拉近”效果中應該有的那種頭部逐漸變大的視覺印象。于是我們給相機加上了一點Z軸(向前)的運動,營造出景別變化的感覺,這樣畫面看起來更有動感,也更接近我們想要的效果。
我們也嘗試通過移動其他圖層位置來配合整體的透視變化,使“男孩頭部變大”的效果更加明顯。為此還對遠景背景位置進行后移,使其更加符合透視關系。由于這個鏡頭不是簡單的網絡插值,而是帶有透視投影效果,所以我們必須精細控制每個圖層的位置和比例。
最終,通過不斷試驗,我們找到了合適的鏡頭運動節奏、背景比例、角色位置和景深配置,達到了較為理想的畫面效果。雖然這個鏡頭仍然有一定難度和不確定性,但整體上已呈現出預期的空間感和動勢,為后續的過渡鏡頭和敘事鋪墊打下基礎。
game_cutscene.cpp:合成鏡頭 4
接下來,我們開始著手處理下一個鏡頭。首先清理了一些標記和設置,讓場景回到一個更合理的狀態。接著,檢查了鏡頭設置,準備進行一個緩慢的縮放。這個鏡頭沒有特殊的相機動作,只是一個簡單的鏡頭縮放,看起來就像是逐漸拉近的效果。
為了調整這個縮放效果,決定讓鏡頭略微靠近一點,并且調整鏡頭的運動速度,確保場景過渡的流暢性。完成這些調整后,繼續添加新的圖層,確保每個圖層都設置正確。
接下來,發現場景中有一個小小的動畫效果,決定在系統中添加一個新功能來支持這個動畫。這個動畫的效果比較輕微,但仍然需要系統支持才能完成。為了調整這個動畫,需要做一些新的功能擴展,但這不會太復雜。
在此過程中,還注意到場景中的人物數量不太對,原本以為會有更多的小孩出現在畫面中,但目前只看到一個小女孩在前景中。這可能是資源包中出現了問題,導致人物缺失,需要稍后檢查和更新資源包。
此外,還注意到場景中有一些閃亮的裝飾物(例如亮片),這些也需要確保正確顯示。
最終,確認了這個鏡頭的設置,并且完成了對動畫的處理,保證了整個場景的效果能夠如預期般運行。這一切都做好后,準備繼續進行后續調整和測試,確保每個鏡頭都能夠順利呈現。
反正就是挨著調鏡頭
缺少孩子β
首先,對于場景中的一些問題,決定暫時假設它們是正確的。雖然有感覺應該有更多的小孩出現在畫面中,但目前沒有找到他們的蹤影,可能是資源導出時出現了問題。對不起,小孩們,似乎有些小孩丟失了,但其他部分基本上看起來是對的。
接下來,重點是調整場景中的一些元素,特別是裝飾品(如亮片)。亮片的尺寸需要調整,變得更合適一些,應該離攝像機更近一些。調整后,亮片應該不會顯得那么搶眼,避免遮擋其他重要元素,應該調整為一個更加合適的比例。
此外,孩子和圣誕老人應該稍微向下調整位置,看起來應該像是稍微低一些的樣子。調整這些元素的位置,使得整體效果更加自然。
最后,回顧了一下文件的導出,發現確實有一些小孩缺失,計劃稍后重新導出并更新資源包。因為這些小孩應該位于畫面的角落,但目前找不到他們的位置,可能是在保存文件時丟失了。
討論錯位的孩子γ
在處理場景中的一些元素時,發現自己可能錯位了很多孩子角色。這并非有意為之,完全是個失誤。始終嘗試盡量保證所有的角色都在場景中,但偶爾一些角色會因為太煩人而決定“失蹤”,這時就不小心把他們錯放了。其實在游戲中也鼓勵這種做法——有時實在是讓角色消失更為方便,尤其是當他們真的非常擋路時。
接下來,調整了一些角色的位置,特別是一個小女孩的位置。原先的位置稍微遮擋了另外一個小女孩,所以需要稍微縮小她的大小,讓她低一些,這樣看起來更加合適。調整后,感覺效果不錯,看起來就對了。
接著,又調整了圣誕老人和孩子的位置,原先他們的相對位置有點不對,圣誕老人似乎壓住了地面的一些元素,所以稍微向一邊移了下,調整后看起來好多了。對于這些細微的調整,感覺每一處的改變都非常細小,但卻非常關鍵。每一個細微的調整,給場景帶來的效果可以是巨大的,所以這些小動作和細節處理都非常重要。
game_cutscene.h:將 MinTime 和 MaxTime 添加到 scene_layer,將 Transient 添加到 scene_layer_flags
為了讓這個余弦動畫按預期執行,我們需要確保兩個元素在不同時刻播放。可以通過一個簡單的方式來實現這一點,即添加一些“排除”機制。具體來說,我們可以設置一個時間范圍,定義某些場景層在特定的時間段內出現或消失。
實現的方式是設置一個類似“瞬態層”的標記,也就是一個僅在特定時間范圍內激活的層。這樣,我們就能夠在時間上控制某些層的顯示,確保它們不會同時存在于畫面中。
具體做法是,我們可以給這個瞬態層加一個標記,讓它只在指定的時間段內存在。通過這種方式,可以輕松地控制動畫中各個層的顯示時機,確保它們在正確的時刻開始和結束。
game_cutscene.cpp:設置 Transient 層
我們為了解決兩個圖層不能同時播放的問題,可以采用“瞬態層(transient layer)”的概念,將這兩個圖層都標記為瞬態層,然后通過設置它們的播放時間范圍,使它們分別出現在鏡頭的前半段和后半段。
實現上,我們可以添加一個參數,例如 thought_change_time
,設定為一個值,比如 10。這個值將作為時間分界點,控制兩個瞬態圖層的出現時機。例如,第一個圖層在前半段(時間小于 10)出現,第二個圖層在后半段(時間大于等于 10)出現。
接下來在渲染場景時,遍歷每一層時可以加一個 active
標志來判斷該層是否應該被渲染。默認情況下,active
是 true
,但如果當前圖層被標記為瞬態層,那么就需要判斷當前歸一化時間 t_normal
是否在其指定的時間范圍 [min_time, max_time)
之間。如果在這個范圍內,該層就被激活并參與渲染,否則就被跳過。
特別地,在判斷時間區間時,使用了“左閉右開”的區間判斷方式,即:
t_normal >= min_time
:表示當前時間已經到達或超過該層的起始時間。t_normal < max_time
:表示當前時間還沒有超過該層的結束時間。
這樣可以實現兩個圖層在某個關鍵時刻(比如 0.5)進行無縫切換,保證它們不會在同一個時間點重疊。這個時間判斷的精度設計是刻意的,確保不同圖層之間不會發生時間上的沖突,從而實現清晰準確的視覺切換效果。
觀看動畫版本
這是當前動畫版本的呈現效果,可以清楚地看到其中的動作變化,比如角色將帽子戴到另一個角色頭上的小動作。整個片段中,角色間的交互已經具備了一定的動態表現力。
在此基礎上,也可以考慮是否加入一些過渡效果,例如淡入淡出(fade)的方式,讓兩個圖層之間的切換更加平滑自然。這種做法的可行性需要根據整體畫面的風格判斷是否合適。如果畫面風格比較干凈利落,淡化切換可能會讓視覺語言顯得不夠利索;但如果想加入一些更具表現力或情緒性的元素,漸變過渡可能是一種值得嘗試的方式。
實現這種漸變的方式可以使用漸變函數(ramp)來控制兩個圖層之間的透明度權重。例如,從前一個圖層逐漸降低透明度,同時下一個圖層逐步增強透明度,這樣在一段時間內兩個圖層都會存在于畫面中,但視覺上只感受到一種柔和的過渡感。
雖然目前還未決定是否要使用這樣的漸變方式,但技術實現層面是可行的,關鍵是是否與整體視覺風格協調一致。現在的版本已經能夠展現基本動作邏輯,是否進一步美化轉場效果可以作為下一個優化方向來考慮。
game_cutscene.cpp:合成鏡頭 5
現在繼續處理鏡頭五的部分。在剩下的五分鐘內,計劃再推進一下整體進度。到目前為止,已經完成了大約一半的鏡頭,進度良好。
開始查看鏡頭五的內容。首先看到的是背景圖層的導入,屬于一個標準的背景畫面。觀察之后認為這個背景可以稍微往后拉一些,使得整個構圖更合理。
繼續查看接下來的圖層安排,初步判斷鏡頭五仍是一個結構比較常規的畫面,沒有特別復雜的動態或分層變化。畫面中各元素的排列方式和前面處理的鏡頭類似,繼續按部就班地進行就可以。
這一部分的關鍵在于確認背景位置和后續圖層的相對關系是否協調,確保畫面空間感與整體節奏的一致性。下一步將繼續處理鏡頭五中的具體圖層內容,并根據需要微調位置與層級。
最精彩的鏡頭δ
這是整個場景中非常重要的鏡頭——“關鍵鏡頭”,一切戲劇性的展開都從這里開始。在這一鏡頭中,我們首先設置了背景圖層,并將其拉得相對較遠,以此營造出一個緩慢移動的效果。同時為了保持視覺沖擊力,將其整體比例調大,使得它在構圖中更具存在感。
接著計劃為鏡頭添加一個更具戲劇性的相機移動,以提升整體的動態張力。然后開始處理畫面中的門的圖層,將它們添加進場景,并且要確保這些門能夠填滿整個畫面。這一部分的圖層也會使用 transient(臨時)標志,意味著它們會在畫面中短暫出現,然后被后續的圖層取代。
設定這些門的顯示時間為鏡頭切換時間點(shot change time),例如 1.0,確保門在特定時間點消失,讓下一個重要角色順利登場。
隨著門的爆開,格蘭帕斯(Krampus)終于登場——這個眾所周知的假日惡魔角色突然出現在孤兒院的大門口。為了讓他的出現更具沖擊力,將其圖層略微縮小,使其比例更合適,并調整其位置以獲得更理想的構圖。同時,他的圖層設置得比前景更接近鏡頭,使得他在視覺上更突出,并帶有明顯的動感。
另外還加入了雪的圖層,進一步增強了節日氛圍和畫面層次感。通過合理設置雪的顯示方式,使整個畫面更加生動豐富。整個鏡頭完成后,效果非常令人滿意,畫面節奏緊湊,角色登場充滿張力,是目前為止非常喜歡的一個鏡頭。
“格蘭帕斯(Krampus)”是歐洲民間傳說中的一個神秘角色,特別流行于奧地利、德國、匈牙利、捷克等地區的圣誕節文化中。他是一個反面節日角色,可以被理解為圣誕老人(Santa Claus)的“邪惡搭檔”。
簡單來說,Krampus 是誰?
- 外貌:通常被描繪成一個高大、全身長毛、有角、舌頭很長的惡魔形象,有時還拖著鐵鏈或手持柳條。
- 職責:他不像圣誕老人那樣獎勵乖孩子,而是懲罰不聽話的孩子。
- 故事背景:
- 圣尼古拉斯(Santa Claus)會獎勵乖孩子;
- Krampus 則會懲罰壞孩子,甚至把他們裝進麻袋里帶走。
Krampus 的“節日”
在一些地區,每年的 12 月 5 日 是“Krampus Night(克蘭帕斯之夜)”,年輕人會裝扮成 Krampus,在街上游行,制造氣氛,也是一種傳統慶典。
在創作/影視中
Krampus 經常被用作節日恐怖題材的角色,象征節日文化中的陰暗面。許多動畫、電影或游戲會以他為靈感,塑造出一種在喜慶氣氛下潛伏的“威脅”角色。
“這就是電子游戲”ε
我們完成了整個鏡頭的布置,整體效果非常不錯,令人滿意。這個鏡頭的構成和動畫都體現出一種非常典型的視頻游戲式風格,也確實是在做“電子游戲”的感覺。
我們已經把所有需要的元素都加入到了畫面中。為了讓鏡頭更有動感,我們打算對攝像機的移動軌跡做一些微調,加入一點向上的平移。這樣可以更好地呈現出角色格蘭帕斯的氣勢——因為他像是一個山羊形態的角色,所以鏡頭緩緩地向上移動,有種仰視的感覺,更具張力。這種鏡頭運動可以更好地引導觀眾的視線,把注意力集中到格蘭帕斯身上,氣氛會更有壓迫感。
我們還考慮了發音上的差異——如果按照中歐大陸風格的發音,他的名字可能更像是“克蘭帕斯”或“克拉姆普斯”(Krampus / Krampus),無論如何,這種差異在不同地區的表現中都是常見的現象,也增添了一點文化趣味。
這個鏡頭整體已經讓我們感到很滿意,最終的構圖和節奏也非常到位。接下來可能還會有人對這個部分提出一些問題,比如關于鏡頭語言、角色氛圍或動態表現的細節,但就目前來看,整體已經進入了一個比較穩定和完善的階段。
game_cutscene.cpp:合成鏡頭 6
我們繼續進行下一個鏡頭的制作,這是第六鏡頭。因為場景制作非常有趣,而且能看到它們實際出現在游戲中,非常有成就感,所以決定再做一個。
在這個鏡頭中,格蘭帕斯已經完全登場。按照設定,他自然是要開始追逐孩子們了,這是他的“職責”。他出現的目的就是專門對付那些淘氣的孩子,這正是他的“行事風格”,可以說是他存在的意義。
這次的鏡頭設置依然從兩層結構開始,并重新整理了圖層數量。我們估算了一下格蘭帕斯與前景的距離,大概是八米左右,于是將他放置在適當的位置,使他在畫面中的比例和位置更具視覺沖擊力。
對格蘭帕斯的位置進行了微調,使其更加居中并且具有威脅感,同時保持和前一個鏡頭的連貫性。從目前的效果來看,這個鏡頭的構圖已經相當不錯了,格蘭帕斯的存在感強烈,畫面張力十足。
整體氣氛符合預期的敘事發展節奏,也為接下來的動作鋪墊了很好的基礎。鏡頭設定簡潔但有力,讓格蘭帕斯的壓迫感直接傳達給觀眾,進一步營造出緊張氛圍,令人期待后續的發展。
當克蘭普斯出現時ζ
我們繼續制作了第六個鏡頭,這一段是格蘭帕斯真正開始追逐孩子的場景——通常來說,格蘭帕斯一登場,事情就開始“變得有意思”了。他的出現基本意味著故事節奏的加快,也是游戲中最令人期待的時刻之一。
在這一鏡頭中,沒有使用任何“transient”臨時圖層,而是采用了標準圖層結構,場景構建比較常規。我們依舊從設置圖層數量開始,并加載了雪的圖層,這一圖層為整個畫面增加了深度和空間感。雪花是分離圖層導出的,這樣每個圖像都更具專屬的空間層次,也便于后續動態表現的調整。
接著我們加載了被格蘭帕斯追逐的孩子的圖層。這個孩子的位置進行了微調,包括左右和上下的輕微移動,讓其在構圖中更合理。他應該略低一些,以增強被追逐感。
相機的移動也進行了調整,決定采用略微向上的鏡頭運動,模擬相機從地面稍微上仰的效果,以增強格蘭帕斯的壓迫感和畫面的戲劇性。
隨后添加了代表孩子眼淚的圖層。這個圖層進行了大小調整,并通過鎖定時間軸的位置精確對齊到孩子臉部。我們確保眼淚是從眼角流出而不是鼻子,這種微調雖然細小但非常重要。考慮到眼淚是和角色面部動作綁定的,所以它不會作為獨立運動圖層,而是緊貼孩子本身。
然后添加了第五圖層,也就是另一個小孩。這一圖層的位置和比例依舊需要對照前景角色進行合理推算。如果這個小孩位于主要角色稍前方,那么她就需要稍微放大,同時位置稍高一點以匹配透視。
接著加入了第六圖層,包含花環等場景道具。這一部分的擺放相對較難確定,因為道具的比例和位置既不能干擾主角的動態,又要保持裝飾作用。對這一層進行了多次嘗試,包括縮放和垂直位置調整,最終選定了一個比較理想的位置。
最后我們重新審視雪的圖層,認為它原本的位置過于前景,因此將其調整為更偏向中景的深度層次,并適當減小雪的顆粒尺寸,使其更自然地融入整體畫面。
整體來說,這一鏡頭構圖已經趨于完整,層次分明、動作明確,同時保持良好的故事節奏和視覺沖擊力。畫面中的雪、人物、裝飾和動作結合得自然流暢,鏡頭運動也增強了畫面的動感,整個場景效果令人滿意。
為什么不傳遞每個過場動畫的時長,而不是讓所有的過場動畫時長相同?
目前我們在制作過場動畫時,確實還沒有區分每個鏡頭的具體時長,所有鏡頭默認采用相同的持續時間。但這是暫時的安排,并不是最終的實現方式。
我們之后是會為每個鏡頭分別傳遞并設定其各自的時長的,這是已經在計劃內的事情。只不過在目前這個階段,我們的目標是先完成鏡頭的布局和場景的搭建,還不需要同步到音樂節奏或者做精細的時間調控,所以先使用統一時長作為過渡。
一旦進入到更精細的階段,比如過場動畫需要配合背景音樂、對白或節奏點進行展示,我們就會為每個鏡頭指定具體的持續時間,確保整個敘事的節奏與氛圍更加精準貼合。
總結來說,現在是為了方便快速制作內容,暫時統一了鏡頭時長,等之后節奏需要更精細化時,我們會對每個鏡頭的時間單獨處理。
對于奇怪的攝像機運動場景,你是否考慮過使用曲線插值,而不是線性插值?
關于鏡頭的旋轉和曲線運動,我覺得使用三拍形式反而能產生一種不同的效果,而不是線性運動。三拍式的運動感覺更有動態感,這樣的設計能夠在場景中加入一些有趣的變化。
如果是旋轉的鏡頭,可能就需要更柔和的曲線運動來平滑過渡,畢竟這種旋轉動作本身是帶有曲線感的。但從這個場景來看,我對它最終的效果并不是特別有信心。可能很難做到完全合適的視覺效果,所以我并不確定這會不會真的看起來很好。
至于其他的提問,關于Yankee的工作,她確實是游戲的插畫師,負責了大量的藝術設計和視覺工作,具有很強的插畫能力。
楊天的藝術真棒!
游戲的藝術風格看起來非常棒,我很喜歡。雖然我自己不太參與藝術設計的細節,我通常會讓藝術家去做這部分的工作。我基本上只是給出一些簡單的想法,比如“這里應該有一個格蘭帕斯從門口出現”,然后我可能會畫個簡單的草圖,標明場景的大概布局,比如格蘭帕斯在這兒,其他角色在那兒,接著藝術家就會基于這些簡單的描述,展開創作。
藝術家負責了所有角色的設計,包括格蘭帕斯的外形、其他人物的形象以及整個游戲的視覺風格。所有這些視覺內容都是藝術家發揮創造力后設計出來的。
請做更多的工作η
大家似乎都希望看到更多的過場動畫,那就讓我們做更多的吧,感覺這樣很有意義。反正如果有問題,明天還可以繼續提問,每個工作日都可以隨時向我們詢問。總的來說,這個過程非常有趣,我可以一直做下去,真的很喜歡做這些事情,感覺每天都能做得很開心。
game_cutscene.cpp:合成鏡頭 7
在第七鏡頭中,場景設定相對簡單,只有兩個層次。一個是格蘭帕斯,另一個是孩子,二者在相對運動中。格蘭帕斯向左滑動,孩子向右滑動。這一鏡頭的特點是平移鏡頭,鏡頭不會變焦,只是水平移動。鏡頭的動作是左右平移,展示兩者之間的運動,最終使得格蘭帕斯顯現出來。
此場景使用了“臨時標志”(transient flag)和“反向攝像機動作”標志,用來控制鏡頭和角色的移動。具體來說,格蘭帕斯和孩子的相對運動可以通過調整兩者的位置來實現,保證鏡頭拍攝效果和動作的自然過渡。由于這個場景較為簡單,調整的元素較少,主要是格蘭帕斯和孩子的位置調整,確保兩者在鏡頭中合適的顯示。
在場景的后續調整中,重點是移動鏡頭,以確保格蘭帕斯和孩子之間的互動清晰可見。格蘭帕斯和孩子的運動要協調,以表現他們之間的對抗和互動。
接下來進入第八鏡頭,這一鏡頭不需要做太多的時間變化調整,主要是控制層次的變化和角色的相對移動,確保過場動畫的流暢性和視覺效果。
game_cutscene.cpp:合成鏡頭 8
在第七鏡頭的設置中,首先檢查了鏡頭和角色的層次,確保每一層都正確地展示了角色和物體的位置。首先是格蘭帕斯的設定,鏡頭需要調整,確保畫面清晰,方便查看每一層的元素。鏡頭的運動采用了放大縮小的方式,具體表現為鏡頭對格蘭帕斯進行一定的放大,保證他在鏡頭中的位置和動態更清晰。
在具體操作上,鏡頭和層次的調整需要確保每個元素都居中并覆蓋整個畫面。這是為了保證視覺效果的平衡,讓每個元素都有足夠的展示空間,特別是像手套這樣的道具。手套作為一個重要的物品,它的大小和位置需要精確調整,保證它看起來與角色的比例匹配。
同時,其他層次也被逐一加入,包括一些孩子的角色和吊飾等,這些元素需要保持協調,避免畫面過于擁擠。在這一過程中,注意到了鏡頭的運動軌跡,特別是對于放大縮小的處理,確保鏡頭的移動更加自然。
隨著鏡頭的推進,故事情節也有所展開。格蘭帕斯從最初的追逐孩子轉變為幫助孩子,表現出一種積極向上的形象,與傳統的圣誕老人角色形成對比。這個轉變讓角色更加立體,也為后續的劇情發展奠定了基礎。
最后,調整了畫面中的裝飾元素,如吊飾等,確保它們的位置和大小符合畫面整體的視覺效果。為了讓鏡頭更加有層次感,決定讓鏡頭稍微向下傾斜一些,這樣可以更好地聚焦于手套等物品,同時突出格蘭帕斯和孩子之間的互動。
這個鏡頭的設置基本完成,主要聚焦在細節調整上,確保每個元素都能在鏡頭中正確展現,達到預期的視覺效果。
game_cutscene.h:將 v2 參數添加到 scene_layer
在這段過程中,討論了代碼實現中的一些細節,主要是關于參數的設定和代碼優化。首先提到,雖然不想過于沉溺于自己設定的細節中,但依然決定嘗試做一些修改,優化代碼的方式。提出了設定一個“間隔”參數,甚至考慮了設定一個“最大值”或“最小值”的區間參數,像是“32”和“bob”之類的變量名,用來控制某些功能的范圍。
接著,介紹了如何使用一個通用的向量作為參數傳遞,并提到將在這些對象中進行打包處理,目的是為了管理多個數據的組織方式。盡管遇到了一個小問題,即沒有收到預期的錯誤提示,可能是因為代碼在實現時沒有按照預期執行,產生了不完全的錯誤提示。盡管如此,對于這些問題并不感到特別煩惱,認為這并不是非常關鍵的地方,且認為這只是一個技術上的小偏差。
整體來看,這段討論的重點是對代碼中某些參數的調整和優化,以便使其更加符合需求,雖然有些問題出現了,但并沒有太大影響,依然在進行相關操作以完成整體工作。
game_cutscene.cpp:合成鏡頭 9
在這段內容中,討論了關于第九個鏡頭的設置。這個鏡頭主要是一個簡單的鏡頭拉近(zoom),聚焦到一個小孩上。他正回到自己的房間,鏡頭會從遠處拉近到他的身上,確保鏡頭的移動方向與場景相符,調整了鏡頭的角度,使得畫面更具表現力。
接下來,討論了需要的幾個層級。第一個層級是鏡頭拉近至孩子身上的效果,第二個層級則是一些細節的處理,例如房間的天花板上的物品。這個層級中的物品相對較小,且會很快被鏡頭移動過去,因此放置這些物品時也需要考慮它們的大小與位置。
具體來說,鏡頭中的燈具、裝飾物和其他元素都需要調整大小和位置,使得它們與鏡頭的運動相適應,避免遮擋重要的畫面內容。燈具和裝飾物的大小被做了適當的調整,有些元素如燈具還需要稍微移動,確保它們出現在畫面中的合適位置。
在完成這些調整之后,鏡頭的整體效果感覺非常順暢,所有層級都正確排列,鏡頭的移動和物體的擺放都達到了預期的效果。最終,確認鏡頭的布局完成,剩下的任務是繼續處理后續的鏡頭,完成所有的鏡頭序列。
此外,還提到,剩下的工作是將這些鏡頭按照順序連接起來,完成開場的動畫。雖然目前還沒有聲音和配音,但整體的畫面和動畫布局已經準備好了。剩余的工作將在第二天繼續完成,只剩下最后的兩個鏡頭。
你喜歡聽到鏈接器的哀嚎和它因無法寫入 .exe 而在西西弗式的痛苦中扭動嗎?
在這段內容中,討論了對Microsoft Linker的負面看法,認為它是一個非常糟糕的工具。對于Linker在遇到問題時的痛苦和掙扎,表達了一種輕微的娛樂感,認為它在遇到困難時的表現是可以接受的,甚至某種程度上令人愉快。對于這種情況的態度反映出對這個工具的不滿,并且對其在處理問題時的無力感感到某種程度的解脫或滿足。
你們有安排配音演員了嗎?
在這段內容中,提到由于還沒有找到合適的人選來進行開場序列的旁白配音,因此配音并沒有包含在當前的包中。等找到合適的配音演員之后,會把旁白部分加入到包中。
第一個鏡頭中的手套是左手手套,接下來的鏡頭是右手手套
在這段內容中,提到了第一個場景中的手套是左手手套,而下一個場景中的手套卻是右手手套。對于這種情況,可能需要修正,因為不應該出現不同的手套方向。解決方法是可以將左手手套翻轉過來,變成右手手套。這樣處理是比較簡單的,而且手套本身發光,因此沒有特別的方向要求,翻轉手套應該是個合理的選擇。
第一場景中的門是開的,但在克蘭普斯進入之前關了
在這段內容中,提到第一個場景中的門是開著的,但在角色進入之前門卻是關著的。對于這種情況,應該做一些修正,并且記錄下需要修正的地方,特別是一些藝術方面的修訂筆記。可能存在一個場景中門是關著的,然而具體情況還不清楚,需要進一步確認和詢問,可能會找到相關的素材。
在鏡頭 2 中,我注意到窗戶頂部有個縫隙。那還在嗎?
在這段內容中,提到在窗口的頂部似乎有一個空隙,需要確認是否仍然存在。回顧了鏡頭二和鏡頭三,提到可能是鏡頭二中的問題,確實看起來窗戶頂部的部分有偏差,似乎過于下移。針對這一點,考慮進行調整,以解決這個問題。盡管這可能是一個缺少視差效果的鏡頭,但仍需進一步修正。
我可以收養其中一個孩子嗎?
提到一個問題,是否可以收養其中一個孩子。對于這個問題,表示不確定,因為不清楚該孤兒院的具體政策。
試試社區中的配音演員?我們中的不少人愿意參與/有很好的麥克風
提到可以嘗試在社區中尋找配音演員,表示有不少人愿意并且有一定的基礎,但需要找到一個特別合適的人選,特別是能夠提供高質量配音的人選。
這個游戲會支持左撇子嗎?
關于是否支持左撇子玩家,認為其實玩起來差別不大,不論是左手還是右手,都只是四個方向的操作。因此,不管是左撇子還是右撇子,游戲的玩法基本上是一樣的。
你能解釋一下動畫中的漸變效果嗎?
在討論動畫中的漸變效果時,需要明確具體是指哪種漸變效果。漸變可能指的是圖像、元素或者場景的淡入淡出效果,或者是一些特定動作、過渡的視覺效果。所以,具體是哪種類型的漸變效果需要進一步確認。
你應該在那個地方加一點雪,這樣能增加深度感
需要在畫面上加一點雪花效果,以增加深度感。為了記住這些修改,可能需要更新并記錄一些事項,包括手套的朝向等細節。考慮到沒有筆,決定將這些修改內容寫在系統里,以便以后能夠查看和提醒自己。
我們仍然需要自己的三角函數,這樣就不需要每次都調用 C 標準庫中的 sin() 函數了
需要使用一些三角函數來停止當前的簽名操作,通過使用C語言的標準庫來實現。標準庫提供了一些函數,例如sprintf
、sign
、floor
、ceil
、round
等。對于這些函數中的一些,可能不需要花費太多時間來實現,因為它們比較簡單,如truncate
。而像floor
和ceil
這樣的函數實現起來可能需要更多工作。對于sign
和round
函數,雖然不容易實現,但使用現有的工具可以幫助完成這些工作。
你之前提到過我們可以通過漸變讓動畫序列更流暢。例如,當圣誕老人給英雄戴上帽子時。我想知道那會是什么樣子
提到的這種漸變效果可以通過在時間范圍內選擇特定部分,改變兩個層的透明度來實現。例如,可以讓一個層的透明度從1漸變到0,而另一個層的透明度則從0漸變到1。通過這種方式,就能讓一個物體(例如角色)漸漸出現或消失,達到逐步顯現或隱去的效果。這樣的方法非常直觀,只需調整時間范圍內透明度的變化即可。
我注意到過場動畫的位圖沒有隨著窗口大小縮放。這是為什么?
問題出在窗口的大小和渲染的分辨率之間不匹配。當前,游戲在一個固定的分辨率下渲染,因此它不會根據窗口的大小來調整。如果游戲能夠請求一個較小的窗口,并根據窗口大小渲染,那么就可以解決這個問題。目前的問題是,盡管我們可以改變分辨率,但渲染并沒有根據實際窗口大小進行調整,因此導致了窗口和渲染內容的不一致。
win32_game.cpp:暫時切換到使用更小的后臺緩沖區
目前,渲染的問題與窗口大小和分辨率之間的匹配有關。游戲引擎支持分辨率獨立性,可以請求引擎生成較小的圖像,只需要調整后端緩沖區的大小即可。然而,在當前的測試過程中,窗口的大小是固定的,并沒有進行窗口尺寸的動態調整。因此,盡管引擎可以處理更小的窗口和分辨率,但為了測試游戲實際運行時的分辨率(例如 1920x1080),目前并沒有讓窗口大小與分辨率調整匹配。游戲會有一個窗口,通常是全屏模式,且不會允許用戶調整游戲窗口的大小。這種裁剪行為是有意為之的,并且是為了確保游戲在最終發布時在正確的分辨率下運行。
floor 和 ceil 很難嗎?
實現 floor
和 ceil
函數并不像 sign
或 tan
函數那樣困難,但仍然具有一定的挑戰性。要正確處理這些函數,必須使用一些“魔法常量”并執行一些復雜的操作。這些操作的實現涉及到不少細節,需要一些精心設計的代碼。例如,如果使用的是 sfc
(某種庫),這些函數的實現非常簡單,直接可以調用 floor
和 ceil
函數。但如果使用的是其他庫(如 sse2
),則需要自己動手實現,并且這并不簡單,必須細致地思考并完成一些特定的計算。雖然這項工作并不算特別難,但為了做到正確,確實需要仔細考慮和執行,大約需要四到五條指令。
為什么我們要重做 sin() 函數?
減少使用 sign
函數的原因主要是出于教育目的。雖然在實際應用中,減少使用 sign
函數可能有性能上的考慮,但這里的重點是通過實現這些低級功能來學習底層編程。如果只是調用現有的庫函數,我們就無法真正了解這些功能是如何實現的。
sign
函數本身是一個相對復雜的函數,如果只是簡單地調用它而不理解它的實現,我們就無法掌握如何使用如冪級數近似、泰勒級數近似等方法。因此,學習如何手動實現這些功能非常重要,尤其是當你需要模擬一個沒有現成庫函數的功能時。
這種做法的核心理念是,避免依賴庫函數,而是通過自己實現,掌握如何做這些低級操作。雖然在實際應用中,可以使用 C 運行時庫來簡化開發,但出于教育目的,希望盡量減少依賴庫函數,確保每個人都能理解如何實現 C 運行時庫中的所有功能。最終的目的是通過這種方式,學習和掌握更多的編程技巧,而不是簡單地依賴別人已經做好的東西。