canvas实现3D魔方
摘要:使用canvas实现可交互的3D魔方
一、简单分析
魔方物理性质:
1.中心块(6个):中心块与中心轴连接在一起,但可以顺着轴的方向自由的转动。
2.棱块(12个):棱块的表面是两个正方形,结构类似一个长方体从立方体的一个边凸出来。
3.角块(8个):角块的表面是三个正方形,结构类似一个小立方体从立方体的一个边凸出来,这样的结构可以让角块嵌在三个棱块之间。
4.可见方块(26个):魔方对于我们可见的方块有26块。
5.魔方六个面,每个面九个方块,转动时每个面绕着自己面的中心块旋转。
6.在观察魔方时,我们将整个魔方绕着三维空间中的某个点旋转
7.在人的视野范围内,魔方可见的部分只有三个面,19个方块。
二、实现方式
1)完成方块的旋转

通过简略的类图,先了解一下实现的思路。在一个三维空间中,最基础的就是点(Vertex),点组成了面(Face),面组成了空间立方体(Cube)。魔方(MagicCube)由26个Cube组成,同时将26个Cube单组不重复的分为6组(MagicFace)。当旋转观察魔方时,26个Cube绕着魔方的中心旋转。当转动魔方的某一面时,MagicFace上所有的Cube围绕以原点为起点,面的中心为终点的矢量旋转。只需要掌握点在空间中的旋转,即可完成整个魔方的旋转。三维空间中点的旋转主要用到了数学上的旋转公式。关于如何将一个三维空间的立方体投影到平面并实现旋转请看我的上一篇随笔。
2)完成方块的上色
第一步只是完成了一个透明魔方旋转。我们需要给魔方上色。初始化时为每个cube的face上色,我们不可见的面设置为白色。就像我们在现实中绘画一样,在canvas上绘制图像时后渲染的图像会把之前的覆盖掉,因此魔方的渲染顺序我们需要从后往前渲染。

我们通过面的中心距离原点的Y值(本例以Y轴垂直与屏幕作为参考轴),来确定渲染顺序。单个方块的渲染如上图,6个面(*代表看不见的面),渲染顺序为1*,2*,3*,4,5,6,后渲染的面将前面渲染的面盖住。

整个魔方的渲染,举例标了数字的三个方块,也是通过方块中点距离原点的Y值来确定渲染顺序。渲染顺序先是方块1,然后方块2把1的上半部分盖住,然后方块3把方块二的上半部分盖住。
3)完成鼠标的点击事件
交互是本例中比较难的一个点,canvas 没有提供为其内部元素添加事件监听的方法,因此如果要使 canvas 内的元素能够响应事件,需要自己动手实现。通过获得鼠标在 canvas 上的坐标,计算当前坐标在哪些元素内部,然后对元素进行相应的操作。配合自定义事件,我们就可以实现为 canvas 内的元素添加事件监听的效果。

在上图中,可旋转的面投影到二维平面的区域共有6个,图中只标识了三个。如何确定投影的区域呢?想了很多方法,最终采用了建立参考点的方法。
1.获取到3个可视面MagicFace(F1F2F3)---6个面中中心Y值最大的3个
2.获取到3个可视面无穷远的参考点(V1V2V3)--6个参考点中Y值最大的3个
4.我们循环6个面,例如循环到图中的F2面,我们过滤离F2中心最近的参考点(过滤掉与F2中心空间距离最小的点),剩下V1V3
5.获取到F2面中离V1最最近的三个方块(即上方红色区域的三个方块) -- 离参考点的空间距离
6.获取三个方块中里F2这个面中点最远的4个点(即上方红色区域的4个顶点)
通过3层循环,即可获取到所有可视面的投影。当我们鼠标点击并滑动一段距离时(图中黑点),我们就可以判断两个点所在的投影的位置是哪一个面的,获取到面之后就可以旋转那个面。
PS:我们通过建立参考点,6个无穷远的点(分别在X,Y,Z轴的正负方向上,魔方整体旋转时参考点也会旋转)。使用他与各个元素中点的距离用于判断一些特殊位置的点和面的方法。滑动部分的投影的8个点就是用参考点辅助求出的。
判断点是否在面中使用的是pnpoly算法 https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
三、最终效果

