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

【计算机图形学】结课大作业——三维场景变换(ASCII表)

程序员文章站 2022-03-22 10:12:31
效果 >_<技术栈经典三剑客——HTML / CSS / JavaScriptWebGL快速开发:Three.js思路分析▶ 变量声明var table——列表,存放ASCII码表及其信息var scene, camera, renderer——场景、相机、渲染器var controls——控件var objects = []——objects[]集合是ascii码图形的集合,记录着3D排列方式var target...

效果 >_<

【计算机图形学】结课大作业——三维场景变换(ASCII表)

 
 

技术栈

  1. 【前端】HTML / CSS / JavaScript
  2. 【图形学】WebGL / Three.js
     
     

思路

three.js开发一般是比较套路的——init() + animate()

  1. init()时把所有的场景摆放好
  2. animate()就是一个递归调用的渲染过程。
     

如何实现ASCII码图形的静态排列和动态变化?

  1. 一次遍历初始化128个element元素对象,紧接着使用Three.js将其THREE成3D对象——这样,我们首先得到了128个3D对象(object)
  2. 这些3D对象的空间位置(position)都是可以设置的,这也是我们得以排列出这些奇妙图形的关键——这些位置信息用一个大小128的列表容器objects[]装起来——一种图形排列就完成了
  3. 接着我们初始化出许许多多个这样的容器,每个容器对应一种3D排列图形(可以用数学表达式、也可以将元素直接贴到某个大的3D图形上)——table、sphere、broken、shuffle…
  4. 接下来一个至关重要的问题是,如何实现3D图形排列的变换?这里我们使用Three.js提供的一个渐变类THREE.Tween——轻易实现了非常丝滑的变换效果!

 
 

代码结构

变量声明

var table 列表,存放ASCII码表及其信息
var scene, camera, renderer 场景、相机、渲染器
var controls 控件
var objects = [] 装有128个3D元素的容器
var targets = { table: [], sphere: [], ... } 许许多多种3D图形排列方式

初始化

initSCRC(); 初始化场景、相机、渲染器、控件
initFirst(); 初始化128个元素,THREE成3D对象,装进容器;并进行第一次的展示
initGraph(); 初始化各种3D图形排列
initButton(); 初始化按钮,为每个按钮绑定一个事件(一种3D图形排列)
initOthers(); 初始化其他杂事

关键函数

init(){...} 初始化
function transform(targets, duration){...} 图形转换
function animate(){...} 动画递归
unction render(){...} 渲染

 
 

完整代码

代码可直接运行。结构非常清晰。注释非常非常非常详细。

▽▽▽ ascii.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <title>Ascii&Animate</title>
    <link rel="stylesheet" type="text/css" href="acsii.css" />
    <script src="loli/three.js"></script>
    <script src="loli/CSS3DRenderer.js"></script>
    <script src="loli/TrackballControls.js"></script>
    <script src="loli/tween.min.js"></script>
    <script src="ascii.js"></script>
</head>

<body>
    <div id="container"></div>
    <div id="menu">
        <!-- <button id="auto">AUTO</button> -->
        <button id="table">TABLE</button>
        <button id="sphere">SPHERE</button>
        <button id="helix">HELIX</button>
        <button id="grid">GRID</button>
        <button id="broken">BROKEN</button>
        <button id="shuffle">SHUFFLE</button>
        <button id="gather">GATHER</button>
        <button id="boom">BOOM</button>
    </div>
    <script>
        init();
        animate();
    </script>
</body>

</html>

▽▽▽ ascii.css

html,
body {
    height: 100%;
}

body {
    background-color: #000000;
    margin: 0;
    font-family: Helvetica, sans-serif;
    overflow: hidden;
}

#menu {
    position: absolute;
    bottom: 20px;
    width: 100%;
    text-align: center;
}

