前言
Three.js是一个基于WebGL
的JavaScript
3D库,它允许在浏览器中创建和展示交互式的3D图形和动画。Three.js
建立在WebGL
技术之上,是OPENGL
在浏览器端的体现。那么在本文中Virtual09将会给大家展示,如何实现一个地球仪旋转
正文
三个主要"角色"
在Three.js
的官方文档中有这样一张图,很好为我们解释了Three.js
是如何创建一个3D场景的,我们现在开始先来认识场景Scene
,相机Camera
,渲染器Renderer
这三个基本概念,以及它们的作用
三维场景Scene
在场景中,我们可以自定义我们需要的"景点".场景中我们可以进行如下操作:
- 创建并添加物体
- 设置物体的外观
- 创建模型
- 设置模型位置
虚拟相机Camera
我们在三维场景中添加好了"景点",但是我们依旧是需要用照相机记录下来
我们创建照相机const camera = new THREE.PerspectiveCamera(fov,aspect,near,far)
一种可以接受四个参数那么每一个参数表示的含义如下:
fov
:相机拍摄的角度,默认值是50
aspect
:表示相机是横拍还是竖拍,这里我们一般用window.innerWidth / window.innerHeight
表示横拍,反之表示竖拍。
near
:相机距离拍摄位置的最近距离,默认值为0.1
far
:相机距离拍摄的最远距离,默认值为2000
这里解释的可能没有官方文档讲解的那么具体,下面就展示官方文档的解释
透视投影相机四个参数
fov
,aspect
,near
,far
构成一个四棱台3D空间,被视为视椎体,只有视椎体之内的物体就会渲染出来,视椎体范围之外的物体不会显示在Canvas画布上
我个人是认为看这张图是比较头疼的,所以我就通俗化的解释了一下四个参数。
渲染器
当我们场景搭建完毕,且照相机也成功的拍下了我们要的"照片",这时我们就需要把渲染器给搬出来工作了。那么具体如何操作,我们就在下面的案例实现来分析;
地球仪的实现
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>three.js canvas earth</title>
<!-- CDN 引入three.js -->
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
</head>
<body>
<canvas id="webglcanvas"></canvas>
<script>
let canvas;//3D容器
let camera // 照相机
,scene // 场景
,renderer //渲染器
let group;//组合
</script>
</body>
</html>
我们创建一个html
文件,并以CDN
的格式将three.js
引入文件中。创建一个画布作为3D容器.我们之后的内容都是会在这个容器中展示的。分别创建了3D容器,照相机,场景,渲染器。组合。前面四个变量的作用都好理解,这个组合是什么呢?诶,别急各位,后面会给大家介绍的。
我们创建一个初始化函数init()
在该函数中,我们需要完成照相机,场景,渲染等多项操作.
ini
function init(){
canvas = document.getElementById('webglcanvas');
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
2000
)
camera.position.z = 500;
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
group = new THREE.Group()
scene.add(group);
let loader = new THREE.TextureLoader();
loader.load('earth.jpg',function(texture){
let geometry = new THREE.SphereGeometry(200,20,20);
let material = new THREE.MeshBasicMaterial({
map: texture,
});
let mesh = new THREE.Mesh(geometry,material);
group.add(mesh);
})
renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias:true
})
renderer.setSize(window.innerWidth,window.innerHeight);
}
第一步我们是获取到了我们在html
部分的3D容器。然后创建一个照相机,拍摄角度为60,横拍,最近拍摄距离为1,最远为2000.这里camera.position.z
是设置了照相机在z轴方向上的拍摄距离,我们也可以使用set
直接设置三个坐标轴的位置camera.position.set(x,y,z)
.创建完照相机之后就是创建场景了scene = new THREE.Scene()
. scene.background = new THREE.Color(0xffffff)
是设置背景色。这里我们就可以看到group
了,但是它具有什么作用呢,我们来看看官方文档是怎么说的
这张图片是指Group
层级模型,我们可以将group
中这一组对象作为场景对象scene
的子对象这样就成了scene->group->mesh
这样的三层模型了。TextureLoader()
是一个纹理贴图加载器,通过load()
方法加载一张照片可以返回一个纹理对象Texture
,纹理对象Texture
可以作为模型材质颜色贴图.map
属性的值。SphereGeometry()
是创建球体的API,Three.js
提供了多种几何体的API
传递给构造函数的三个参数分别代表球体的半径、水平分段数(width segments)和垂直分段数(height segments)。
MeshBasicMaterial()
物体外观材质,Three.js
对于不同的材质渲染效果不同,就有多种材质的API
Mesh()
创建网络模型,网络模型接受两个参数,一个是几何体,一个是材质,然后 group.add(mesh)
将模型添加到场景中。官方对于add()
方法的解释,在 group.add(mesh)
中表示"在three.js
中你创建一个表示物体的虚拟对象Mesh,需要通过add()
方法,把网络模型mesh
添加到三维场景scene
中"。
WebGLRenderer
创建一个渲染器,中接受两个参数canvas: canvas
表示在webglcanvas
中渲染,antialias:true
用于控制渲染器是否开启抗锯齿功能,使模型和场景看起来更加平滑。renderer.setSize()
设置渲染空间的大小.
到这里我们的初始化就完成了,现在我们就是需要实现让它自己动起来了。
scss
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
group.rotation.y -= 0.005;
renderer.render(scene, camera);
}
requestAnimationFrame(animate)
是一个请求动画帧,每秒执行60次,执行完又会重新调用animate
函数,并调用render
函数,重新渲染, group.rotation.y
开启旋转。
这样上述代码就可以实现地球仪了。
文章到此就结束了,感谢大家阅读。下面则是完整的代码
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>three.js canvas earth</title>
<!-- CDN 引入three.js -->
<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
</head>
<body>
<canvas id="webglcanvas"></canvas>
<script>
let canvas;//3D容器
let camera // 照相机
,scene // 场景
,renderer //渲染器
let group;//组合
init();
animate();
function init(){
canvas = document.getElementById('webglcanvas');
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
2000
)
camera.position.z = 500;
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
group = new THREE.Group()
scene.add(group);
let loader = new THREE.TextureLoader();
loader.load('earth.jpg',function(texture){
let geometry = new THREE.SphereGeometry(200,20,20);
let material = new THREE.MeshBasicMaterial({
map: texture,
});
let mesh = new THREE.Mesh(geometry,material);
group.add(mesh);
})
renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias:true
})
renderer.setSize(window.innerWidth,window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
// camera.position.x += (mouseX - camera.position.x) *0.5;
// camera.position.y += (- mouseY - camera.position.y) * 0.5;
// camera.lookAt(scene.position);
group.rotation.y -= 0.005;
renderer.render(scene, camera);
}
</script>
</body>
</html>