00 - three.js 笔记 - 开始记录学习进度
首先,本人不是专业的WebGl开发工程师,也没有任何计算机图形学和WebGl基础,更不是开发前端的,只是一个刚刚参加工作的小白菜。
从今天开始起,我将把自己对 ThreeJs 的学习记录分享给大家。虽然并不专业,但也是自己的一些见解,也许以后再来回顾,或许会有一些不同的体会。
这个系列没有结束,但凡自己以后在工作中遇到问题都会分享在此博客,谈一下自己的思路和寻找的资料的总结!
本篇demo的浏览地址:http://ithanmang.com/threeJs/home/01-helloworld.html
然后我们来看示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>three hello world!</title>
<style>
body{
margin: 0;
overflow: hidden;
}
</style>
<script src="../libs/build/three.js"></script>
<script src="../libs/jquery-1.9.1.js"></script>
<script src="../libs/examples/js/controls/TrackballControls.js"></script>
<script src="../libs/examples/js/libs/dat.gui.min.js"></script>
<script src="../libs/examples/js/libs/stats.min.js"></script>
</head>
<body>
<div id="WebGL-output"></div>
<div id="Stats-output"></div>
<script>
$(function () {
// 初始化性能插件
var stats = initStats();
// 创建场景
var scene = new THREE.Scene();
// 创建相机--透视相机
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
// 创建WebGl渲染器
var webGlRenderer = new THREE.WebGLRenderer();
// 配置渲染器
webGlRenderer.antialias = true;// 抗锯齿
webGlRenderer.autoClear = true;// 自动清除
webGlRenderer.setClearColor( 0x050505 );// 渲染背景色
webGlRenderer.setSize( window.innerWidth, window.innerHeight);// 渲染范围
// 配置相机
camera.position.set(0, 400, 800);// 相机在三维空间的位置
camera.lookAt(new THREE.Vector3(0, 0, 0));// 相机看向空间坐标原点
// 创建立方体
var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);// 立方体模型
var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 创建网格实例
cube.position.y = 90;// 立方体的 y 坐标 +90
// 将立方体加入场景
scene.add(cube);
// 创建光源 ambientLight:环境光、directionalLight:平行光
var ambientLight = new THREE.AmbientLight( 0x404040 );
var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
// 设置光源的位置
directionalLight1.position.set(-300, -400, 300);
directionalLight2.position.set(300, 400, -300);
// 将光源加入场景
scene.add(ambientLight);
scene.add(directionalLight1);
scene.add(directionalLight2);
// 创建网格辅助
var gridHelper = new THREE.GridHelper(1200, 50, 0xFF4444, 0x404040 );
scene.add( gridHelper );
// 创建轨迹球控件
var trackballControls = new THREE.TrackballControls(camera, webGlRenderer.domElement);
// 加入图形调试控件中的组件 gui
var controls = new function () {
this.rotationSpeed = 0.02;
this.wireframe = cubeMaterial.wireframe;
this.color = cubeMaterial.color.getStyle();
this.gridHelper = false;
this.backGround = webGlRenderer.getClearColor().getHex();
}
// 创建图形调试控件
var gui = new dat.GUI();
// 创建 helperGui 目录,下面包含 gridHelper 组件
var helperGui = gui.addFolder('Helper');
helperGui.add(controls,'gridHelper').onChange(function (e) {
console.log(e);
if (e){
scene.remove(gridHelper);
}else{
scene.add(gridHelper);
}
});
// 创建 meshGui 目录, 目录下包含组件 wireframe、color、rotationSpeed
var meshGui = gui.addFolder("Mesh");
meshGui.add(controls,'wireframe').onChange(function (e) {
cubeMaterial.wireframe = e;
});
meshGui.addColor(controls,'color').onChange(function (e) {
cubeMaterial.color.setStyle(e);
})
meshGui.add(controls,'rotationSpeed',0, 0.1);
// 创建 sceneGui 目录, 目录下包含 backGround 组件
var sceneGui = gui.addFolder('Scene');
sceneGui.addColor(controls,'backGround').onChange(function (e) {
webGlRenderer.setClearColor(e)
})
// 将渲染器添加到画布
$("#WebGL-output").append(webGlRenderer.domElement);
// 窗口大小改变触发的方法
function onWindowResize() {
// 改变相机的 aspect 为窗口的宽和长度之比
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相机的投影矩阵
camera.updateProjectionMatrix();
// 重新设置渲染器的大小
webGlRenderer.setSize(window.innerWidth, window.innerHeight);
}
// 添加事件监听
window.addEventListener('resize',onWindowResize,false);
// 初始化性能插件方法
function initStats() {
var stats = new Stats();
stats.setMode(0);// 0:现实fps, 1:ms
// 调整插件布局
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
// 加入画布
$("#Stats-output").append(stats.domElement);
// 将初始化的插件返回
return stats;
}
// 渲染方法
function render() {
// 更新性能插件
stats.update();
// 立方体绕 x、y、z 轴旋转,速度由调试插件控制
cube.rotation.x += controls.rotationSpeed;
cube.rotation.y += controls.rotationSpeed;
cube.rotation.z += controls.rotationSpeed;
// 更新轨迹球控件的操作范围
trackballControls.handleResize();
// 更新物体位置
trackballControls.update();
// 开始渲染
webGlRenderer.render(scene, camera);
}
// 实现动画效果
function animate() {
requestAnimationFrame(animate);
render();
}
animate();
});
</script>
</body>
</html>
代码分析
这个简单的demo实现了三维场景 scene 的创建,加入了灯光和鼠标控制,并且添加了性能插件 stats 和 调试插件 datGUI 来控制立方体的颜色和材质的变换,以及加入了网格辅助对象,来清晰的看到立方体所处的位置。
threejs主要元素
- 场景 (scene)
- 相机(camera)
- 渲染器(render)
以上三个元素 是最主要的部分,然后来看实例中的部分代码。 - 场景
// 创建场景
var scene = new THREE.Scene();
- 相机
// 创建相机--透视相机
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
并且对相机进行了配置
// 配置相机
camera.position.set(0, 400, 800);// 相机在三维空间的位置
camera.lookAt(new THREE.Vector3(0, 0, 0));// 相机看向空间坐标原点
- 渲染器
// 创建WebGl渲染器
var webGlRenderer = new THREE.WebGLRenderer();
此处创建的是WebGL渲染器,threejs还有别的渲染器,可以根据具体情况来选择
对渲染器进行配置
// 配置渲染器
webGlRenderer.antialias = true;// 抗锯齿
webGlRenderer.autoClear = true;// 自动清除
webGlRenderer.setClearColor( 0x050505 );// 渲染背景色
webGlRenderer.setSize( window.innerWidth, window.innerHeight);// 渲染范围
此时三维场景就已经搭建完成,但是当我们运行代码的时候发现发现浏览器一片黑白,因为我们只是创建了三维场景所必须的组件,并没有开始渲染。
- 开始渲染
// 首先需要将渲染器添加到画布
$("#WebGL-output").append(webGlRenderer.domElement);
// 开始渲染
webGlRenderer.render(scene, camera);
上面webGlRenderer.render(scene, camera);
是渲染器将场景和相机结合到一起,然后开始进行执行渲染操作。
当我们再次执行的时候发现浏览器还是什么都没有,因为并没有向场景中添加对象,下面创建一个立方体,并将其加入到场景之中。
- 创建立方体
// 创建立方体
var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);// 立方体模型
var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 创建网格实例
cube.position.y = 90;// 立方体的 y 坐标 +90
// 将立方体加入场景
scene.add(cube);
- 还需要创建灯光
// 创建光源 ambientLight:环境光、directionalLight:平行光
var ambientLight = new THREE.AmbientLight( 0x404040 );
var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
// 设置光源的位置
directionalLight1.position.set(-300, -400, 300);
directionalLight2.position.set(300, 400, -300);
// 将光源加入场景
scene.add(ambientLight);
scene.add(directionalLight1);
scene.add(directionalLight2);
然后再次打开浏览器就会发现场景中出现了一个小立方体,
并且颜色是随机的,因为var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色
设置的为随机色。
- 让立方体动起来
想让立方体动起来就需要不断的改变立方体的三维坐标,并且改变一次浏览器就需要刷新一次,因此需要使用这个函数来实现方法的回调,实现动画的效果requestAnimationFrame();
参数是一个函数名,也就是需要重复执行的函数体。
所以若想让立方体动起来,就需要在重复执行的函数里不断改变立方体的位置坐标,即改变一次刷新一次,来实现动画的效果。
// 实现动画效果
function animate() {
// 立方体绕 x、y、z 轴旋转,速度由调试插件控制
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
requestAnimationFrame(animate);
// 开始渲染
webGlRenderer.render(scene, camera);
}
animate();
这样就实现了,动画的效果,如果在这个函数中添加一行代码 console.log(cube.rotation);
就会回发现此时浏览器在疯狂的刷新,来改变立方体旋转的三维坐标。
- 添加网格辅助
当然这个不是必须的,它只是场景中的一个对象,而已,凭个人喜好而添加,js是面向对象的语言,可以很好的使用 通过Object3D 继承来的 add()方法 和 remove()方法为场景接口来添加和移除对象。
// 创建网格辅助实例
var gridHelper = new THREE.GridHelper(1200, 50, 0xFF4444, 0x404040 );
scene.add( gridHelper );
这两个方法,scene并不具有,只是从基类Object3D 继承来的。
- 添加轨迹球控件
threeJs用来通过鼠标和键盘来和模型交互的控件很多,这里就不一一概述了。
// 创建轨迹球控件
var trackballControls = new THREE.TrackballControls(camera, webGlRenderer.domElement);
轨迹球控件是用来操控物体和相机的,因此需要将相机传给它,因为场景一直在刷新,所以也要重置轨迹球的控制范围。
下面两个控件也不是必须的,仅仅是为了调试。
因为在场景中要把灯光和别的物体 一次放在一个合适的位置,是不可能的,因此需要调试。
添加性能插件
这是初始化性能插件的方法。
、
在页面加载的时候就初始化。添加图形调试控件
在threeJs_r93\three.js-master\examples\js\libs
目录可以找到dat.gui.min.js
这个js库,引入。
1.首先通过构造函数 来创建它的实例
2.将需要调试的对象和属性放入一个函数中
3.然后将要实现的逻辑添加到控件中
4.举个例子
在这个完整的示例中,可以看到当点击这个按钮的时候 网格 对象就会消失。
这是怎么实现的呢?首先,为controls函数添加一个属性 并初始化。
然后,将这个属性添加给图形控件
看控制台的输出 e的变化。
此时 e 的值默认为false
取消之后e的值又变为了默认的 fasle。别的需要调试的属性也是类似方法来创建。
本篇文章对于 threeJs新手来说,可能会有点难度,但是也并不是很复杂,从以上解释来看,threeJs是完全面向对象的,除了所必须的场景(Scene)、相机(Camera)以及渲染器(Renderer)之外其它的对象都是可插拔的,个人认为学习,threeJs没有一些捷径,也有人认为学习三维开发应该从底层的OpenGL开始学起,但是那样对于没有任何计算机图形学基础的人来说,是很挫败自信心的,因为有时候学习了一周也不会创建出来一个简单的图形。
上一篇: three.js学习笔记MorphAnimMesh
下一篇: ThreeJS系列教程-Lesson2