.element {
    width: 120px;
    height: 160px;
    box-shadow: 0px 0px 12px rgba(0, 255, 255, 0.5);
    border: 1px solid rgba(127, 255, 255, 0.25);
    text-align: center;
    cursor: default;
}

.element:hover {
    box-shadow: 0px 0px 12px rgba(0, 255, 255, 0.75);
    border: 1px solid rgba(127, 255, 255, 0.75);
}

.element .number {
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: 12px;
    font-weight: bold;
    color: rgba(255, 255, 255, 0.75);
}

.element .symbol {
    position: absolute;
    top: 45px;
    left: 0;
    right: 0;
    font-size: 50px;
    font-weight: bold;
    color: rgba(255, 255, 255, 0.75);
    text-shadow: 0 0 10px rgba(0, 255, 255, 0.95);
}

.element .details {
    position: absolute;
    bottom: 15px;
    left: 0;
    right: 0;
    font-size: 12px;
    color: rgba(127, 255, 255, 0.75);
}

button {
    color: rgba(127, 255, 255, 0.75);
    background: transparent;
    outline: 1px solid rgba(127, 255, 255, 0.75);
    border: 0;
    padding: 5px 10px;
    cursor: pointer;
}

button:hover {
    background-color: rgba(0, 255, 255, 0.5);
}

button:active {
    background-color: rgba(0, 255, 255, 0.75);
}

▽▽▽ ascii.js