PS:面积投影越小事件效果就不灵敏了,有待优化
canvas实现3D魔方的更多相关文章
- css3之3D魔方动画(小白版)
在这里分享一下3D魔方动画,html5+CSS3即可完成~无图无真相,先上效果图 第一步非常简单,就是先将魔方的结构画出来.大家都玩过魔方,知道魔方是一个有六个面的正方体.这里我们先写一个大的di ...
- Seen.js – 使用 SVG 或者 Canvas 渲染 3D 场景
Seen.js 渲染3D场景为 SVG 或者 HTML5 画布.Seen.js 包含对于 SVG 和 HTML5 Canvas 元素的图形功能的最简单的抽象.所有这个库的其它组件都是不用关心将要渲染的 ...
- DirectX11--实现一个3D魔方(3)
前言 (2019/1/9 09:23)上一章我们主要讲述了魔方的旋转,这个旋转真是有毒啊,搞完这个部分搭键鼠操作不到半天应该就可以搭完了吧... (2019/1/9 21:25)啊,真香 有人发这张图 ...
- DirectX11--实现一个3D魔方(2)
前言 上一章我们主要讲述了魔方的构造和初始化.纹理的准备工作.目前我还没有打算讲Direct3D 11关于底层绘图的实现,因此接下来这一章的重点是魔方的旋转.因为我们要的是能玩的魔方游戏,而不是一个观 ...
- DirectX11--实现一个3D魔方(1)
前言 可以说,魔方跟我的人生也有一定的联系. 在高中的学校接触到了魔方社,那时候的我虽然也能够还原魔方,可看到大神们总是可以非常快地还原,为此我也走上了学习高级公式CFOP的坑.当初学习的网站是在魔方 ...
- 如何用CSS3画出懂你的3D魔方?
作者:首席填坑官∙苏南公众号:honeyBadger8,群:912594095,本文原创,著作权归作者所有,转载请注明原链接及出处. 前言 最近在写<每周动画点点系列>文章,上一期分享了& ...
- 用Canvas玩3D:点-线-面
声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 玩Canvas玩了有两三个礼拜了,平面的东西玩来玩去也就那样,所以就开始折腾3D了. 因为Canvas画布终究还是平面的,所以要有3D就得 ...
- 基于 HTML5 Canvas 的 3D 模型贴图问题
之前注意到的一个例子,但是一直没有沉下心来看这个例子到底有什么优点,总觉得就是一个 list 列表,也不知道右边的 3d 场景放两个节点是要干嘛,今天突然想起来就仔细地看了一下这个例子的代码,实际操作 ...
- 基于 HTML5 Canvas 的 3D 模型列表贴图
少量图片对于我们赋值是没有什么难度,但是如果图片的量大的话,我们肯定希望能很直接地显示在界面上供我们使用,再就是排放的位置等等,这些都需要比较直观的操作,在实际应用中会让我们省很多力以及时间.下面这个 ...
随机推荐
- Oracle ADF 开发必读
MARK:http://www.oracle.com/technetwork/cn/articles/adf/index-086064-zhs.html 第 1 部分- 借助 Subversion 进 ...
- Invalid Subledger (XLA) Packages In Release 12.1.3
In this Document Goal Solution 1.- Information about These Packages 2.- Solution Reference ...
- MTU 最大传输单位
MTU 最大传输单位 通过上面 MAC 封装的定义,现在我们知道标准以太网络frame所能传送的数据量最大可以到达 1500 bytes , 这个数值就被我们称为 MTU (Maximum Trans ...
- HBase运维经验
http://www.qconbeijing.com/download/Nicolas.pdf 重点看了下facebook做了哪些改进以及他们的运维经验,比较重要的有以下几点: 改进: 1 加强了行级 ...
- PHP单元测试使用
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类, ...
- c语言 基本运算
计算机的基本能力就是计算,所以一门程序设计语言的计算能力是非常重要的.C语言之所以无所不能,是因为它不仅有丰富的数据类型,还有强大的计算能力.C语言一共有34种运算符,包括了常见的加减乘除运算.这讲就 ...
- Linux/Windows远程桌面
WINDOWS远程连接LINUX配置(LINUX VNC Server配置): 1.查看本机是否有安装vnc(centOS5默认有安装vnc) rpm -q vnc vnc-server 如果显示 ...
- 在Redis Sentinel环境下,jedis该如何配置
在Redis主从复制架构中,如果master出现了故障,则需要人工将slave提升为master,同时,通知应用侧更新master的地址.这样方式比较低效,对应用侧影响较大. 为了解决这个问题,Red ...
- Java编程语言下Selenium 鼠标悬停以及右击操作
// 基于Actions类创建一个对象 Actions action = new Actions(driver); // 鼠标悬停在药渡公司全称字段上 action.moveToElement(Yao ...
- Python--简单接口测试实例(一)
适用人员:初学python的测试人员,若对抓包不太清楚的可先学习抓包的知识 接口测试流程:发送请求-->返回响应-->结果判定-->生成报告 案例:下面以[今目标]新建客户为例来进行 ...