【HTML5】3D模型--百行代码实现旋转立体魔方实例


Posted in HTML / CSS onDecember 16, 2016

最近研究魔方的玩法,就突然想用HMTL5写一个魔方的模型,由于魔方是一个3D的立方体,这次就试着用HTML5写了一个简单的3D模型。

下面是预览画面。

【HTML5】3D模型--百行代码实现旋转立体魔方实例

制作流程

首先你需要下载Html5开源库件lufylegend-1.4.0

魔方分为6个面,每个面由9个小矩形组成,现在我把每个小矩形当做一个类封装起来,

因为现在建立的是一个3D魔方,所以要画出每个小矩形,需要知道小矩形的4个定点,而这4个定点会根据空间的旋转角度而变换,所以为了计算出这4个定点坐标,需要知道魔方绕x轴和z轴旋转的角度。

所以,建立矩形类如下

function Rect(pointA,pointB,pointC,pointD,angleX,angleZ,color){  
    base(this,LSprite,[]);  
    this.pointZ=[(pointA[0]+pointB[0]+pointC[0]+pointD[0])/4,(pointA[1]+pointB[1]+pointC[1]+pointD[1])/4,(pointA[2]+pointB[2]+pointC[2]+pointD[2])/4];  
    this.z = this.pointZ[2];  
    this.pointA=pointA,this.pointB=pointB,this.pointC=pointC,this.pointD=pointD,this.angleX=angleX,this.angleZ=angleZ,this.color=color;  
}  
  
Rect.prototype.setAngle = function(a,b){  
    this.angleX = a;  
    this.angleZ = b;  
    this.z=this.getPoint(this.pointZ)[2];  
};

pointA,pointB,pointC,pointD是小矩形的四个顶点,angleX,angleZ分别是x轴和z轴旋转的角度,color是小矩形的颜色。

魔方分为6个面,先看一下最前面的一面,如果以立方体的中心作为3D坐标系的中心,那么9个小矩形的各个定点所对应的坐标如下图所示

【HTML5】3D模型--百行代码实现旋转立体魔方实例

所以,前面这个面的9个小矩形可以由下面的代码来建立

for(var x=0;x<3;x++){  
    for(var y=0;y<3;y++){  
        z = 3;  
        var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-step + y*2*step,-3*step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-3*step + z*2*step],0,0,"#FF0000");  
        backLayer.addChild(rect);  
    }  
}

其中backLayer是一个LSprite类,step是半个小矩形的长,同样的道理,可以也得到其他5个面。

6个面都建立了,在绘制这6个面之前,首先要根据旋转的角度来计算各个定点的坐标,看下面的图

【HTML5】3D模型--百行代码实现旋转立体魔方实例

根据上面的图,用下面的公式即可得到变换后的定点坐标

Rect.prototype.getPoint = function(p){  
    var u2,v2,w2,u=p[0],v=p[1],w=p[2];  
    u2 = u * Math.cos(this.angleX) - v * Math.sin(this.angleX);  
    v2 = u * Math.sin(this.angleX) + v * Math.cos(this.angleX);  
    w2 = w;  
    u = u2; v = v2; w = w2;  
    u2 = u;  
    v2 = v * Math.cos(this.angleZ) - w * Math.sin(this.angleZ);  
    w2 = v * Math.sin(this.angleZ) + w * Math.cos(this.angleZ);  
    u = u2; v = v2; w = w2;  
    return [u2,v2,w2];  
};

最后根据小矩形的四个定点坐标,来绘制这个矩形,

Rect.prototype.draw = function(layer){  
    this.graphics.clear();  
    this.graphics.drawVertices(1,"#000000",[this.getPoint(this.pointA),this.getPoint(this.pointB),this.getPoint(this.pointC),this.getPoint(this.pointD)],true,this.color);  
};

其中drawVertices是lufylegend.js库件中LGraphics类的一个方法,它可以根据传入的定点坐标数组来绘制一个多边形。

最后,给出完整代码,代码很少,JS代码一共91行。

一,index.html

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title>3D魔方</title>  
</head>  
<body>  
<div id="mylegend">loading……</div>  
<script type="text/javascript" src="../lufylegend-1.4.0.min.js"></script>   
<script type="text/javascript" src="./Main.js"></script>   
<script type="text/javascript" src="./Rect.js"></script>   
</body>  
</html>

二,Rect类

