ThreeJS快速入门指南

news2024/11/16 7:33:49

Three.js 介绍

Three.js 是一个开源的应用级 3D JavaScript 库,可以让开发者在网页上创建 3D 体验。Three.js 屏蔽了 WebGL的底层调用细节,让开发者能更快速的进行3D场景效果的开发。

Three.js的开发环境搭建

  • 创建目录并使用 npm init -y 初始化 package.json
  • 使用 npm install --save-dev parcel 安装 Web 应用打包工具 parcel
  • 这一步不是必须的,可以使用其他打包工具例如 webpack
  • 在目录中新建 src/index.htmlsrc/script.js 两个文件
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Three.js入门</title>
  </head>
  <body>
    <script src="./script.js" type="module"></script>
  </body>
</html>
script.js文件中会使用到import模块化语法,所以引入文件需要加上type=“module”
  • package.json 中加入 "start": "parcel src/index.html" 脚本
  • 使用 npm install three 引入 Three.js
  • src/script.js 文件中验证 Three.js 是否引入成功
import * as THREE from "three";
console.log(THREE);

Three.js的一些重要概念

开发一个Three.js的场景,需要如下一些元素:
  • scene 场景
场景像一个容器(container),可以将物体(模型,粒子,光源,相机等)加入其中。
  • objects 物体
物体可以有很多种,比如原始的几何体,导入的模型 ,粒子,光源等。
  • camera 相机
理论上的视角,虽然相机也被加入了场景中,但是相机是看不见的
  • renderer 渲染器
从相机的角度渲染场景,结果将被绘制到 canvas 中
  • 透视相机
Three.js最常使用的是透视相机,它是模拟人的观察视角:物体近大远小。透视相机有四个构造参数
constructor(fov?: number, aspect?: number, near?: number, far?: number);

在这里插入图片描述

  1. 视野(The field of view)
  2. 宽高比(Aspect) 纵横比需要设置为画布的宽度除以其高度,否则会造成场景中物体变形
  3. 近平面距离(Near) 比近平面距离近的物体将不会被渲染,也就是说不能被看见
  4. 远平面距离(Far) 比远平面距离远的物体将不会被渲染,也不能被看见

Three.js的第一个场景

我们了解了基本的概念后,可以开始写代码了。

// 1. 创建渲染器,指定渲染的分辨率和尺寸,然后添加到body中
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.pixelRatio = window.devicePixelRatio;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);

// 2. 创建场景
const scene = new THREE.Scene();

// 3. 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

// 4. 创建物体
const axis = new THREE.AxesHelper(5);
scene.add(axis);

// 5. 渲染
renderer.render(scene, camera);
  • 创建渲染器,并将渲染器设置为body的尺寸大小,然后将渲染器的Canvas添加body中;
  • 创建场景;
  • 创建相机,设置75度视野,相机的纵横比设置为画布的宽度除以其高度,近平面距离为0.01,远平面距离为1000;
  • 创建了一个坐标辅助线物体,用来标识坐标位置;
  • 用渲染器进行渲染,传递的参数是场景和相机两个参数。

结果令人遗憾,什么也看不到,屏幕上是一片黑暗。

在这里插入图片描述

如果需要了解原因,需要知道一个重要的概念:坐标系统。

坐标系统

Three.js使用的是右手坐标系,这源于OpenGL默认情况下,也是右手坐标系。x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外。

在这里插入图片描述

所有的物体默认是摆放在坐标原点位置,也就是(0,0,0)这个位置。

由于透视相机和物体都是放在同一个位置,也就是距离是0。并且相机也默认看向的(0,0,0)这个点,所以透视相机不会渲染内容。

移动相机

为了解决这问题,可以移动相机也可以移动物体。默认是移动相机位置。

同时设置:

camera.position.set(5, 5, 10);

或者单独设置

camera.position.z = 10;
camera.position.x = 5;
camera.position.y = 5;

移动了相机,还需要设置相机看向原点的方向

camera.lookAt(0, 0, 0);

在这里插入图片描述

这时候就可以看到坐标辅助线了。

Geometry和Material

我们想创建一个立方体,我们需要创建一种名为Mesh的对象。Mesh是几何(形状)和材质(外观如何)的组合。

