用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一定不少,欢迎大家提出宝贵意见。
== Happy Coding ==
用DirectX实现魔方(一)的更多相关文章
- 用DirectX实现魔方(三)视角变换及缩放(附源码)
在本系列第一篇介绍过鼠标按键的功能,如下. 左键拖拽 - 旋转魔方 右键拖拽 - 变换视角 滚轮 - 缩放魔方 今天研究一下如何实现后面两个功能,用到的技术主要是Arcball,Arcball是实现M ...
- 用DirectX实现魔方(二)
这篇说一下如何构造魔方,主要包括魔方几何体的构造及纹理贴图.以下论述皆以三阶魔方为例,三阶魔方共有3 x 3 x 3 = 27个小立方体. 构造魔方 在第一篇里面说过,最初模型用的是微软的.x文件格式 ...
- DirectX11--实现一个3D魔方(3)
前言 (2019/1/9 09:23)上一章我们主要讲述了魔方的旋转,这个旋转真是有毒啊,搞完这个部分搭键鼠操作不到半天应该就可以搭完了吧... (2019/1/9 21:25)啊,真香 有人发这张图 ...
- DirectX11--实现一个3D魔方(2)
前言 上一章我们主要讲述了魔方的构造和初始化.纹理的准备工作.目前我还没有打算讲Direct3D 11关于底层绘图的实现,因此接下来这一章的重点是魔方的旋转.因为我们要的是能玩的魔方游戏,而不是一个观 ...
- DirectX11--实现一个3D魔方(1)
前言 可以说,魔方跟我的人生也有一定的联系. 在高中的学校接触到了魔方社,那时候的我虽然也能够还原魔方,可看到大神们总是可以非常快地还原,为此我也走上了学习高级公式CFOP的坑.当初学习的网站是在魔方 ...
- Windows 常用运行库下载 (DirectX、VC++、.Net Framework等)
经常听到有朋友抱怨他的电脑运行软件或者游戏时提示缺少什么 d3dx9_xx.dll 或 msvcp71.dll.msvcr71.dll又或者是 .Net Framework 初始化之类的错误而无法正常 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- “为什么DirectX里表示三维坐标要建一个4*4的矩阵?”
0x00 前言 首先要说明的是,本文的标题事实上来自于知乎上的一个同名问题:为什么directX里表示三维坐标要建一个4*4的矩阵? - 编程 .因此,正如Milo Yip大神所说的这个标题事实上是存 ...
- VS2015+Win10 调试DirectX 报错
安装完Win10调试程序突然在这个地方报错: #if (defined(DEBUG) || defined(_DEBUG)) deviceFlags |= D3D11_CREATE_DEVICE_DE ...
随机推荐
- android6.0锁屏界面接收新通知处理流程
灭屏状态下,接收新信息,屏幕会半亮显示通知流程: 1,应用构造notification后,传给NotificationManager,而后进入NotificationManagerService处理. ...
- emmet插件快捷键:
概念:emmet插件是用在编辑器里面的一个可以快速编写代码的插件,比如sublime text中,就可以用它来快速创建代码,本文主要是在sublime text的编辑器中做的测试代码. 一.html ...
- backbone框架思路
Backbone是MVC框架.如何使用这个框架来简化前端过程呢?作为一个初学者,虽然网上有它的官方文档,但是都是讲的一些方法,思路分析的却对初学者来说,看得晕乎乎的.现在就把自己对这个框架的理解记录在 ...
- 领域模型驱动设计(Domain Driven Design)入门概述
软件开发要干什么: 反映真实世界要自动化的业务流程 解决现实问题 领域Domain Domain特指软件关注的领域 在不能充分了解业务领域的情况下是不可能做出一个好的软件 领域建模 领域模型驱动设计 ...
- HTML与CSS基础知识补遗(一)
开始从零基础系统地学习前端知识了,虽说html和css多少了解一些,但是学着还是能发现很多新大陆.... 一. HTML中head标签 1. <meta>标签: meta标签里是一些基础的 ...
- 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management
写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...
- Object-C中一些不同于C系列语言表现的特性
这段时间体验和学习OC,虽然这么多年基本都在使用C系列语言(C,C++,C#),但是仍然有很多的不习惯. 当然,这些不习惯不代表讨厌或者不好,也许这些就是OC作为Apple开发首选语言而显得特殊的一些 ...
- php面向对象学习
近期跟着别人开发一套php程序,深感自己面向对象很白痴,于是再次巩固了一下面向对象的学习,自己整理了一下这几天面向对象的东西,给大家分享!! 面向对象的三大特性: 封装 -- 隐藏内部实现,稳定外部接 ...
- WPF控件经验小结:(1) ToolBar去掉右边箭头(扩展图标)
今天开发时,同事问我一个问题.怎么去除ToolBar右边扩展图标.我想了一下,说改Style.同事说太麻烦了.可不可以快速修正.我说应该动态去读取Template模板中的Style,然后隐藏.怎么实现 ...
- 每天记一些php函数,jQuery函数和linux命令(二)
简介:学习完了php和jQuery之后,对函数的记忆不到位,导致很多函数没记住,所以为了促进自己的记忆,每天花一点时间来写这个博客. 时间:2016-12-19 地点:太原 天气:晴 一.p ...