// ascii要展示的信息————符号、16进制、二进制
var table = [
    "NUL", "00", "00000000", 1, 1,
    "SOH", "01", "00000001", 2, 1,
    "STX", "02", "00000010", 3, 1,
    "ETX", "03", "00000011", 4, 1,
    "EOT", "04", "00000100", 5, 1,
    "ENQ", "05", "00000101", 6, 1,
    "ACK", "06", "00000110", 7, 1,
    "BEL", "07", "00000111", 8, 1,
    "BS", "08", "00001000", 9, 1,
    "HT", "09", "00001001", 10, 1,
    "LF", "0A", "00001010", 11, 1,
    "VT", "0B", "00001011", 12, 1,
    "FF", "0C", "00001100", 13, 1,
    "CR", "0D", "00001101", 14, 1,
    "SO", "0E", "00001110", 15, 1,
    "SI", "0F", "00001111", 16, 1,
    "DLE", "10", "00010000", 17, 1,
    "DCI", "11", "00010001", 18, 1,
    "DC2", "12", "00010010", 1, 2,
    "DC3", "13", "00010011", 2, 2,
    "DC4", "14", "00010100", 3, 2,
    "NAK", "15", "00010101", 4, 2,
    "SYN", "16", "00010110", 5, 2,
    "TB", "17", "00010111", 6, 2,
    "CAN", "18", "00011000", 7, 2,
    "EM", "19", "00011001", 8, 2,
    "SUB", "1A", "00011010", 9, 2,
    "ESC", "1B", "00011011", 10, 2,
    "FS", "1C", "00011100", 11, 2,
    "GS", "1D", "00011101", 12, 2,
    "RS", "1E", "00011110", 13, 2,
    "US", "1F", "00011111", 14, 2,
    "spa", "20", "00100000", 15, 2,
    "!", "21", "00100001", 16, 2,
    '"', "22", "00100010", 17, 2,
    "#", "23", "00100011", 18, 2,
    "$", "24", "00100100", 1, 3,
    "%", "25", "00100101", 2, 3,
    "&", "26", "00100110", 3, 3,
    "'", "27", "00100111", 4, 3,
    "(", "28", "00101000", 5, 3,
    ")", "29", "00101001", 6, 3,
    "*", "2A", "00101010", 7, 3,
    "+", "2B", "00101011", 8, 3,
    ",", "2C", "00101100", 9, 3,
    "-", "2D", "00101101", 10, 3,
    ".", "2E", "00101110", 11, 3,
    "/", "2F", "00101111", 12, 3,
    "0", "30", "00110000", 13, 3,
    "1", "31", "00110001", 14, 3,
    "2", "32", "00110010", 15, 3,
    "3", "33", "00110011", 16, 3,
    "4", "34", "00110100", 17, 3,
    "5", "35", "00110101", 18, 3,
    "6", "36", "00110110", 1, 4,
    "7", "37", "00110111", 2, 4,
    "8", "38", "00111000", 3, 4,
    "9", "39", "00111001", 4, 4,
    ":", "3A", "00111010", 5, 4,
    ";", "3B", "00111011", 6, 4,
    "<", "3C", "00111100", 7, 4,
    "=", "3D", "00111101", 8, 4,
    ">", "3E", "00111110", 9, 4,
    "?", "3F", "00111111", 10, 4,
    "@", "40", "01000000", 11, 4,
    "A", "41", "01000001", 12, 4,
    "B", "42", "01000010", 13, 4,
    "C", "43", "01000011", 14, 4,
    "D", "44", "01000100", 15, 4,
    "E", "45", "01000101", 16, 4,
    "F", "46", "01000110", 17, 4,
    "G", "47", "01000111", 18, 4,
    "H", "48", "01001000", 1, 5,
    "I", "49", "01001001", 2, 5,
    "j", "4A", "01001010", 3, 5,
    "K", "4B", "01001011", 4, 5,
    "L", "4C", "01001100", 5, 5,
    "M", "4D", "01001101", 6, 5,
    "N", "4E", "01001110", 7, 5,
    "O", "4F", "01001111", 8, 5,
    "P", "50", "01010000", 9, 5,
    "Q", "51", "01010001", 10, 5,
    "R", "52", "01010010", 11, 5,
    "S", "53", "01010011", 12, 5,
    "T", "54", "01010100", 13, 5,
    "U", "55", "01010101", 14, 5,
    "V", "56", "01010110", 15, 5,
    "W", "57", "01010111", 16, 5,
    "X", "58", "01011000", 17, 5,
    "Y", "59", "01011001", 18, 5,
    "Z", "5A", "01011010", 1, 6,
    "[", "5B", "01011011", 2, 6,
    "/", "5C", "01011100", 3, 6,
    "]", "5D", "01011101", 4, 6,
    "^", "5E", "01011110", 5, 6,
    "_", "5F", "01011111", 6, 6,
    "`", "60", "01100000", 7, 6,
    "a", "61", "01100001", 8, 6,
    "b", "62", "01100010", 9, 6,
    "c", "63", "01100011", 10, 6,
    "d", "64", "01100100", 11, 6,
    "e", "65", "01100101", 12, 6,
    "f", "66", "01100110", 13, 6,
    "g", "67", "01100111", 14, 6,
    "h", "68", "01101000", 15, 6,
    "i", "69", "01101001", 16, 6,
    "j", "6A", "01101010", 17, 6,
    "k", "6B", "01101011", 18, 6,
    "l", "6C", "01101100", 1, 7,
    "m", "6D", "01101101", 2, 7,
    "n", "6E", "01101110", 3, 7,
    "o", "6F", "01101111", 4, 7,
    "p", "70", "01110000", 5, 7,
    "q", "71", "01110001", 6, 7,
    "r", "72", "01110010", 7, 7,
    "s", "73", "01110011", 8, 7,
    "t", "74", "01110100", 9, 7,
    "u", "75", "01110101", 10, 7,
    "v", "76", "01110110", 11, 7,
    "w", "77", "01110111", 12, 7,
    "x", "78", "01111000", 13, 7,
    "y", "79", "01111001", 14, 7,
    "z", "7A", "01111010", 15, 7,
    "{", "7B", "01111011", 16, 7,
    "|", "7C", "01111100", 17, 7,
    "}", "7D", "01111101", 18, 7,
    "~", "7E", "01111110", 1, 8,
    "DEL", "7F", "01111111", 2, 8
];


// 场景、相机、渲染器————Three.js老三样
var scene, camera, renderer;

