欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-11-23 22:18:28
本篇文章主要介绍【HTML5】3D模型--百行代码实现旋转立体魔方实例,具有一定的参考价值,有需要的可以了解一下。... 16-12-16...

最近研究魔方的玩法,就突然想用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模型,希望对大家的学习有所帮助,也希望大家多多支持。