Three.js学习笔记 | 相册魔方,让爱更“炫”一点

507 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

照片魔方.gif

最近在学习Three.js,纯粹的示例程序过于乏味,让人昏昏欲睡。用自己掌握的知识做一些自己感兴趣的、喜爱的小东西。巩固学到的知识的同时也愉悦了身心。

今天用Three.js做了个相册魔方,每个面上放上自己宝贝(大宝贝、小宝贝都可以哦)的照片,很炫哦。

前置条件

在自己的电脑上安装了Nginx,使用Nginx作为静态资源服务器。

本篇文章中使用的图片的浏览地址是:http://localhost:8000/momo.png

示例程序的基本骨架

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>相册魔方</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r99/three.min.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="container"></div>
    <!-- three.js代码 -->
    <script>
	// ...
    </script>
</body>
</html>

说明:

  • 引入 Three.js 函数库;
  • 定义了一个idcontainerdiv元素,用于存放内容;
  • bodymargin设置成0
  • <script>标签用于存放示例程序JS代码。

操作步骤

  1. 定义一个init()方法,在页面加载成功后调用。
/**
 * 初始化方法
 */
function init() {
	// ...
}
window.onload = init;

示例程序所有相关的业务代码都放存了init()方法体中。

  1. 定义 Three.js 三大件:场景、摄像机、渲染器。
// 场景
var scene = new THREE.Scene();
// 透视摄像机
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 渲染器
var renderer = new THREE.WebGLRenderer({ antialias: true });

// 设置摄像机的位置
camera.position.z = 600;

// 设置渲染器背景颜色
renderer.setClearColor("#222222");
// 设置渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将渲染的结果输出到指定页面元素中
document.getElementById("container").appendChild(renderer.domElement);

这里定义了场景、摄像机、渲染器,并且设置了摄像机的位置、渲染器背景颜色、渲染器大小,最后将渲染的结果输出到container页面元素中。

摄像机的位置也会影响立方体的显示大小,设置不合适的话,立方体会显示不出来。

  1. window添加resize事件,当窗体大小变化时,立体体大小也会随着变化。
window.addEventListener( 'resize', () => {
	var width = window.innerWidth;
	var height = window.innerHeight;
	renderer.setSize(width, height);
	// 摄像机视锥体长宽比
	camera.aspect = width / height;
	// 更新摄像机投影矩阵
	camera.updateProjectionMatrix();
});

Camera.updateProjectionMatrix():更新摄像机投影矩阵。在任何参数被改变以后必须被调用。

  1. 定义立方体,六个面都加载图片
var image_1 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var image_2 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var image_3 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var image_4 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var image_5 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var image_6 = new THREE.TextureLoader().load( 'http://localhost:8000/momo.png' );
var material_1 = new THREE.MeshBasicMaterial( { map: image_1 } );
var material_2 = new THREE.MeshBasicMaterial( { map: image_2 } );
var material_3 = new THREE.MeshBasicMaterial( { map: image_3 } );
var material_4 = new THREE.MeshBasicMaterial( { map: image_4 } );
var material_5 = new THREE.MeshBasicMaterial( { map: image_5 } );
var material_6 = new THREE.MeshBasicMaterial( { map: image_6 } );
var materials = [];
materials.push(material_1);
materials.push(material_2);
materials.push(material_3);
materials.push(material_4);
materials.push(material_5);
materials.push(material_6);

// 创建一个立方体
var cubeGeometry = new THREE.BoxGeometry(300, 300, 300);
var cube = new THREE.Mesh(cubeGeometry, materials);
//将立方体添加到场景中
scene.add(cube);

这里六个面我使用的是一个图片,如果有需求,可以自行修改每个面的图片。

TextureLoader:加载texture的一个类。 内部使用ImageLoader来加载文件。

  1. 添加光源
// 环境光
var ambientLight = new THREE.AmbientLight( 0xffffff, 0.2);
scene.add( ambientLight );