// 控件
var controls;

// 所有元素的集合
var objects = [];

// 每个key都对应一个上面的objects[]
var targets = { table: [], sphere: [], helix: [], grid: [], broken: [], shuffle: [], gather: [], boom: [] };


/**
 * 初始化
 */
function init() {
    initSCRC();         // 初始化场景(Scene)、相机(Camera)、渲染器(Renderer),以及控件(Controls)
    initFirst();        // 初始化128个元素,THREE成3D对象,装进容器;并进行第一次的展示
    initGraph();        // 初始化各种3D图形排列
    initButton();       // 初始化按钮,为每个按钮绑定一个事件(一种3D图形排列)
    initOthers();       // 初始化其他杂事
}



/**
 * 初始化场景(Scene)、相机(Camera)、渲染器(Renderer)
 * 初始化控件(Controls)
 */
function initSCRC() {

    // 初始化场景
    scene = new THREE.Scene();

    // 初始化相机
    camera = new THREE.PerspectiveCamera(40, window.innerWidth, window.innerHeight, 1, 10000);
    camera.position.z = 3000;

    // 初始化渲染器
    renderer = new THREE.CSS3DRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.getElementById('container').appendChild(renderer.domElement);

    // 初始化控件
    controls = new THREE.TrackballControls(camera, renderer.domElement);
    controls.rotateSpeed = 0.5;
    controls.minDistance = 500;
    controls.maxDistance = 6000;
    controls.staticMoving = true;
    controls.addEventListener('change', render);

}


/**
 * 初始化128个元素,并进行第一次的展示
 * 即根据信息第一次生成所有的元素,并附加上数字、符号、细节...THREE成3D对象后装进Objects集合里
 */
function initFirst() {

    for (var i = 0; i < table.length; i += 5) {

        //【Step1】新建element元素
        var element = document.createElement('div');
        element.className = 'element';
        element.style.backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')';

        //【Step2.1】附加数字
        var number = document.createElement('div');
        number.className = 'number';
        number.textContent = i / 5;
        element.appendChild(number);

        //【Step2.2】附加符号
        var symbol = document.createElement('div');
        symbol.className = 'symbol';
        symbol.textContent = table[i];
        element.appendChild(symbol);

        //【Step2.3】附加细节
        var details = document.createElement('div');
        details.className = 'details';
        details.innerHTML = table[i + 1] + '<br>' + table[i + 2];
        element.appendChild(details);

        //【Step3】Three成3D对象
        var object = new THREE.CSS3DObject(element);
        object.position.x = Math.random() * 4000 - 2000;
        object.position.y = Math.random() * 4000 - 2000;
        object.position.z = Math.random() * 4000 - 2000;

        //【Step4.1】加到到场景中(展示出来)
        scene.add(object);

        //【Step4.2】加到元素集合中
        objects.push(object);

    }

}


/**
 * 初始化各种3D图形排列
 * 即事先计算并保存在各种图形中元素的位置(position),放在targets字典中,随用随取
 */
