第一章 作业背景
1.1 作业要求
编程实现一个多面体的旋转。在多面体的旋转过程中,对于不可见的线,用虚线表示;对于可见的线,用实线表示。
1.2 开发技术
本次作业采用前端技术实现,主要有:html、css、css3、javascript、Jquery。其中,html作为页面显示的骨架,css用来渲染页面样式、绘制立体图形,css3控制图形旋转等相关参数,javascript作为脚本语言来显式的操作页面各个dom的css样式,Jquery是javascript的框架,实现跨浏览器的js编写。
1.3 实现思路
①绘制6个正方形,利用css3把它们拼成一个立方体;
②使用css3的动画功能,设置立方体旋转;
③使用Jquery,读取立方体旋转的角度,当角度在一定阈值的时候,显式地控制立方体地12条边变为虚线或者变为实线。
第二章 代码实现
2.1 绘制立方体
首先,编写html代码,绘制立方体的6个面:
<div class="box"> <ul> <li id="panel_1">1</li> <li id="panel_2">2</li> <li id="panel_3">3</li> <li id="panel_4">4</li> <li id="panel_5">5</li> <li id="panel_6">6</li> </ul> </div>
代码块2-1 立方体html代码
之后,加上css的样式,对每个面进行一定量的偏移。此处需要数学的3D几何基础,计算每个面在X方向、Y方向、Z方向的偏移量,css代码如下:
*{margin: o;padding: 0;} body{background: white;} .box{ width: 400px; height: 400px; margin: 200px auto; perspective: 1000px; } .box ul{ width: 300px; height: 300px; margin: 48px; position:relative; transform-style: preserve-3d; animation: move 20s infinite linear; transform-origin:center center 150px ; } .box ul li{ width: 300px; height: 300px; list-style: none; font-size: 20px; color: #000; text-align: center; line-height: 300px; position: absolute; } .box ul li:nth-of-type(2){ transform:translateX(300px) rotateY(-90deg) ;transform-origin: left;} .box ul li:nth-of-type(3){ transform:translateX(-300px) rotateY(90deg);transform-origin: right;} .box ul li:nth-of-type(4){ transform: translateY(-300px) rotateX(-90deg);transform-origin:bottom;} .box ul li:nth-of-type(5){ transform: translateY(300px) rotateX(90deg);transform-origin:top;} .box ul li:nth-of-type(6){ transform: translateZ(300px);}
代码块2-2 立方体css代码
最终立方体的效果图,如下所示:
图2-1 立方体静态效果
2.2 使立方体旋转
图2-1的立方体只是静态的,我们使用css3的动画控制,使得立方体的6个面绕Y轴转动。代码如下:
@keyframes move{ from{transform:rotateY(0deg);} to{transform: rotateY(360deg);} }
代码块2-3 立方体css3代码
旋转后的gif效果图如下:
图2-2 立方体旋转效果
2.3 实线虚线切换
图2-2的立方体中,所有的线都是实线,我们需要当立方体的边不可见时,把边变成虚线,可见时再变成实线。这里使用了Jquery,判断每个的旋转角度,当某个面旋转的角度大于0或者小于0时,表示这个面可见或者不可见,往往这个时候又伴随着某线边的可见与不可见,于是写下JS代码如下:
setInterval( ()=>{ var deg_2 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[2]) var deg_3 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[8]) var deg_6 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[10]) // 面3不可见时 if(deg_3 <= 0){ /***面2可见***/ // 面2上下变实线 $("li").eq(1).css('borderTop','2px solid black') $("li").eq(1).css('borderBottom','2px solid black') // 面3上下变虚线 $("li").eq(2).css('borderTop','2px dashed black') $("li").eq(2).css('borderBottom','2px dashed black') // 面2可见时,面36之间线不可见 $("li").eq(5).css('borderLeft','2px dashed black') }else{ /***面3可见***/ // 面3上下变实线 $("li").eq(2).css('borderTop','2px solid black') $("li").eq(2).css('borderBottom','2px solid black') // 面2上下变虚线 $("li").eq(1).css('borderTop','2px dashed black') $("li").eq(1).css('borderBottom','2px dashed black') // 面3可见时,面12之间线不可见 $("li").eq(0).css('borderRight','2px dashed black') } if(deg_6 <= 0){ /***面1可见***/ // 面1上下变实线 $("li").eq(0).css('borderTop','2px solid black') $("li").eq(0).css('borderBottom','2px solid black') // 面6上下变虚线 $("li").eq(5).css('borderTop','2px dashed black') $("li").eq(5).css('borderBottom','2px dashed black') // 面1可见时,面12之间线可见 $("li").eq(0).css('borderRight','2px solid black') // 面2可见时,26线可见 $("li").eq(5).css('borderRight','2px dashed black') }else{ /***面6可见***/ // 面1上下变虚线 $("li").eq(0).css('borderTop','2px dashed black') $("li").eq(0).css('borderBottom','2px dashed black') // 面6上下变实现 $("li").eq(5).css('borderTop','2px solid black') $("li").eq(5).css('borderBottom','2px solid black') // 面6可见时,面36之间线可见 $("li").eq(5).css('borderLeft','2px solid black') // 面3可见时,13线可见 $("li").eq(2).css('borderRight','2px dashed black') } if(deg_2<=0){ // 面3可见时,13线可见 $("li").eq(2).css('borderRight','2px solid black') }else{ // 面2可见时,26线可见 $("li").eq(5).css('borderRight','2px solid black') } },20)
代码块2-4 立方体边虚实JS代码
此时,效果图如下:
图2-3 立方体最终旋转效果
2.4 动态切换视角
图2-3的立方体是在一定视角下来观看的,我们添加一个切换视点的函数,如下:
var per = 1000 ; $(document).mousewheel(function(event) { if(event.deltaY < 0 ){ per = per >= 2000 ? 2000 : per+100 }else{ per = per <= 300 ? 300 : per-100 } $('.box').css('perspective', per + 'px') console.log(per) });
代码块2-5 立方体切换视角代码
当鼠标滚轮上下滑动时,可以拉近或者拉远视点。
第三章 总结
作业实现起来难度较大,如果掌握一定的专业工具实现起来的效果、效率都会很高,用前端网页只能实现一些简单的功能。
掌握一些制作游戏的引擎、开发工具、概念应该很容易去做,耳熟能详的有UE4、Unity、光追、光捕、粒子等等。
在读研究生选方向前,我也有一腔热血,想投身于计算机图形学。凭什么电影《哪吒》的画质效果比不过皮克斯、迪士尼,为什么中国做不出属于自己的特效呢?后来才发现这条路太难走了,家里条件也不支持,最终妥协,选了NLP作为科研方向。
附代码及使用方式
总共有三个文件,一个index.html,一个jquery-3.3.1.min.js,一个jquery.mousewheel.min.js。后两个js文件网上自行下载,很容易找,下面附上index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>立方体</title> <style> *{margin: o;padding: 0;} body{background: white;} .box{ width: 400px; height: 400px; margin: 200px auto; perspective: 1000px; } .box ul{ width: 300px; height: 300px; margin: 48px; position:relative; transform-style: preserve-3d; animation: move 20s infinite linear; transform-origin:center center 150px ; } .box ul li{ width: 300px; height: 300px; list-style: none; font-size: 20px; color: #000; text-align: center; line-height: 300px; position: absolute; } .box ul li:nth-of-type(2){ transform:translateX(300px) rotateY(-90deg) ;transform-origin: left;} .box ul li:nth-of-type(3){ transform:translateX(-300px) rotateY(90deg);transform-origin: right;} .box ul li:nth-of-type(4){ transform: translateY(-300px) rotateX(-90deg);transform-origin:bottom;} .box ul li:nth-of-type(5){ transform: translateY(300px) rotateX(90deg);transform-origin:top;} .box ul li:nth-of-type(6){ transform: translateZ(300px);} @keyframes move{ from{transform:rotateY(0deg);} to{transform: rotateY(360deg);} } </style> </head> <body> <div class="box"> <ul> <li id="panel_1">1</li> <li id="panel_2">2</li> <li id="panel_3">3</li> <li id="panel_4">4</li> <li id="panel_5">5</li> <li id="panel_6">6</li> </ul> </div> </body> <script src="./jquery-3.3.1.min.js"></script> <script src="./jquery.mousewheel.min.js"></script> <script> /** * 6与1相对,2与3相对 * deg_2 第2面:为正可见, 为负不可见 * deg_3 第3面:为正可见, 为负不可见 * deg_6 第6面:为正可见, 为负不可见 * * 当1个面可见时,这个面的右边框可见,为实线 **/ setInterval( ()=>{ var deg_2 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[2]) var deg_3 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[8]) var deg_6 = parseFloat($("ul").css("transform").replace(/[^0-9\-.,]/g,'').split(',')[10]) // 面3不可见时 if(deg_3 <= 0){ /***面2可见***/ // 面2上下变实线 $("li").eq(1).css('borderTop','2px solid black') $("li").eq(1).css('borderBottom','2px solid black') // 面3上下变虚线 $("li").eq(2).css('borderTop','2px dashed black') $("li").eq(2).css('borderBottom','2px dashed black') // 面2可见时,面36之间线不可见 $("li").eq(5).css('borderLeft','2px dashed black') }else{ /***面3可见***/ // 面3上下变实线 $("li").eq(2).css('borderTop','2px solid black') $("li").eq(2).css('borderBottom','2px solid black') // 面2上下变虚线 $("li").eq(1).css('borderTop','2px dashed black') $("li").eq(1).css('borderBottom','2px dashed black') // 面3可见时,面12之间线不可见 $("li").eq(0).css('borderRight','2px dashed black') } if(deg_6 <= 0){ /***面1可见***/ // 面1上下变实线 $("li").eq(0).css('borderTop','2px solid black') $("li").eq(0).css('borderBottom','2px solid black') // 面6上下变虚线 $("li").eq(5).css('borderTop','2px dashed black') $("li").eq(5).css('borderBottom','2px dashed black') // 面1可见时,面12之间线可见 $("li").eq(0).css('borderRight','2px solid black') // 面2可见时,26线可见 $("li").eq(5).css('borderRight','2px dashed black') }else{ /***面6可见***/ // 面1上下变虚线 $("li").eq(0).css('borderTop','2px dashed black') $("li").eq(0).css('borderBottom','2px dashed black') // 面6上下变实现 $("li").eq(5).css('borderTop','2px solid black') $("li").eq(5).css('borderBottom','2px solid black') // 面6可见时,面36之间线可见 $("li").eq(5).css('borderLeft','2px solid black') // 面3可见时,13线可见 $("li").eq(2).css('borderRight','2px dashed black') } if(deg_2<=0){ // 面3可见时,13线可见 $("li").eq(2).css('borderRight','2px solid black') }else{ // 面2可见时,26线可见 $("li").eq(5).css('borderRight','2px solid black') } },20) var per = 1000 ; $(document).mousewheel(function(event) { if(event.deltaY < 0 ){ per = per >= 2000 ? 2000 : per+100 }else{ per = per <= 300 ? 300 : per-100 } $('.box').css('perspective', per + 'px') console.log(per) }); </script> </html>