用DirectX實現魔方(一)


關於魔方

魔方英文名字叫做Rubik's Cube,是由匈牙利建築學教授和雕塑家Ernő Rubik於1974年發明,最初叫做Magic Cube(這大概也是中文名字的來歷吧),1980年Ideal Toys公司開始銷售此玩具,並將名字改為Rubik's Cube。

魔方在80年代最為風靡,至今未衰。截至2009年1月,魔方在全世界已經售出了3億五千多萬個。最常見的魔方是三階魔方,由27個小方塊構成,共三層,每層9個小方塊。我的Demo實現的就是三階魔方。其他的魔方種類有二階,四階及更高階,也有鑽石魔方,五邊形魔方,三角魔方等。

三階魔方所有可能的排列數是43252003274489856000,這個數實在是太大了,用中文不知道該如何表達。可以打一個比方,如果有這么多個三階魔方,那么可以覆蓋地球表面275次!

Demo來歷

這是我以前學習DirectX的時候寫的一個Demo,大概是2008年左右,當時寫完以后高興了好幾天,現在拿出來看看,彼時的情景歷歷在目。隨着年齡的增長,已經不能像以前那么拼命的寫程序了,現在想安靜下來干點事都是奢望呀,不過對於DirectX的熱情倒是有增無減,一有時間還是會抽空寫點代碼。對於強大的DX來說,這個Demo簡直是小兒科了,不過麻雀雖小,五臟俱全。再小的東西也有值得學習和總結的地方,本着這個目的,我將這個Demo從新整理了一下,簡化了一些代碼,並改進了一些算法,拿出來和大家分享。說實話,這個Demo有很多地方我不是很滿意,發出來也是為了能收集一下大家的意見,繼續改進,歡迎大家多多指教。我打算分幾個部分詳細介紹一下這個Demo的編寫原理。

  • 概述(此篇),講一下整個程序的結構及流程。
  • 構造魔方,模型構造,貼圖,光照,渲染等。
  • 旋轉視角,主要介紹一下如何用Arcball來實現旋轉。
  • 旋轉魔方,如何旋轉某一層,這是程序最核心的部分,占了整個程序50%左右的代碼。
  • 雜項,一些不好分類的都放在這里,並不是不重要,比如D3D程序框架,D3D設備的管理,全屏及窗口的切換等。

知識准備

程序采用C/C++語言+DirectX 9.0編寫,用的還是固定管線API,因為我對shader不太熟悉,稍后有空學習一下可以出個shader版本。也可能移植到DirectX 11上,就算是練練手吧。這個Demo涉及的技術有以下幾個方面。

  • C/C++語言
  • DirectX,Vertex, Index。光照,紋理映射等,都是入門級的東西。
  • Windows程序設計,窗口管理,消息處理等。
  • 計算機圖形學,這個就不用多說了,必須的。
  • 數學,線性代數,空間解析幾何,Arcball及相交檢測都會涉及到一點數學知識。

效果圖

俗話說得好,有圖有真相!先來個透視照(線框圖)

然后來個素顏照(實體未貼圖)

 

再來個有貼圖的(穿上衣服后,好看多了),魔方的顏色采用國際標准配色。

  • 前面-白色
  • 后面-黃色
  • 左面-紅色
  • 右面-橙色
  • 頂面-綠色
  • 底面-藍色

旋轉某一層

        

打亂順序

實現原理

構造魔方

起初,模型采用的是DirectX的.x文件格式,現在.x格式已經被微軟拋棄了,盡管你仍然可以使用它,但是在DirectX 11中,已經沒有支持.x文件的接口了。要使用.x文件,只能使用舊版本的DirectX SDK或者用第三方庫。由於魔方對應的幾何模型比較簡單,就是立方體,所以就干脆不用.x文件了,直接畫,一個完整的魔方由27個小的立方體構成,所以如果能繪制一個小立方體,那么就可以繪制27個,拼成一個完整的魔方。

關於貼圖,開始用的是紋理圖片,后來簡化了一下,直接在內存中生成紋理,因為單色的,而且只有六種顏色,並不麻煩。動態生成的一個好處是發布程序的時候也不同發布紋理圖片了,只有一個可執行文件。

旋轉魔方

旋轉魔方是通過鼠標拖拽來完成的,分為如下兩個部分:

  • 旋轉整個魔方(右鍵拖拽)
  • 旋轉某一層(左鍵拖拽)

前者通過變換視角來完成,實現采用Arcball技術,Arcball有很多優點,相比歐拉角來說,Arcball更加平滑,而且沒有抖動現象(這個本質是因為Arcball里面采用的是Quaternion)。變換視角而不是通過旋轉魔方本身的好處是

  • 實現更方便,更高效。
  • 不改變模型的坐標,維持模型的坐標不便對於旋轉魔方的某一層十分重要。

后者通過旋轉模型本身來實現,因為變換視角會影響場景中的所有模型,而旋轉某一層要保證其他層不動,所以只能旋轉模型本身,因為將魔方拆成了27個小的cube。這對於只操作某些部分而維持其他部分不變是十分方便的。旋轉某一層的方法如下

  • 通過鼠標點擊生成拾取射線,判斷射線是否擊中魔方,如擊中則執行后續步驟,否則不做任何操作。
  • 通過鼠標移動判斷該旋轉哪一層
  • 根據旋轉層選定該層包含的小立方體
  • 計算旋轉軸和旋轉角度
  • 旋轉這些立方體
  • 鼠標松開時完成剩下的旋轉(保證每次旋轉都是90度的倍數,否則魔方無法對齊)

鍵位介紹

  • 鼠標左鍵(拖拽)-旋轉某一層
  • 鼠標右鍵(拖拽)-旋轉整個魔方
  • 滾輪-縮放
  • F - 全屏及窗口切換
  • S - 打亂順序
  • R - 還原
  • Esc 退出程序

程序結構

主要有如下幾個類及文件

  • Arcball,軌跡球,模型旋轉的根基。
  • Camera,攝像機類,負責顯示場景,變換視角。會用到Arcball類。
  • Cube,構成魔方的小立方體類,包括構造,繪制,貼圖,更新變換矩陣等主要接口。
  • D3D9,這個類是后來加入的,把大部分與D3D9相關的操作全部歸到這里了。
  • RubikCube,魔方類,總控,協調其他類完成魔方的所有功能。會用到Cube類。
  • Math,數學相關,主要有三角形,矩形,射線的實現,以及射線和三角形的相交檢測。
  • Main,程序入口,負責創建窗口和運行程序。

程序下載

先出個不太成熟的版本,bug一定不少,歡迎大家提出寶貴意見。

Rubik Cube

== Happy Coding ==


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM