zl程序教程

您现在的位置是:首页 >  其他

当前栏目

【计算机图形学】六面体旋转并实时切换虚线实线 - 代码实现

2023-03-14 22:52:09 时间

第一章 作业背景


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代码

  最终立方体的效果图,如下所示:

image.png

  图2-1 立方体静态效果

2.2 使立方体旋转


  图2-1的立方体只是静态的,我们使用css3的动画控制,使得立方体的6个面绕Y轴转动。代码如下:

@keyframes move{
    from{transform:rotateY(0deg);}
    to{transform: rotateY(360deg);}
}

  代码块2-3 立方体css3代码

  旋转后的gif效果图如下:

c418d13475e14bbcba859f7605d604b3.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代码

  此时,效果图如下:

image.gif

  图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>