function Rect(pointA,pointB,pointC,pointD,angleX,angleZ,color){  
    base(this,LSprite,[]);  
    this.pointZ=[(pointA[0]+pointB[0]+pointC[0]+pointD[0])/4,(pointA[1]+pointB[1]+pointC[1]+pointD[1])/4,(pointA[2]+pointB[2]+pointC[2]+pointD[2])/4];  
    this.z = this.pointZ[2];  
    this.pointA=pointA,this.pointB=pointB,this.pointC=pointC,this.pointD=pointD,this.angleX=angleX,this.angleZ=angleZ,this.color=color;  
}  
Rect.prototype.draw = function(layer){  
    this.graphics.clear();  
    this.graphics.drawVertices(1,"#000000",[this.getPoint(this.pointA),this.getPoint(this.pointB),this.getPoint(this.pointC),this.getPoint(this.pointD)],true,this.color);  
};  
Rect.prototype.setAngle = function(a,b){  
    this.angleX = a;  
    this.angleZ = b;  
    this.z=this.getPoint(this.pointZ)[2];  
};  
Rect.prototype.getPoint = function(p){  
    var u2,v2,w2,u=p[0],v=p[1],w=p[2];  
    u2 = u * Math.cos(this.angleX) - v * Math.sin(this.angleX);  
    v2 = u * Math.sin(this.angleX) + v * Math.cos(this.angleX);  
    w2 = w;  
    u = u2; v = v2; w = w2;  
    u2 = u;  
    v2 = v * Math.cos(this.angleZ) - w * Math.sin(this.angleZ);  
    w2 = v * Math.sin(this.angleZ) + w * Math.cos(this.angleZ);  
    u = u2; v = v2; w = w2;  
    return [u2,v2,w2];  
};

三,Main.js

init(50,"mylegend",400,400,main);  
var a = 0,b=0,backLayer,step = 20,key = null;  
function main(){  
    backLayer = new LSprite();  
    addChild(backLayer);  
    backLayer.x = 120,backLayer.y = 120;  
    //后  
    for(var x=0;x<3;x++){  
        for(var y=0;y<3;y++){  
            z = 0;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-step + y*2*step,-3*step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-3*step + z*2*step],0,0,"#FF4500");  
            backLayer.addChild(rect);  
        }  
    }  
    //前  
    for(var x=0;x<3;x++){  
        for(var y=0;y<3;y++){  
            z = 3;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-step + y*2*step,-3*step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-3*step + z*2*step],0,0,"#FF0000");  
            backLayer.addChild(rect);  
        }  
    }  
    //上  
    for(var x=0;x<3;x++){  
        for(var z=0;z<3;z++){  
            y = 0;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-3*step + y*2*step,-step + z*2*step],0,0,"#FFFFFF");  
            backLayer.addChild(rect);  
        }  
    }  
    //下  
    for(var x=0;x<3;x++){  
        for(var z=0;z<3;z++){  
            y = 3;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-step + x*2*step,-3*step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-3*step + y*2*step,-step + z*2*step],0,0,"#FFFF00");  
            backLayer.addChild(rect);  
        }  
    }  
    //左  
    for(var y=0;y<3;y++){  
        for(var z=0;z<3;z++){  
            x = 0;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-3*step + x*2*step,-3*step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-3*step + z*2*step],0,0,"#008000");  
            backLayer.addChild(rect);  
        }  
    }  
    //右  
    for(var y=0;y<3;y++){  
        for(var z=0;z<3;z++){  
            x = 3;  
            var rect = new Rect([-3*step + x*2*step,-3*step + y*2*step,-3*step + z*2*step],[-3*step + x*2*step,-3*step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-step + z*2*step],[-3*step + x*2*step,-step + y*2*step,-3*step + z*2*step],0,0,"#0000FF");  
            backLayer.addChild(rect);  
        }  
    }  
    backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);  
}  
function onframe(){  
    a += 0.1 , b += 0.1;  
    backLayer.childList = backLayer.childList.sort(function(a,b){return a.z - b.z;});  
    for(key in backLayer.childList){  
        backLayer.childList[key].setAngle(a,b);  
        backLayer.childList[key].draw(backLayer);  
   }  
}

