Three.js——创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化

2024-04-02 14:36

本文主要是介绍Three.js——创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js🍒Three.js🍖数据结构与算法体系教程

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
WebGL专栏WebGL 入门

文章目录

    • 前言
    • 一、创建场景
    • 二、渲染三维对象
    • 三、旋转动画
    • 四、添加灯光
    • 五、添加阴影
    • 六、添加雾化
    • 总结

前言

大家好,这里是前端杂货铺。

原 three.js 专栏

本专栏将以更清晰专业的方式记录并讲解 three.js 相关的基础知识。

在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档


一、创建场景

在渲染三维对象之前我们需要以下几个对象:场景(scene)、相机(camera)和渲染器(renderer),这样我们就能透过摄像机渲染出场景。

场景 用于存放我们需要的物体(比如桌子放在房间里,那么此时房间就是场景,桌子就是物体)。

相机 用于拍摄我们场景中的物体,它包括 PerspectiveCamera(透视摄像机:用来模拟人眼所看到的景象,近大远小)和 OrthographicCamera(正交摄像机:渲染的图片中物体的大小都保持不变)。

渲染器 用于把场景和场景里面的物体渲染到我们的屏幕上。

<!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>Document</title><script src="../lib/three/three.js"></script><style>* {margin: 0;padding: 0;}</style>
</head><body><script>// 创建场景const scene = new THREE.Scene();// 创建相机 参数:视野角度、长宽比、近截面、远截面const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);// 设置相机位置camera.position.set(0, 0, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 将渲染器的 canvas 添加到 body 中document.body.appendChild(renderer.domElement);</script>
</body></html>

此时的 renderer 是一个庞大的对象,renderer.domElement 其实就是一个 canvas,它此刻代表着我们屏幕上的黑色场景。

在这里插入图片描述


二、渲染三维对象

我们可以在场景中渲染的三维对象有很多种,比如:立方体、球体、椎体、圆柱体…

接下来,我们在刚刚创建好的场景中添加一个立方体。其实也很简单,我们只需要创建 立方缓冲几何体 实例,然后定义一个材质,最后通过 mesh 网格 构建出来几何体添加到场景中即可。

<!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>Document</title><script src="../lib/three/three.js"></script><style>* {margin: 0;padding: 0;}</style>
</head><body><script>// 创建场景const scene = new THREE.Scene();// 创建相机 视野角度、长宽比、近截面、远截面const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);// 设置相机位置camera.position.set(0, 0, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight);// 将渲染器的 canvas 添加到 body 中document.body.appendChild(renderer.domElement);// 添加立方体const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);// 创建立方体材质const cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, // 立方体颜色wireframe: true //  是否将几何体渲染为线框});// 基于以三角形为 polygon mesh(多边形网格)的物体的类 => 此时就是立方体const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 添加到场景scene.add(cube);// 渲染renderer.render(scene, camera);</script>
</body></html>

在这里插入图片描述

若把 wireframe 置为 false,则渲染出的为几何体

在这里插入图片描述


三、旋转动画

接下来,我们来让刚刚被渲染出来的三维对象旋转起来,看一下它的总体形态。

在此,我们使用 window.requestAnimationFrame(),它会告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

requestAnimatingFrame 相较于 setTimeout 的优点:为了提高性能和电池寿命,在大多数浏览器里,当 requestAnimationFrame() 运行在后台标签页或者隐藏的 <iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。(总而言之,requestAnimatingFrame 有更高的效率!)

requestAnimationFrame 通常每秒执行 60 次,相当于每 0.01667s 执行一次,即 60帧。

下面代码中的 rotation 用于控制立方体的绕轴旋转,通过 requestAnimationFrame 设置每单位时间立方体绕 x 轴旋转 0.01,绕 y 轴也旋转 0.01。

<!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>Document</title><script src="../lib/three/three.js"></script><style>* {margin: 0;padding: 0;}</style>
</head><body><script>// 创建场景const scene = new THREE.Scene();// 创建相机 视野角度、长宽比、近截面、远截面const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);// 设置相机位置camera.position.set(0, 0, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight);console.log(renderer);// 将渲染器的 canvas 添加到 body 中document.body.appendChild(renderer.domElement);// 添加立方体const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);// 创建立方体材质const cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000,wireframe: true});const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 添加到场景scene.add(cube);const animation = () => {cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 渲染renderer.render(scene, camera);requestAnimationFrame(animation);}animation();</script>
</body></html>

立方体旋转动画


四、添加灯光

