用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 ==


本文转自zdd博客园博客,原文链接:http://www.cnblogs.com/graphics/p/2580832.html,如需转载请自行联系原作者

相关文章
|
8月前
|
JSON 监控 前端开发
Python爬取微博热搜并实时发送到邮箱:零基础实现指南
本文介绍如何用Python实现微博热搜自动抓取与邮件推送,通过requests、BeautifulSoup和smtplib等库,50行代码即可完成定时监控,解决数据获取、解析与发送难题,提升信息获取效率。
352 1
|
8月前
|
API
鸿蒙应用开发从入门到实战(七):ArkTS组件声明语法
《鸿蒙应用开发从入门到项目实战》系列文章持续更新中,陆续更新AI+编程、企业级项目实战等原创内容、欢迎关注!​本文从界面制作从组件声明开始,通过一个相对简单的案例来系统的学习 ArkTS 声明组件的语法。
219 2
|
存储 弹性计算 缓存
阿里云服务器99元和199元与轻量应用服务器38元各自性能、适用场景与选择参考
2025年,阿里云推出了多款低价特惠云服务器,其中轻量应用云服务器2核2G 200M带宽 40G ESSD云盘38元1年,云服务器ECS 2核2G 3M带宽 40G ESSD Entry盘活动价99元1年,而2核4G 5M带宽 80G ESSD Entry盘则仅售199元1年。对于还未使用过阿里云轻量应用服务器和云服务器的用户来说,并不是很清楚他们各自有性能怎么样,主要使用场景有哪些,本文来做个简单介绍与对比,以供参考和选择。
|
数据采集 SQL 分布式计算
Hadoop数据清洗和转换
【5月更文挑战第9天】Hadoop数据清洗和转换
466 2
|
机器学习/深度学习 TensorFlow 语音技术
使用Python实现深度学习模型:语音合成与语音转换
【7月更文挑战第19天】 使用Python实现深度学习模型:语音合成与语音转换
715 1
|
关系型数据库 MySQL 测试技术
记录一次后端接口抖动的排查过程
某天下午,测试新功能时发现页面接口偶尔变慢,平均十次调用中有三到四次出现3秒以上的延迟。排查了接口、数据库和服务器资源后未发现问题,最终锁定为K8s节点的负载均衡策略导致。测试环境仅有一个公网IP,SLB轮询四个Pod(其中三个为空),造成周期性延迟。移除空Pod后问题解决。
409 6
|
缓存 JavaScript 前端开发
Vue 中动态导入的注意事项
【10月更文挑战第12天】 在 Vue 项目中,动态导入是一种常用的按需加载模块的技术,可以提升应用性能和效率。本文详细探讨了动态导入的基本原理及注意事项,包括模块路径的正确性、依赖关系、加载时机、错误处理、缓存问题和兼容性等,并通过具体案例分析和解决方案,帮助开发者更好地应用动态导入技术。
433 18
|
算法 安全 Go
Go语言哈希函数不可不知的N个实战技巧
Go语言哈希函数不可不知的N个实战技巧
704 0
|
缓存 资源调度 Rust
前端效率提升实践之路
在一个B端前端项目中,开发团队面临开发效率低、交付质量和可维护性差的问题。为了解决这些问题,他们以“提效”为主题,展开了项目治理。首先,他们优化了发布和编译过程,通过更换包管理工具、减少不必要的包、使用缓存策略等方法,显著缩短了发布和编译时间。其次,团队致力于沉淀可复用物料,创建了高度配置化的组件,通过VSCode插件助手自动化配置,提高了代码复用性和开发效率。此外,他们还改进了研发流程,制定了前端、后端和产品的规范,以减少沟通成本和提高接口质量。通过这些措施,团队成功提升了开发效率,并降低了代码维护成本。
705 3
前端效率提升实践之路
|
机器人 Shell 开发者
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。
`roslibpy`是一个Python库,它允许非ROS(Robot Operating System)环境(如Web浏览器、移动应用等)与ROS环境进行交互。通过使用`roslibpy`,开发者可以编写Python代码来远程控制ROS节点,发布和订阅话题,以及调用服务。

热门文章

最新文章