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 模型列表贴图
少量图片对于我们赋值是没有什么难度,但是如果图片的量大的话,我们肯定希望能很直接地显示在界面上供我们使用,再就是排放的位置等等,这些都需要比较直观的操作,在实际应用中会让我们省很多力以及时间.下面这个 ...
随机推荐
- Palette状态栏颜色提取,写的不错就分享了
Palette 说Palette之前先说下前面提到的Pager.ViewPager是什么大家应该都是知道的了,一般ViewPager.xxxTabStrip.Fragment三个好基友是一起出现的.这 ...
- 菜鸟玩云计算之十七:RHEL克隆虚拟机后改变网卡地址
菜鸟玩云计算之十七:RHEL克隆虚拟机后改变网卡地址 (一)更改hostname # vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=your-vm ...
- WinCE上BINFS实现详解
网上不少介绍三星24x0系列的BINFS启动方式实现,有些内容上描述的不是非常全面 下面就WinCE6上的BINFS实现,从基本原理到修改BSP,再到如何烧录启动做一个较全面的讲解 一 BINFS到底 ...
- WinCE系统声音定制
作者:ARM-WinCE 2010的第一篇Blog,介绍一下WinCE系统声音的定制.说白了,就是设置注册表.WinCE系统启动的开机音乐,点击触摸屏以及键盘输入的按键音,还有系统运行过程中的各种声音 ...
- ZooKeeper leader election
Paxos是分布式应用中解决同步问题的核心.作为应用研发工程师,我们总是倾向于使用一种相对简洁的方式实现复杂的算法.ZooKeeper leader election实现就是一个非常好的参考. 其实现 ...
- objective-c随机数+日期格式显示一例
在原来的代码上有修改,主要为: 将准备随机数方法放到了init中,这样不用手动调用了 setWeek方法已经过时,使用的是setWeekOfYear方法 在此放一份以备以后查找: le.h // // ...
- leetCode(66)-Excel Sheet Column Title
题目: Given a positive integer, return its corresponding column title as appear in an Excel sheet. For ...
- 树的广度优先遍历和深度优先遍历(递归非递归、Java实现)
在编程生活中,我们总会遇见树性结构,这几天刚好需要对树形结构操作,就记录下自己的操作方式以及过程.现在假设有一颗这样树,(是不是二叉树都没关系,原理都是一样的) 1.广度优先遍历 英文缩写为BFS即B ...
- 手动编译Flume
1.源码下载: 我用的是1.6版,因为加了kafka-sink,下载地址 http://www.apache.org/dyn/closer.cgi/flume/1.6.0/apache-flume-1 ...
- PhpStudy如何开启Apache的gzip压缩功能?
要让apache支持gzip功能,要用到deflate_Module和headers_Module. 打开apache的配置文件httpd.conf,大约在105行左右,找到以下两行内容:(这两行不是 ...