记录大学时代的一个实验demo
代码完全基于html、three.js实现
1. 实现效果演示:
2. 项目结构:
3. three.js需自行下载依赖包,index.html完整代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="js/three.js"></script> <!-- <script type="text/javascript" src="js/OrbitControls.js"></script> --> <style type="text/css"> body{ margin: 0; overflow: hidden; } </style> </head> <body onload="initThreeScene();"> <script> var width=window.innerWidth; var height=window.innerHeight; var camera; var renderer; var scene; var light,ambient; var cube=[];//立方体 var cube_to_rotate=[];//待旋转的立方体 var mesh=[];//立方体mesh var raycaster;//检测点击物体 var obj_click_pos=[];//被检测到的物体坐标 var startpoint=[],leavepoint=[];//鼠标点击与离开的点 var rotate=-1,direction=-1;//旋转方向 var x=[],y=[],z=[],x1=[],y1=[],z1=[];//相隔帧的position var axisX=[],axisY=[],axisZ=[];//调整坐标系 function initThreeScene(){ initScene(); initCube(); initLight(); initCamera(); initRender(); render(); initListener(); // var controls=new THREE.OrbitControls(camera); //controls.addListener("change",render); var axesHelper=new THREE.AxesHelper(250); scene.add(axesHelper); window.addEventListener("resize",function(){ width=window.innerWidth; height=window.innerHeight; renderer.setSize(width,height); camera.aspect=width/height; camera.updateProjectionMatrix(); },false); } function initScene(){ scene=new THREE.Scene(); } function initCamera(){ // var k=width/height; // var s=200; // camera=new THREE.OrthographicCamera(-s*k,s*k,s,-s,1,1000); camera = new THREE.PerspectiveCamera(50,width/height,1,1000); // camera.position.set(200,300,200); camera.position.set(300,260,300); camera.lookAt(scene.position); } function initRender(){ renderer=new THREE.WebGLRenderer(); renderer.setSize(width,height); renderer.setClearColor(0xb9d3ff,1); document.body.appendChild(renderer.domElement); } function initLight(){ light=new THREE.PointLight(0xffffff); light.position.set(400,200,300); ambient=new THREE.AmbientLight(0x555555); scene.add(light); scene.add(ambient); } function initCube(){ for(i=0;i<27;i++) cube[i]=new THREE.BoxGeometry(50,50,50); for(i=0;i<9;i++){ cube[i].faces[2].color.setHex(0xff0000); cube[i].faces[3].color.setHex(0xff0000); if(i%3==0){ cube[i].faces[10].color.setHex(0x00ff00); cube[i].faces[11].color.setHex(0x00ff00); } if(i%3==2){ cube[i].faces[8].color.setHex(0xffff00); cube[i].faces[9].color.setHex(0xffff00); } if(i>5){ cube[i].faces[4].color.setHex(0x0000ff); cube[i].faces[5].color.setHex(0x0000ff); } if(i<3){ cube[i].faces[6].color.setHex(0x00ffff); cube[i].faces[7].color.setHex(0x00ffff); } } for(i=9;i<18;i++){ if((i-9)%3==0){ cube[i].faces[10].color.setHex(0x00ff00); cube[i].faces[11].color.setHex(0x00ff00); } if((i-9)%3==2){ cube[i].faces[8].color.setHex(0xffff00); cube[i].faces[9].color.setHex(0xffff00); } if((i-9)>5){ cube[i].faces[4].color.setHex(0x0000ff); cube[i].faces[5].color.setHex(0x0000ff); } if((i-9)<3){ cube[i].faces[6].color.setHex(0x00ffff); cube[i].faces[7].color.setHex(0x00ffff); } } for(i=18;i<27;i++){ if((i-18)%3==0){ cube[i].faces[10].color.setHex(0x00ff00); cube[i].faces[11].color.setHex(0x00ff00); } if((i-18)%3==2){ cube[i].faces[8].color.setHex(0xffff00); cube[i].faces[9].color.setHex(0xffff00); } if((i-18)>5){ cube[i].faces[4].color.setHex(0x0000ff); cube[i].faces[5].color.setHex(0x0000ff); } if((i-18)<3){ cube[i].faces[6].color.setHex(0x00ffff); cube[i].faces[7].color.setHex(0x00ffff); } cube[i].faces[0].color.setHex(0xff00ff); cube[i].faces[1].color.setHex(0xff00ff); } for(i=0;i<27;i++){ var material=new THREE.MeshBasicMaterial({ vertexColors:THREE.FaceColors }); mesh[i] = new THREE.Mesh(cube[i],material); mesh[i].position.set((Math.floor(i/9)-1)*53,((Math.floor(i%9/3))-1)*53,(Math.floor(i%9%3)-1)*53); scene.add(mesh[i]); x[i]=mesh[i].position.x; y[i]=mesh[i].position.y; z[i]=mesh[i].position.z; axisX[i]=1; axisY[i]=2; axisZ[i]=3; } } var angle=0; function render(){ renderer.render(scene,camera); if(rotate==0||rotate==1){ var length=rotate==0?27:9; if(direction==0||direction==1){ var dir=(direction==0)?1:-1; var dir1; var pre; if(angle<=0.5){ angle+=0.01; for(i=0;i<length;i++){ pre=cube_to_rotate[i]; x1[pre]=Math.cos(dir*angle*Math.PI)*x[pre]-Math.sin(dir*angle*Math.PI)*z[pre]; z1[pre]=Math.cos(dir*angle*Math.PI)*z[pre]+Math.sin(dir*angle*Math.PI)*x[pre]; mesh[pre].position.set(x1[pre],mesh[pre].position.y,z1[pre]); dir1=(axisY[pre]>0)?1:-1; switch(Math.abs(axisY[pre])){ case 1: mesh[pre].rotateX(-0.01*dir*dir1*Math.PI); break; case 2: mesh[pre].rotateY(-0.01*dir*dir1*Math.PI); break; case 3: mesh[pre].rotateZ(-0.01*dir*dir1*Math.PI); break; } } }else{ reviseAxis(direction); direction=-1; rotate=-1; revisePosition(); angle=0; } }else if(direction==2||direction==3){ var dir=(direction==2)?-1:1; var dir1; var pre; if(angle<=0.5){ angle+=0.01; for(i=0;i<length;i++){ pre=cube_to_rotate[i]; y1[pre]=Math.cos(dir*angle*Math.PI)*y[pre]-Math.sin(dir*angle*Math.PI)*x[pre]; x1[pre]=Math.cos(dir*angle*Math.PI)*x[pre]+Math.sin(dir*angle*Math.PI)*y[pre]; mesh[pre].position.set(x1[pre],y1[pre],mesh[pre].position.z); dir1=(axisZ[pre]>0)?1:-1; switch(Math.abs(axisZ[pre])){ case 1: mesh[pre].rotateX(-0.01*dir*dir1*Math.PI); break; case 2: mesh[pre].rotateY(-0.01*dir*dir1*Math.PI); break; case 3: mesh[pre].rotateZ(-0.01*dir*dir1*Math.PI); break; } } }else{ reviseAxis(direction); direction=-1; rotate=-1; revisePosition(); angle=0; } }else if(direction==4||direction==5){ var dir=(direction==4)?-1:1; var dir1; var pre; if(angle<=0.5){ angle+=0.01; for(i=0;i<length;i++){ pre=cube_to_rotate[i]; z1[pre]=Math.cos(dir*angle*Math.PI)*z[pre]-Math.sin(dir*angle*Math.PI)*y[pre]; y1[pre]=Math.cos(dir*angle*Math.PI)*y[pre]+Math.sin(dir*angle*Math.PI)*z[pre]; mesh[pre].position.set(mesh[pre].position.x,y1[pre],z1[pre]); dir1=(axisX[pre]>0)?1:-1; switch(Math.abs(axisX[pre])){ case 1: mesh[pre].rotateX(-0.01*dir*dir1*Math.PI); break; case 2: mesh[pre].rotateY(-0.01*dir*dir1*Math.PI); break; case 3: mesh[pre].rotateZ(-0.01*dir*dir1*Math.PI); break; } } }else{ reviseAxis(direction); direction=-1; rotate=-1; revisePosition(); angle=0; } } } requestAnimationFrame(render); } function revisePosition(){ var x2,y2,z2; for(i=0;i<27;i++){ x2=Math.round(mesh[i].position.x/53)*53; y2=Math.round(mesh[i].position.y/53)*53; z2=Math.round(mesh[i].position.z/53)*53; x[i]=x2; y[i]=y2; z[i]=z2; mesh[i].position.set(x2,y2,z2); } } function reviseAxis(dir){ var temp; var pre; var length=rotate==0?27:9; switch(dir){ case 0://横左 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisX[pre]; axisX[pre]=-axisZ[pre]; axisZ[pre]=temp; } break; case 1://横右 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisX[pre]; axisX[pre]=axisZ[pre]; axisZ[pre]=-temp; } break; case 2://左上 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisX[pre]; axisX[pre]=-axisY[pre]; axisY[pre]=temp; } break; case 3://右下 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisX[pre]; axisX[pre]=axisY[pre]; axisY[pre]=-temp; } break; case 4://左下 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisZ[pre]; axisZ[pre]=axisY[pre]; axisY[pre]=-temp; } break; case 5://右上 for(i=0;i<length;i++){ pre=cube_to_rotate[i]; temp=axisZ[pre]; axisZ[pre]=-axisY[pre]; axisY[pre]=temp; } break; } } function initListener(){ raycaster=new THREE.Raycaster(); window.addEventListener("mousedown",mousedown); window.addEventListener("mouseup",mouseup); } function mousedown(e){ //将html坐标系转化为webgl坐标系,并确定鼠标点击位置 startpoint[0]=e.clientX; startpoint[1]=e.clientY; var clickPoint=new THREE.Vector2(); clickPoint.x = e.clientX / renderer.domElement.clientWidth*2-1; clickPoint.y = -(e.clientY / renderer.domElement.clientHeight*2)+1; raycaster.setFromCamera(clickPoint,camera); var intersects = raycaster.intersectObjects(scene.children); if(intersects.length==0){ if(rotate==-1) rotate=0; }else{ if(rotate==-1){ rotate=1; obj_click_pos[0]=intersects[0].object.position.x; obj_click_pos[1]=intersects[0].object.position.y; obj_click_pos[2]=intersects[0].object.position.z; } } } function mouseup(e){ leavepoint[0]=e.clientX; leavepoint[1]=e.clientY; var x=leavepoint[0]-startpoint[0]; var y=leavepoint[1]-startpoint[1]; if((rotate==0||rotate==1)&&direction==-1){ if(Math.abs(x)>50||Math.abs(y)>50){ if(rotate==0) for(i=0;i<27;i++){ cube_to_rotate[i]=i; } if(Math.abs(x)<Math.abs(y)){ if(x<0){ if(y<0){//>>左上direction=2,绕z轴旋转 if(rotate==1){ var j=0; for(i=0;i<27;i++){ if(mesh[i].position.z==obj_click_pos[2]){ cube_to_rotate[j]=i; j++; } } } direction=2; }else{//>>左下direction=4,绕x轴旋转 if(rotate==1){ var j=0; for(i=0;i<27;i++){ if(mesh[i].position.x==obj_click_pos[0]){ cube_to_rotate[j]=i; j++; } } } direction=4; } }else{ if(y>0){//右下>>direction=3,绕z轴旋转 if(rotate==1){ var j=0; for(i=0;i<27;i++){ if(mesh[i].position.z==obj_click_pos[2]){ cube_to_rotate[j]=i; j++; } } } direction=3; }else{//右上>>direction=5,绕x轴旋转 if(rotate==1){ var j=0; for(i=0;i<27;i++){ if(mesh[i].position.x==obj_click_pos[0]){ cube_to_rotate[j]=i; j++; } } } direction=5; } } }else{//绕y轴旋转 if(rotate==1){ var j=0; for(i=0;i<27;i++){ if(mesh[i].position.y==obj_click_pos[1]){ cube_to_rotate[j]=i; j++; } } } if(x<0){//横左>>direction=0 direction=0; }else{//横右>>direction=1 direction=1; } } } } } </script> </body> </html>