// 添加立方体
const geometry = new THREE.BoxGeometry(4, 4, 4);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
  • 创建长宽高都为4的立方几何体;
  • 立方体的表明颜色为红色的材质;
  • 将集合体和材质组合为Mesh对象;
  • 将Mesh对象添加到场景中。

在这里插入图片描述

动画

开发者都知道动画本质上是不同的重绘,由于物体的位置、大小、材质和缩放等的不同而形成了视觉上的动画。

通过rotate设置旋转度角:

cube.rotation.y = Math.PI / 4;

在这里插入图片描述

不断旋转角度:

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}

animate();
  • 通过 requestAnimationFrame 不断的回调 animate 函数;
  • animate 函数中先将旋转角度增加 0.01 度,然后调用 renderer.render(scene, camera) 进行重新绘制。

在这里插入图片描述

优化:

requestAnimationFrame 函数的调用频率取决于浏览器的刷新率,实际的刷新率可能因浏览器、硬件性能以及当前页面的负载而有所不同。

可以使用 three.js 中内置的 Clock 来解决这个问题。

const clock = new THREE.Clock();

function animate() {
  requestAnimationFrame(animate);

  const elapsedTime = clock.getElapsedTime(); // 返回已经过去的时间, 以秒为单位
  cube.rotation.y = elapsedTime * Math.PI; // 两秒自转一圈

  renderer.render(scene, camera);
}

通过使用 Clock 就能保证两秒自转一圈。

添加交互

到目前位置,用户是无法和场景进行交互的,为了能够和场景进行交互,可以添加一个控制器 OrbitControls

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

const controls = new OrbitControls(camera, renderer.domElement);
controls.update();

通过上面的代码,用户就可以用对场景内容进行旋转、放大缩小等操作。

在这里插入图片描述

添加光源

three.js中有三种重要的光源:环境光源,方向光源和点光源。

  • 环境光(Ambient Light):环境光是一种均匀的光照,它会均匀地照亮场景中的所有物体,不考虑光照源的位置和方向。
  • 方向光(Directional Light):方向光是一种平行光源,它具有确定的方向和强度,类似于太阳光。
  • 点光源(Point Light):点光源是一种位于特定位置的光源,它向所有方向发射光线,类似于灯泡。
// 1.
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });

// 2.
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);

// 3.
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10, 0, 10);
scene.add(directionalLight);
  • 因为MeshBasicMaterial不受光源的影像,所以需要将Material改成MeshStandardMaterial;
  • 添加一个白色透明度为0.4的环境光,这个环境光会均匀地照亮场景中的所有物体表面,并且使用PBR(Physically-Based Rendering)渲染模型和材质自身的颜色进行混合得到新的颜色;
  • 添加一个白色的方向光,方向光从(10, 0, 10)照向原点(10, 0, 10), 所以有两个面会收到这个方向光,表面的颜色会更偏亮。

在这里插入图片描述

阴影

在现实生活中,有光照的情况下会产生阴影,three.js也能很容易实现这种效果。

// 1. 渲染器能够渲染阴影效果
renderer.shadowMap.enabled = true;

// 2. 该方向会投射阴影效果
directionalLight.castShadow = true;

// 3. 
cube.castShadow = true;

// 4. 
const planeGeometry = new THREE.PlaneGeometry(20, 20);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff });
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
planeMesh.rotation.x = -0.5 * Math.PI;
planeMesh.position.set(0, -3, 0);
planeMesh.receiveShadow = true;
scene.add(planeMesh);

// 5. 方向光的辅助线
const directionalLightHelper = new THREE.DirectionalLightHelper(
  directionalLight
);
scene.add(directionalLightHelper); // 辅助线
  • 将渲染器的shadowMap.enabled设置为true, 表示渲染器能够渲染阴影效果;
  • directionalLight.castShadow = true,表示该方向会投射阴影效果;
  • cube.castShadow = true, 表示该立方体会产生影像效果;
  • 新建了一个平面,该平面能够接受投射过来的阴影效果;
  • 为了清晰展示方向光的方向和位置,添加了一个辅助线。

在这里插入图片描述

纹理

除了颜色外,对几何体材质添加纹理是非常重要和常见的操作。我们接下来给平面和立方体添加纹理实现。

地板纹理:

