用DirectX實現魔方(一)

關於魔方

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

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

三階魔方全部可能的排列數是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及相交檢測都會涉及到一點數學知識。

效果圖

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

而後來個素顏照(實體未貼圖)blog

 

再來個有貼圖的(穿上衣服後,好看多了),魔方的顏色採用國際標準配色。接口

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

旋轉某一層圖片

        

打亂順序ip

實現原理

構造魔方

起初,模型採用的是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 ==

相關文章
相關標籤/搜索