// 点光源
var pointLight = new THREE.PointLight( 0xffffff, 1 );
pointLight.position.set( 325, 350, 325 );
scene.add( pointLight );

AmbientLight:环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。

PointLight:从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。该光源可以投射阴影。

  1. 使立方体转起来
function animate() {
	requestAnimationFrame( animate )
	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;
	renderer.render( scene, camera )
}

animate();

到这里,照片魔方就做出来了。

完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>相册魔方</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/three.js/r99/three.min.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="container"></div>
    <!-- three.js代码 -->
    <script>
        /**
         * 初始化方法
         */
        function init() {
            // 场景
            var scene = new THREE.Scene();
            // 透视摄像机
            var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            // 渲染器
            var renderer = new THREE.WebGLRenderer({ antialias: true });

            // 设置摄像机的位置
            camera.position.z = 600;

            // 设置渲染器背景颜色
            renderer.setClearColor("#222222");
            renderer.setSize(window.innerWidth, window.innerHeight);
            // 将渲染的结果输出到指定页面元素中
            document.getElementById("container").appendChild(renderer.domElement);


            window.addEventListener( 'resize', () => {
                var width = window.innerWidth;
                var height = window.innerHeight;
                renderer.setSize(width, height);
                camera.aspect = width / height;
                camera.updateProjectionMatrix();
            });
			var image_1 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2018/01/13/19/39/fashion-3080644__340.jpg' );
			var image_2 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2018/01/05/07/05/people-3062246__340.jpg' );
			var image_3 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2015/12/17/22/26/portrait-1097950__340.jpg' );
			var image_4 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2018/01/18/01/44/beautiful-3089385__340.jpg' );
			var image_5 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2015/03/28/00/39/woman-695456_960_720.jpg' );
			var image_6 = new THREE.TextureLoader().load( 'https://cdn.pixabay.com/photo/2015/03/04/19/41/woman-659350__340.jpg' );
			var material_1 = new THREE.MeshBasicMaterial( { map: image_1 } );
			var material_2 = new THREE.MeshBasicMaterial( { map: image_2 } );
			var material_3 = new THREE.MeshBasicMaterial( { map: image_3 } );
			var material_4 = new THREE.MeshBasicMaterial( { map: image_4 } );
			var material_5 = new THREE.MeshBasicMaterial( { map: image_5 } );
			var material_6 = new THREE.MeshBasicMaterial( { map: image_6 } );
			var materials = [];
			materials.push(material_1);
			materials.push(material_2);
			materials.push(material_3);
			materials.push(material_4);
			materials.push(material_5);
			materials.push(material_6);

            // 创建一个立方体
            var cubeGeometry = new THREE.BoxGeometry(300, 300, 300);
            var cube = new THREE.Mesh(cubeGeometry, materials);
            //将立方体添加到场景中
            scene.add(cube);

            // 环境光
            var ambientLight = new THREE.AmbientLight ( 0xffffff, 0.2);
            scene.add( ambientLight );

            // 点光源
            var pointLight = new THREE.PointLight( 0xffffff, 1 );
            pointLight.position.set( 325, 350, 325 );
            scene.add( pointLight );

            function animate() {
                requestAnimationFrame( animate )
                cube.rotation.x += 0.01;
                cube.rotation.y += 0.01;
                renderer.render( scene, camera )
            }

            animate();
        }

        // 页面加载成功后调init()方法
        window.onload = init;
    </script>
</body>
</html>

为了演示,我把本地的图片换成了在线免费的图片了。


如果觉得文章写得还凑合,还麻烦你动动小手帮忙点个赞呗。你的支持是我更文的动力。目前在写的系列有下面几个系统:

  • MyBatis源码解读
  • 设计模式
  • 一起学Three.js
  • Spring Boot
  • Spring Cloud

都是一些平时工作中用到的知识点的个人总结和学习笔记。