// 1. 引入图片
import floor from "./images/floor_wood.jpeg";

// 2. 初始化纹理加载器
const textloader = new THREE.TextureLoader();

// 3. 给地板加载纹理
const planeMaterial = new THREE.MeshStandardMaterial({
  map: textloader.load(floor),
});

在这里插入图片描述

立方体纹理:

前面方式添加的纹理会给几何体的每个面都设置为相同的纹理,接下来我们为不同的面设置不同的纹理。

// 立方体的顶部纹理
import grass_top from "./images/grass_top.png";
// 立方体的侧边纹理
import grass_side from "./images/grass_side.png";
// 立方体的底部纹理
import grass_bottom from "./images/grass_bottom.png";

const geometry = new THREE.BoxGeometry(4, 4, 4);
const material = [
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_side),
  }),
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_side),
  }),
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_top),
  }),
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_bottom),
  }),
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_side),
  }),
  new THREE.MeshBasicMaterial({
    map: textloader.load(grass_side),
  }),
];
const cube = new THREE.Mesh(geometry, material);

在构造 Mesh 对象的时候,传入6个 MeshBasicMaterial 对象的数组,数组的纹理顺序是: x正方向轴的面,x负方向轴的面,y正方向轴的面,y负方向轴的面,z正方向轴的面,z负方向轴的面。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Laravel 10.x 里如何使用ffmpeg

原理上很简单&#xff0c;就是使用命令行去调用ffmpeg&#xff0c;然后分析一下输出是不是有错误。 安装 首先安装 symfony/process&#xff0c;主要用于包装一下&#xff0c;用来代替 exec, passthru, shell_exec and system 。 composer require symfony/process composer…

像素图片在网页中很模糊怎么办?输入这个样式

像素图片在网页中很模糊怎么办&#xff1f;输入这个样式 image-rendering: pixelated;输入前 输入后

java数据结构与算法刷题-----LeetCode378. 有序矩阵中第 K 小的元素

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 已知矩阵相对有序&#xff0c;可以用二分搜索&#xff0c;不过和…

Ultraleap 3Di配置以及在 Unity 中使用 Ultraleap 3Di手部跟踪

0 开发需求 1、硬件&#xff1a;Ultraleap 手部追踪相机&#xff08;Ultraleap 3Di&#xff09; 2、软件&#xff1a;在计算机上安装Ultraleap Gemini (V5.2) 手部跟踪软件。 3、版本&#xff1a;Unity 2021 LTS 或更高版本 4、Unity XR插件管理&#xff1a;可从软件包管理器窗…

Pyside6在Pycharm下安装和使用

目录 一&#xff1a;安装 二&#xff1a;使用 一&#xff1a;安装 打开Pycharm编辑器&#xff0c;file-setting里Python解释器&#xff0c;点击小号&#xff0c;添加模块&#xff0c;搜索Pyside6,安装 安装报错&#xff0c;可能是默认的库安装超时&#xff0c;用其他的源 p…

【论文阅读笔记】Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation

1.介绍 Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation Swin-Unet&#xff1a;用于医学图像分割的类Unet纯Transformer 2022年发表在 Computer Vision – ECCV 2022 Workshops Paper Code 2.摘要 在过去的几年里&#xff0c;卷积神经网络&#xff…

深入理解Kubernetes探针和.NET服务健康检查机制

前言 随着越来越多的软件采用云原生和微服务架构&#xff0c;我们面临着更多的技术挑战&#xff0c;比如&#xff1a; Kubernetes如何在容器服务异常终止、死锁等情况下&#xff0c;发现并自动重启服务&#xff1b;当服务依赖的关键服务&#xff08;例如数据库&#xff0c;Red…