这只是一个非常简陋的3D模型,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
灵活运用CSS3特性绘制简易版围棋效果
Sep 28 HTML / CSS
css3.0 图形构成实例练习二
Mar 19 HTML / CSS
纯css3实现的鼠标悬停动画按钮
Dec 23 HTML / CSS
值得收藏的HTML5资源(学习html5的朋友可以收藏下)
Jul 20 HTML / CSS
Html5游戏开发之乒乓Ping Pong游戏示例(二)
Jan 21 HTML / CSS
html5 的a标签 Href 拨电话的写法
Nov 04 HTML / CSS
html5定位获取当前位置并在百度地图上显示
Aug 22 HTML / CSS
HTML5拖放API实现拖放排序的实例代码
May 11 HTML / CSS
html5使用Drag事件编辑器拖拽上传图片的示例代码
Aug 22 HTML / CSS
HTML5 Canvas实现放大镜效果示例
Mar 25 HTML / CSS
canvas实现滑动验证的实现示例
Aug 11 HTML / CSS
Html5移动端网页端适配(js+rem)
Feb 03 HTML / CSS
使用spring mvc+localResizeIMG实现HTML5端图片压缩上传的功能
Dec 16 #HTML / CSS
详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)
Dec 15 #HTML / CSS
canvas与html5实现视频截图功能示例
Dec 15 #HTML / CSS
详解html5 canvas常用api总结(二)--绘图API
Dec 14 #HTML / CSS
HTML5 Canvas玩转酷炫大波浪进度图效果实例(附demo)
Dec 14 #HTML / CSS
详解使用HTML5 Canvas创建动态粒子网格动画
Dec 14 #HTML / CSS
H5新属性audio音频和video视频的控制详解(推荐)
Dec 09 #HTML / CSS
You might like
提高PHP编程效率的53个要点(经验小结)
2010/09/04 PHP
php+mysql数据库实现无限分类的方法
2014/12/12 PHP
Symfony2开发之控制器用法实例分析
2016/02/05 PHP
PHP+MySQL使用mysql_num_rows实现模糊查询图书信息功能
2018/05/31 PHP
使用ucenter实现多站点同步登录的讲解
2019/03/21 PHP
用JavaScript实现单继承和多继承的简单方法
2009/03/29 Javascript
jQuery EasyUI API 中文文档 - DataGrid数据表格
2011/11/17 Javascript
jquery DIV撑大让滚动条滚到最底部代码
2013/06/06 Javascript
jquery 获取 outerHtml 包含当前节点本身的代码
2014/10/30 Javascript
微信小程序 获取相册照片实例详解
2016/11/16 Javascript
JavaScript制作弹出层效果
2016/12/02 Javascript
JQuery Ajax 异步操作之动态添加节点功能
2017/05/24 jQuery
Javascript别踩白块儿(钢琴块儿)小游戏实现代码
2017/07/20 Javascript
vue.js路由跳转详解
2017/08/28 Javascript
动态Axios的配置步骤详解
2018/01/12 Javascript
vue移动端下拉刷新和上拉加载的实现代码
2018/09/08 Javascript
NodeJS 实现多语言的示例代码
2018/09/11 NodeJs
关于ckeditor在bootstrap中modal中弹框无法输入的解决方法
2019/09/11 Javascript
Javascript模拟实现new原理解析
2020/03/03 Javascript
微信小程序多列表渲染数据开关互不影响的实现
2020/06/05 Javascript
Python中用format函数格式化字符串的用法
2015/04/08 Python
详解将Django部署到Centos7全攻略
2018/09/26 Python
PyQt弹出式对话框的常用方法及标准按钮类型
2019/02/27 Python
Python pyautogui模块实现鼠标键盘自动化方法详解
2020/02/17 Python
Django {{ MEDIA_URL }}无法显示图片的解决方式
2020/04/07 Python
Spark处理数据排序问题如何避免OOM
2020/05/21 Python
CSS3中的content属性使用示例
2015/07/20 HTML / CSS
意大利领先的奢侈品在线时装零售商:MCLABELS
2020/10/13 全球购物
职工趣味运动会方案
2014/02/10 职场文书
委托书范文
2014/04/02 职场文书
房地产销售经理岗位职责
2015/02/02 职场文书
总经理岗位职责
2015/02/04 职场文书
高中生打架检讨书1000字
2015/02/17 职场文书
2016春季运动会通讯稿
2015/07/18 职场文书
深入理解java.lang.String类的不可变性
2021/06/27 Java/Android
Python中Schedule模块使用详解 周期任务神器
2022/04/19 Python