接下来,我们在场景中添加一个聚光灯光照 SpotLight(光线从一个点沿一个方向射出,随着光线照射的变远,光线圆锥体的尺寸也逐渐增大)。从而模拟出有光照打在物体上的立体效果。

也很简单,我们只需要创建聚光灯实例,给它传递一个白色,设置合适的位置添加到场景中即可。

需要注意的是:添加灯光时的材质需要改为 MeshLambertMaterial,因为 MeshBasicMaterial 不支持添加材质。

<!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>Document</title><script src="../lib/three/three.js"></script><style>* {margin: 0;padding: 0;}</style>
</head><body><script>// 创建场景const scene = new THREE.Scene();// 创建相机 视野角度FOV、长宽比、近截面、远截面const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);// 设置相机位置camera.position.set(0, 0, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);// 添加立方体const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);// 创建立方体材质const cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000,wireframe: false});const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 添加到场景scene.add(cube);// 添加灯光const spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(-10, 10, 10);scene.add(spotLight);const animation = () => {cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 渲染renderer.render(scene, camera);requestAnimationFrame(animation);}animation();</script>
</body></html>

添加灯光


五、添加阴影

接下来,我们创建一个平面,模拟出实体旋转时映射到平面上的阴影效果。

平面的创建和实体差不多,都是先创建实例和材质,之后通过 mesh 创建出平面,最后调整到合适的位置添加到场景中即可。

此场景中,我们还创建了个球体,总体创建方式都一样。

<!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>Document</title><script src="../lib/three/three.js"></script><style>* {margin: 0;padding: 0;}</style>
</head><body><script>// 创建场景const scene = new THREE.Scene();// 创建相机 视野角度FOV、长宽比、近截面、远截面const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);// 设置相机位置camera.position.set(0, 0, 20);// 创建渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);// 添加立方体const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);// 创建立方体材质const cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000,wireframe: false});const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 添加到场景scene.add(cube);// 添加球体const sphereGeometry = new THREE.SphereGeometry(1, 10, 10);// 创建球体材质const sphereMatrial = new THREE.MeshBasicMaterial({color: 0x00ff00,wireframe: true})const sphere = new THREE.Mesh(sphereGeometry, sphereMatrial);sphere.position.x = 3;sphere.position.y = 1;// 添加到场景scene.add(sphere);// 添加平面,用来接收阴影const planeGeometry = new THREE.PlaneGeometry(20, 30);const planeMaterial = new THREE.MeshBasicMaterial({color: 0x999999});const plane = new THREE.Mesh(planeGeometry, planeMaterial);plane.rotateZ(20);plane.position.z = -10;plane.position.x = 3;scene.add(plane);// 添加灯光const spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(-10, 10, 90);scene.add(spotLight);// 产生阴影cube.castShadow = true;sphere.castShadow = true;// 接收阴影plane.receiveShadow = true;sphere.receiveShadow = true;// 设置灯光开启阴影spotLight.castShadow = true;renderer.shadowMapEnabled = true;const animation = () => {cube.rotation.x += 0.01;cube.rotation.y += 0.01;sphere.rotation.x += 0.01;sphere.rotation.y += 0.01;// 渲染renderer.render(scene, camera);requestAnimationFrame(animation);}animation();</script>
</body></html>

添加物体阴影


六、添加雾化

添加雾化很简单,我们只需要在场景中添加一个 线性雾 实例即可。

// 雾化
scene.fog = new THREE.Fog(0xffffff, 1, 50);

添加雾化


总结

本篇文章我们熟悉了如何创建场景、怎么渲染出三维对象、如何进行灯光、阴影、雾化的添加等。知识点的总体难度较低,这也是 three.js 的强大之处,它暴露出了很多 API 供我们使用,极大的方便了我们对于实体的创建及操作。

更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. Three.js 官方文档
  2. WebGL+Three.js 入门与实战【作者:慕课网_yancy】

在这里插入图片描述


这篇关于Three.js——创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/870239

相关文章

Window Server2016 AD域的创建的方法步骤

《WindowServer2016AD域的创建的方法步骤》本文主要介绍了WindowServer2016AD域的创建的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、准备条件二、在ServerA服务器中常见AD域管理器:三、创建AD域,域地址为“test.ly”

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用SpringBoot创建一个RESTful API的详细步骤

《使用SpringBoot创建一个RESTfulAPI的详细步骤》使用Java的SpringBoot创建RESTfulAPI可以满足多种开发场景,它提供了快速开发、易于配置、可扩展、可维护的优点,尤... 目录一、创建 Spring Boot 项目二、创建控制器类(Controller Class)三、运行

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一