[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07-3 线性二次型调节器(LQR)

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-3 线性二次型调节器&#xff08;LQR&#xff09; 1. 数学推导2. 案例反洗与代码详解 1. 数学推导 2. 案例反洗与代码详解

RK3568笔记十一:mpp编解码

若该文为原创文章&#xff0c;转载请注明原文出处。 主要是想测试MPP的解码&#xff0c;为后续做测试。 一、环境 1、平台&#xff1a;rk3568 2、开发板:ATK-RK3568正点原子板子 3、环境&#xff1a;buildroot 二、编译 使用的是正点原子提供的虚拟机&#xff0c;搭建好环…

TensorRT部署--Linux(Ubuntu)环境配置

系列文章目录 TensorRT环境配置–Linux(Ubuntu) 文章目录 系列文章目录前言一、环境配置二、CUDA下载安装三、cuDNN下载安装四、TensorRT下载安装五、模型创建总结 前言 TensorRT部署-Windows环境配置: https://blog.csdn.net/m0_70420861/article/details/135658922?csdn_s…

写着玩的程序:pycharm实现无限弹窗程序(非病毒程序,仅整蛊使用)

运行环境 PyCharm 2023.2.1 python3.11 具体内容 源代码 import tkinter as tk from tkinter import messagebox import threadingclass PopupGenerator:def __init__(self):self.root tk.Tk()self.root.geometry("200x120")self.root.title("无限弹窗&qu…

《WebKit 技术内幕》学习之十(2): 插件与JavaScript扩展

2 Chromium PPAPI插件 2.1 原理 插件其实是一种统称&#xff0c;表示一些动态库&#xff0c;这些动态库根据定义的一些标准接口可以跟浏览器进行交互&#xff0c;至于这个标准接口是什么都可以&#xff0c;重要的是大家都遵循它们&#xff0c;NPAPI接口标准只是其中的一种&a…

C# CefSharp 输入内容,点击按钮,并且滑动。

前言 帮别人敲了个Demo,抱试一试心态&#xff0c;居然成功了&#xff0c;可以用。给小伙伴们看看效果。 遇到问题 1&#xff0c;input输入value失败&#xff0c;里面要套了个事件&#xff0c;再变换输入value。后来用浏览器开发工具&#xff0c;研究js代码&#xff0c;太难了&a…

IMX6ULL|GPIO子系统

一.GPIO子系统 GPIO是General Purpose I/O的缩写&#xff0c;即通用输入输出端口&#xff0c;简单来说就是MCU/CPU可控制的引脚&#xff0c;这些引脚通常有多种功能&#xff0c;最基本的是高低电平输入检测和输出&#xff0c;部分引脚还会与主控器的片上外设绑定&#xff0c;如…

Spring Boot3整合knife4j(swagger3)

目录 1.前置条件 2.导依赖 3.配置 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动。 作者版本为3.2.2最新版 2.导依赖 knife4j官网&#xff1a; Knife4j 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j (xiaominfo.com)http…

Unity - 简单音频

“Test_04” AudioTest public class AudioTest : MonoBehaviour {// 声明音频// AudioClippublic AudioClip music;public AudioClip se;// 声明播放器组件private AudioSource player;void Start(){// 获取播放器组件player GetComponent<AudioSource>();// 赋值…

Django ORM 中高级单表查询 API(2)

Django ORM 中的单表查询 API&#xff08;1&#xff09;https://blog.csdn.net/Python_1981/article/details/135653173 在上一篇博文中&#xff0c;我们探讨了 Django ORM 中单表查询 API 的基础知识&#xff0c;重点是 all()、filter()、get()、first() 和 last()。在…

记一次 stackoverflowerror 线上排查过程

一.线上 stackOverFlowError xxx日,突然收到线上日志关键字频繁告警 classCastException.从字面上的报警来看,仅仅是类型转换异常,查看细则发现其实是 stackOverFlowError.很多同学面试的时候总会被问到有没有遇到过线上stackOverFlowError?有么有遇到栈溢出?具体栈溢出怎么来…

Javat集合之Lis---(ArrayList和LinkedList)

文章目录 一、 List概述1.1概念1.2list体系结构图1.3 通用方法测试代码 二、List的特点三、遍历方式foreachfor循环迭代器 四、ArrayListArrayList概述概念数据结构 ArrayList的特点 ArrayList去重字符串去重对象去重 五、LinkedListLinkedList概述概念数据结构LinkedList的特点…

FTP网络文件共享服务

ftp的存储类型 1.直连式&#xff1a;距离最近&#xff0c;存储设备爱只连接到服务器上&#xff0c;速度最快&#xff0c;因为不经过网络 2.存储区域网络&#xff08;SAN&#xff09;&#xff1a;适用于大型应用或数据库系统&#xff0c;可以使用空间&#xff0c;也可以管理。…