借助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>
相关推荐
CaptainDrake2 分钟前
Vue:指令
前端·javascript·vue.js
软件技术NINI5 分钟前
HTML——基本标签
前端·javascript·html
卡兰芙的微笑29 分钟前
get_property --Cmakelist之中
前端·数据库·编辑器
覆水难收呀32 分钟前
三、(JS)JS中常见的表单事件
开发语言·前端·javascript
猿来如此呀39 分钟前
运行npm install 时,卡在sill idealTree buildDeps没有反应
前端·npm·node.js
hw_happy1 小时前
解决 npm ERR! node-sass 和 gyp ERR! node-gyp 报错问题
前端·npm·sass
FHKHH1 小时前
计算机网络第二章:作业 1: Web 服务器
服务器·前端·计算机网络
视觉小鸟1 小时前
【JVM安装MinIO】
前端·jvm·chrome
二川bro2 小时前
【已解决】Uncaught RangeError: Maximum depth reached
前端
qq22951165023 小时前
python毕业设计基于django+vue医院社区医疗挂号预约综合管理系统7918h-pycharm-flask
前端·vue.js·express