function initGraph() {

    /**
     * 表格(Table)
     */

    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        object.position.x = (table[5 * i + 3] * 140) - 1330;
        object.position.y = 990 - (table[5 * i + 4] * 180);

        targets.table.push(object);

    }


    /**
     * 球体(Sphere)
     */

    var vector = new THREE.Vector3();
    var spherical = new THREE.Spherical();

    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();
        var l = objects.length;
        var phi = Math.acos(-1 + (2 * i) / l);
        var theta = Math.sqrt(l * Math.PI) * phi;

        spherical.set(800, phi, theta);
        object.position.setFromSpherical(spherical);
        vector.copy(object.position).multiplyScalar(2);
        object.lookAt(vector);

        targets.sphere.push(object);

    }


    /**
     * 螺旋(Helex)
     */

    var vector = new THREE.Vector3();
    var cylindrical = new THREE.Cylindrical();

    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();
        var theta = i * 0.175 + Math.PI;
        var y = - (i * 8) + 450;

        cylindrical.set(900, theta, y);
        object.position.setFromCylindrical(cylindrical);
        vector.x = object.position.x * 2;
        vector.y = object.position.y;
        vector.z = object.position.z * 2;
        object.lookAt(vector);

        targets.helix.push(object);

    }


    /**
     * 网格(Grid)
     */

    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        object.position.x = ((i % 5) * 400) - 800;
        object.position.y = (- (Math.floor(i / 5) % 5) * 400) + 800;
        object.position.z = (Math.floor(i / 25)) * 1000 - 2000;

        targets.grid.push(object);

    }


    /**
     * 崩塌(Broken)
     */
    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        object.position.y = -2500 - i * i;
        object.position.z = 0;

        targets.broken.push(object);

    }


    /**
     * 混乱(Shuffle)
     */
    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        object.position.x = Math.random() * 4000 - 2000;
        object.position.y = Math.random() * 4000 - 2000;
        object.position.z = Math.random() * 4000 - 2000;

        targets.shuffle.push(object);

    }


    /**
     * 归一(Gather)
     */
    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        object.position.z = 1000;

        targets.gather.push(object);

    }


    /**
     * 爆炸(Boom)
     */
    for (var i = 0; i < objects.length; i++) {

        var object = new THREE.Object3D();

        // object.position.x = 
        // object.position.y = 
        object.position.z = 10000;

        targets.boom.push(object);

    }


}


/**
 * 初始化按钮
 * 即为每个按钮绑定事件
 */
function initButton() {

    document.getElementById('table').addEventListener('click', function (event) {
        transform(targets.table, 2000);
    }, false);

    document.getElementById('sphere').addEventListener('click', function (event) {
        transform(targets.sphere, 2000);
    }, false);

    document.getElementById('helix').addEventListener('click', function (event) {
        transform(targets.helix, 2000);
    }, false);

    document.getElementById('grid').addEventListener('click', function (event) {
        transform(targets.grid, 2000);
    }, false);

    document.getElementById('broken').addEventListener('click', function (event) {
        transform(targets.broken, 2000);
    }, false);

    document.getElementById('shuffle').addEventListener('click', function (event) {
        transform(targets.shuffle, 2000);
    }, false);

    document.getElementById('gather').addEventListener('click', function (event) {
        transform(targets.gather, 2000);
    }, false);

    document.getElementById('boom').addEventListener('click', function (event) {
        transform(targets.boom, 2000);
    }, false);


}


/**
 * 初始化其他
 * 做一些其他的杂事————比如处理窗口缩放事件,自动从First混乱态转换为Table表格
 */
function initOthers() {
    window.addEventListener('resize', onWindowResize, false);
    transform(targets.table, 2000);
}






/**
 * 图形转换
 */
function transform(targets, duration) {

    // 使用到了THREE渐变类
    TWEEN.removeAll();

    for (var i = 0; i < objects.length; i++) {

        var object = objects[i];    // 当前3D对象
        var target = targets[i];    // 目标3D对象

        // 位置
        new TWEEN.Tween(object.position)
            .to({ x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration)
            .easing(TWEEN.Easing.Exponential.InOut)
            .start();

        // 角度
        new TWEEN.Tween(object.rotation)
            .to({ x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration)
            .easing(TWEEN.Easing.Exponential.InOut)
            .start();

    }

    // 别忘了渲染!!!
    new TWEEN.Tween(this)
        .to({}, duration * 2)
        .onUpdate(render)
        .start();

}


/**
 * 窗口缩放时的回调函数
 */
function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);

    render();

}


/**
 * 动画刷新
 */
function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();
    controls.update();
}


/**
 * 渲染
 */
function render() {
    renderer.render(scene, camera);
}

 
 
 
 

 
 
 
 

 
 
 
 

E N D END END

本文地址:https://blog.csdn.net/m0_46202073/article/details/110384845