首页 > 其他分享 >Three.js快速入门

Three.js快速入门

时间:2024-03-20 13:34:12浏览次数:26  
标签:const 入门 THREE Three 相机 camera new js

Three.js 介绍

  • 创建目录并使用 npm init -y 初始化 package.json

  • 使用 npm install --save-dev parcel 安装 Web 应用打包工具 parcel

    • 这一步不是必须的,可以使用其他打包工具例如 webpack 等

  • 在目录中新建 src/index.html 和 src/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)

    • 视野(fov)以度为单位表示,表示视觉角度的大小。

    • 角度越大看到的范围越大,但是太大就会造成场景中物体变形。

    • 一般45~75会比较合适

  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负方向轴的面。 

标签:const,入门,THREE,Three,相机,camera,new,js
From: https://blog.csdn.net/u012148903/article/details/136871764

相关文章

  • 企业身份认证接口-身份证实名认证接口免费调用-Node.js接口调用教程
    现如今,无论是银行开户、办理社保、购买保险、在线教育、电商购物等等的应用场景,都需要进行身份证的实名认证。随着人工智能技术的不断开拓与创新,身份证实名认证已经逐步实现了智能化、在线化。也正因如此,企业对于身份证实名认证接口的需求也在不断增多。翔云身份证识别接口与身份......
  • 基于Java的校园电商物流云平台(Vue.js+SpringBoot)
    目录一、摘要1.1项目介绍1.2项目录屏二、功能模块2.1数据中心模块2.2商品数据模块2.3快递公司模块2.4物流订单模块三、系统设计3.1用例设计3.2数据库设计3.2.1商品表3.2.2快递公司表3.2.3物流订单表四、系统展示五、核心代码5.1查询商品5.2查询快递公......
  • Android视角看鸿蒙第七课(module.json5中的各字段含义之abilities)
    Android视角看鸿蒙第七课(module.json5中的各字段含义之abilities)导读今天一起来了解module.json5中的最后一个字段,也是最复杂的字段abilities官方文档Indicatesallabilitiesinthecurrentmodule.Thevalueisanarrayofobjects,eachofwhichrepresentsan......
  • 基于Java的医院门诊预约挂号系统(Vue.js+SpringBoot)
    目录一、摘要1.1项目介绍1.2项目录屏二、功能模块2.1功能性需求2.1.1数据中心模块2.1.2科室医生档案模块2.1.3预约挂号模块2.1.4医院时政模块2.2可行性分析2.2.1可靠性2.2.2易用性2.2.3维护性三、数据库设计3.1用户表3.2科室档案表3.3医生档案表3.4......
  • 基于Java的考研专业课程管理系统(Vue.js+SpringBoot)
    目录一、摘要1.1项目介绍1.2项目录屏二、功能模块2.1数据中心模块2.2考研高校模块2.3高校教师管理模块2.4考研专业模块2.5考研政策模块三、系统设计3.1用例设计3.2数据库设计3.2.1考研高校表3.2.2高校教师表3.2.3考研专业表3.2.4考研政策表四、系统展......
  • fastjson记录
    参考指南fastjson:我一路向北,离开有你的季节|素十八(su18.org)Java反序列化漏洞始末(3)—fastjson-浅蓝'sblog(b1ue.cn)梅子酒の笔记本(meizjm3i.github.io)fastjson基础早期版本的fastjson的框架图fastjson功能要点:fastjson在创建一个类实例时会通过反射......
  • 【附源码】Node.js毕业设计服装创意定制管理系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着互联网技术的飞速发展,人们对于个性化、定制化的需求日益增长。在服装行业,传统的成品服装销售模式已经无法满足消费者对于个性化、独特性的追求。因此,越......
  • 【附源码】Node.js毕业设计扶贫助农系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在现代社会,随着科技的不断发展和互联网技术的进步,信息技术已经深入到各个领域中,对人们的生产和生活方式产生了深远的影响。特别是在农业领域,传统的农业生产......
  • 【小猪学渗透】打靶第2天:DVWA入门:暴力破解、命令注入、文件上传
    暴力破解low题目界面如上先抓个包试试,发送到intruder可以看到用GET数据包传输,username和password都是直接写在了url上在password后面的数字上加上$123$这样好进行替换。报错,没有加载字典,在知乎上找到了一篇文章讲字典的找到了一个老的字典库开始攻击,发现......
  • 【小猪学渗透】打靶第1天:DVWA入门:SQL注入、SQL盲注
    前言小猪同学正式开始了渗透测试的学习,今天是入门打靶DWVA--真是开心的一天呢--参考文章这是一篇来自于csdn的攻略文开始-环境搭建小猪同学已经事先搭建好了靶场。sql手工注入low输入1and1=1判断注入点输入1’and1=1报错发现注入点,受到单引号闭合的影响......