three.js的基础和使用

three.js的基础和使用

1.threejs引入three.js

  • 项目开发引入threejs,比如vue或react脚手架引入threejs。
    比如你采用的是Vue + threejs或React + threejs技术栈,这很简单,threejs就是一个js库,直接通过npm命令行安装就行
    npm安装特定版本three.js(注意使用哪个版本,查文档就查对应版本)
// 比如安装148版本
npm install three@0.148.0 --save
  • npm安装后,引入three.js
    执行import * as THREE from 'three';,ES6语法引入three.js核心。
// 引入three.js
import * as THREE from 'three';
  • npm安装后,如何引入three.js其他扩展库
    除了three.js核心库以外,在threejs文件包中examples/jsm目录下,你还可以看到各种不同功能的扩展库。

一般来说,你项目用到那个扩展库,就引入那个,用不到就不需要引入

// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';


// 扩展库引入——旧版本,比如122, 新版本路径addons替换了examples/jsm
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

二,基础知识

1、右手坐标系

three.js中使用的都是右手坐标系,即图示右手大拇指指向x轴正向,食指指向y轴正向,中指指向z轴正向,这样的一个三维坐标系。具体来说,x,y坐标用于控制浏览器平面,如果不改变z坐标则物体只在浏览器平面上运动,因此z坐标控制的就是远近
在这里插入图片描述

2、整个程序解构

在这里插入图片描述
程序整个运行过程就是:场景 —— 相机 —— 渲染器

three.js核心组成

1、场景(secne)
/*
 *1. 创建场景  -- 放置物体对象的环境
 */
const scene = new THREE.Scene();
2、相机(camera)
  • 创建透视相机,也称投影相机(PerspectiveCamera)-- 用来模拟人眼所看到的景象
/*
 * 2.创建相机(这里是 透视摄像机--用来模拟人眼所看到的景象)
 */
const camera = new THREE.PerspectiveCamera(
  75, // 视野角度
  window.innerWidth / window.innerHeight, // 长宽比
  0.1, // 进截面
  1000 // 远截面
);
// 设置相机位置
camera.position.set(0, 0, 10);
scene.add(camera); // 将相机添加到场景中
const camera = new THREE.PerspectiveCamera(
        fov : Number,
        aspect : Number,
        near : Number,
        far : Number
)
fov — 摄像机视锥体垂直视野角度 (相机的拍摄视角大小)
aspect — 摄像机视锥体长宽比 (相机拍摄区域的长宽比)
near — 摄像机视锥体近端面 (相机拍摄范围近端距离)
far — 摄像机视锥体远端面 (相机拍摄范围远端距离)
常用:const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
效果:相机拍摄的画面具有近大远小的特性,距离相机近的物体显示的大,距离相机远的物体显示的小。

在 Three 中是没有「长度单位」这个概念的,它的数值都是根据比例计算得出,因此这里提到的 0.1 或 1000 都没有具体的含义,而是一种相对长度
在这里插入图片描述
可以看到,通过配置透视相机的相关参数,最终被渲染到屏幕上的,是在 nearfar 之间,根据 fov 的值和物体远近确定渲染高度,再通过 aspect 值来确定渲染宽度的。
在这里插入图片描述
如图中所示,透视投影相机一共有4个参数:fov(视场,一个角度值), Horizonta Field of View(横向视场),Vertical Field of View(纵向视场),Near plane(近面), Far plane(远面);由这几个因素,构成一个六面体的封闭空间,在这个空间内的一切物体可见。在设置参数时,需满足:

横向视场 / 纵向视场 = 浏览器窗口的宽/浏览器窗口的高。

渲染器(render)

有了场景和相机,我们还需要渲染器把对应的场景用对应的相机可见渲染出来,因此渲染器需要传入场景和相机参数。

/*
 *  3.初始化渲染器-设置渲染器大小及挂载元素
 */
const renderer = new THREE.WebGL1Renderer();
 
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
 
// 清除颜色,第二个参数为 0 表示完全透明,适用于需要透出背景的场景
// renderer.setClearColor(0x000000, 0);
 
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);
 
// 使用渲染器,通过相机将场景渲染出来
renderer.render(scene, camera);
const renderer = new THREE.WebGLRenderer();
document.body.appendChild( renderer.domElement );
实例化一个渲染器,然后将它的dom元素插入到body中,即插入了一个canvas。


也可以将其插入到其他元素中,比如html中有一个<div id='canvas'></div>,就可以写成
document.getElementById('canvas').appendChild( renderer.domElement );这样场景就在这个div中加载了。


注意:设置渲染器的大小,常用的为renderer.setSize( window.innerWidth, window.innerHeight );,如果不设就是默认大小

物体对象-- 包含 几何体(Geometry)、材质(Material)、网格对象(Mesh)

Three 提供了多种类型的几何体,可以分为二维网格和三维网格。二维网格顾名思义只有两个维度,可以通过这种几何体创建简单的二维平面;三维网格允许你定义三维物体;在 Three 中定义一个几何体十分简单,只需要选择需要的几何体并传入相应参数创建即可。常用几何体如下

三维:

在这里插入图片描述

材质(Material)
  • 创建材质:
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x666666 });
const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });
const phongMaterial = new THREE.MeshPhongMaterial({ color: 0x666666 });
const wireMaterial = new THREE.MeshBasicMaterial({ wireframe: true, color: 0x666666 });
网格对象(Mesh)

需要将几何体和材质添加到场景中,还需要依赖 Mesh。Mesh 是用来定义材质和几何体之间是如何粘合的。

或者说 3d物体由点->线->面组成,mesh网格就是由大量的面组成的网格图,再加上材质就创建成物体,新建几何体和材质后,就可以将该物体对象添加到场景中了。

