借助Three.js,我们也能实现一个地球仪旋转

前言

Three.js是一个基于WebGLJavaScript3D库,它允许在浏览器中创建和展示交互式的3D图形和动画。Three.js建立在WebGL技术之上,是OPENGL在浏览器端的体现。那么在本文中Virtual09将会给大家展示,如何实现一个地球仪旋转

正文

三个主要"角色"

Three.js的官方文档中有这样一张图,很好为我们解释了Three.js是如何创建一个3D场景的,我们现在开始先来认识场景Scene,相机Camera,渲染器Renderer这三个基本概念,以及它们的作用

三维场景Scene

在场景中,我们可以自定义我们需要的"景点".场景中我们可以进行如下操作:

  1. 创建并添加物体
  2. 设置物体的外观
  3. 创建模型
  4. 设置模型位置

虚拟相机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>
相关推荐
hongkid7 分钟前
React Native 如何打包正式apk
javascript·react native·react.js
李少兄9 分钟前
简单讲讲 SVG:前端开发中的矢量图形
前端·svg
前端小万11 分钟前
告别 CJS 库加载兼容坑
前端·前端工程化
恋猫de小郭11 分钟前
Flutter 3.38.1 之后,因为某些框架低级错误导致提交 Store 被拒
android·前端·flutter
JarvanMo15 分钟前
Flutter 需要 Hooks 吗?
前端
光影少年25 分钟前
前端如何虚拟列表优化?
前端·react native·react.js
Moment27 分钟前
一杯茶时间带你基于 Yjs 和 reactflow 构建协同流程图编辑器 😍😍😍
前端·后端·面试
菩提祖师_41 分钟前
量子机器学习在时间序列预测中的应用
开发语言·javascript·爬虫·flutter
invicinble44 分钟前
对于前端数据的生命周期的认识
前端
PieroPc1 小时前
用FastAPI 后端 和 HTML/CSS/JavaScript 前端写一个博客系统 例
前端·html·fastapi