创建网格对象可以应用一个或多个材质和几何体。

网格 = 几何体 + 材质

创建几何体相同材质不同的网格对象

const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
const cubePhong = new THREE.Mesh(cubeGeometry, phongMaterial);

scene.add(cube, cubePhong);
创建材质相同几何体不同的网格对象:

const cube = new THREE.Mesh(cubeGeometry, basicMaterial);
const sphere = new THREE.Mesh(sphereGeometry, basicMaterial);
scene.add(cube, sphere);

创建拥有多个材质几何体的网格对象:

 const phongMaterial = new THREE.MeshPhongMaterial({ color: 0x666666 });
const cubeMeshPhong = new THREE.Mesh(cubeGeometry, cubePhongMaterial);
const cubeMeshWire = new THREE.Mesh(cubeGeometry, wireMaterial);
// 网格对象新增材质
cubeMeshPhong.add(cubeMeshWire);
scene.add(cubeMeshPhong);

有了场景、相机和渲染器,再加上物体,我们已经可以看到初步的效果了。但3D世界里,静止的物体多无趣啊。于是我们尝试加入动画效果.。

5、帧循环,游戏循环

// 定义循环渲染方法
function render() {
  // 物体动态移动位置 -- 沿x轴
  cube.position.x += 0.01;
  if (cube.position.x > 7) {
    cube.position.x = 0;
  }
  // 物体动态旋转
  cube.rotateX(0.01); //每次绕y轴旋转0.01弧度
  // cube.rotation.x += 0.01;
 
  renderer.render(scene, camera); // 执行渲染操作
  requestAnimationFrame(render); // 渲染下一帧的时候就会调用render函数
}
render();

灯光

1、灯光用来为场景添加光源,照明物体,虽然部分材质(如MeshBasicMaterial)不会受到灯光的影响,无需添加灯光也能看见,但是这种材质的物体没有质感,也没有明暗变化;如果想让物体更接近真实场景的物体,就需要可以被灯光影响的材质,如MeshLamberMaterial,如果不添加光源就无法看到物体。
2、灯光分为点光源,线光源,面光源等,可依据实际场景进行选择,正如真实场景的光源情况,three.js允许添加多个灯光从而对真实场景进行模拟。
添加灯光方法:
const light = new THREE.AmbientLight( 0x404040 ); 
scene.add( light );

在这里插入图片描述

辅助线

// 三维辅助线(长度)-- 三维坐标系
const axisHelper = new THREE.AxisHelper(7);
scene.add(axisHelper);
 
// 网格辅助线 -- 地表格(网格宽度、等分数、中心线颜色,网格线颜色)
const grid = new THREE.GridHelper(1000, 1000, 0xff0000, 0xff0000);
scene.add(grid);
轨道控制器查看物体(鼠标控制)
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
 
/**
 * 创建轨道控制器(OrbitControls)
 * 可以使得相机围绕目标进行轨道运动
 */
const controls = new OrbitControls(camera, renderer.domElement);
controls.autoRotate = true; // 相机是否自动旋转
controls.autoRotateSpeed = 3; // 自转速度
// 设置控制器阻尼,让控制器更有真实效果,必须在动画循环render()中调用controls.update()()
controls.enableDamping = true;

设置控制器阻尼,必须在动画循环render()中调用controls.update()()

// 定义循环渲染方法
function render() {
  // 动态移动位置
  cube.position.x += 0.01;
  if (cube.position.x > 7) {
    cube.position.x = 0;
  }
  //动态旋转
  cube.rotateX(0.01); //每次绕y轴旋转0.01弧度
  // cube.rotation.x += 0.01;
 
  renderer.render(scene, camera); // 执行渲染操作
 
  controls.update(); // controls控制特定属性时加
 
  requestAnimationFrame(render); // 渲染下一帧的时候就会调用render函数
}
render();

拓展

  • 根据尺寸变化实现自适应画面
// 监听尺寸变化实现自适应画面
window.addEventListener("resize", () => {
  // console.log("画面变化了");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio);
});
  • 在学习环境中实现
    示例:通过script标签和CDN来引入three.min.js,实现一个旋转的球:
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <title>My First three.js app2</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
    <script src='https://cdn.bootcss.com/three.js/91/three.min.js'></script>
</head>
 
<body>
    <script>
        //创建场景
        const scene = new THREE.Scene();
        //创建透视投影相机,视角45度,画幅比例 宽比高,近平面距离0.1,远平面1000
        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
        //创建渲染器
        const renderer = new THREE.WebGLRenderer();
        //渲染器canvas宽高设为与窗口一致
        renderer.setSize(window.innerWidth, window.innerHeight);
        //将渲染器对应的dom元素添加到body中
        document.body.appendChild(renderer.domElement);
        //定义一个几何体
        const geometry = new THREE.SphereGeometry(3, 30, 30);
        //定义一种材质,显示为线框
        const material = new THREE.MeshBasicMaterial({ color: 0xB3DD, wireframe: true });
        //网孔(Mesh)是用来承载几何模型的一个对象,可以把材料应用到它上面
        const ball = new THREE.Mesh(geometry, material);
        //把几何模型添加到场景中,对象被添加到原点(0,0,0)坐标。
        scene.add(ball);
        //移动相机位置
        camera.position.z = 8;
        function render() {
            //渲染循环,以每秒60次的频率来绘制场景
            requestAnimationFrame(render);
            //设置球体绕y轴旋转
            ball.rotation.y += 0.005;
            renderer.render(scene, camera);
        }
        render();
    </script>
</body>
 
</html>

效果如下:
在这里插入图片描述

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值