一、threejs 学习笔记-基础入门

友情链接:threejs 中文文档

目录

1. threejs文件包下载及目录简介

(1) 文件包下载

(2) 特定版本文件包下载

 2. 引入threejs

(1) vue或react框架环境引入

(2) html环境 

3. 创建场景

(1) 三维场景

(2) 几何体

(3) 物体外观:材质Material

(4) 物体:网格模型Mesh

(5) 模型位置.potion 

(6) .add() 方法

4. 透视投影相机

(1) 创建透视投影相机

(2) 相机方法介绍

 (3) 透视投影相机参数介绍

5. 渲染器

(1) 渲染器基础配置

(2) 渲染器重复渲染

6. 相机控件OrbitControls

(1) 引入OrbitControls文件库

(2) 使用OrbitControls 

7. 光源

 平行光和环境光的使用

8. gui.js库

9. gui.js库方法

10. gui.js 生成下拉菜单、单选框

11. gui.js 分组

小案例分享

1. threejs文件包下载及目录简介

(1) 文件包下载

npm命令下载

npm install [email protected] --save

(2) 特定版本文件包下载

github链接查看所有版本threejs:https://github.com/mrdoob/three.js/releases

如果你那边gihtub打不开或下载很慢,你可以使用下面提供的网盘资源下载。

网盘链接: https://pan.baidu.com/s/1_Ix8TiOScypNcQe3BIl5vA?pwd=rrks提取码:rrks

 2. 引入threejs

(1) vue或react框架环境引入

// 引入three.js
import * as THREE from 'three';

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

(2) html环境 

<script type="module">
// 现在浏览器支持ES6语法,自然包括import方式引入js文件
import * as THREE from './build/three.module.js';
</script>

<!-- 具体路径配置,需要根据自己文件目录设置 -->
<script type="importmap">
    {
		"imports": {
			"three": "../../../three.js/build/three.module.js"
		}
	}
</script>

3. 创建场景

入门Three.js的第一步,就是认识场景Scene相机Camera渲染器Renderer三个基本概念。

(1) 三维场景

你可以把三维场景Scene对象理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界。 

// 创建3D场景对象Scene
const scene = new THREE.Scene();

 (2) 几何体

Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。

 (3) 物体外观:材质Material

如果你想定义物体的外观效果,比如颜色,就需要通过材质Material相关的API实现。

threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质MeshBasicMaterial 为例给大家实现一个红色材质效果。

//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
    color: 0xff0000,//0xff0000设置材质颜色为红色
}); 

(4) 物体:网格模型Mesh

​实际生活中有各种各样的物体,在threejs中可以通过网格模型Mesh表示一个虚拟的物体,比如一个箱子、一个鼠标。 ​

// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh

(5) 模型位置.potion 

实际生活中,一个物体往往是有位置的,对于threejs而言也是一样的,你可以通过位置属性.position定义网格模型Mesh在三维场景Scene中的位置。

(6) .add() 方法

在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。

scene.add(mesh); 

4. 透视投影相机

(1) 创建透视投影相机

// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

(2) 相机方法介绍

// .position 设置相机位置
camera.position.set(200, 200, 200);

// .lookAt 设置观察目标位置
camera.lookAt(0, 10, 0);

 (3) 透视投影相机参数介绍

PerspectiveCamera( fov, aspect, near, far )
参数 含义 默认值
fov 相机视锥体竖直方向视野角度 50
aspect 相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height 1
near 相机视锥体近裁截面相对相机距离 0.1
far 相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向 2000

5. 渲染器

生活中如果有了景物和相机,那么如果想获得一张照片,就需要你拿着相机,按一下,咔,完成拍照。对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer 。

(1) 渲染器基础配置

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
    antialias:true,  // 开启抗锯齿
});

// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);

// 设置背景颜色
renderer.setClearColor(0x444444, 1);

// 设置three.js渲染区域的尺寸(像素px)
renderer.setSize(800, 500); 

// 执行渲染操作
renderer.render(scene, camera);

// 添加到页面元素中
document.body.appendChild(renderer.domElement); 

(2) 渲染器重复渲染

threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame实现动画渲染

// 渲染函数
function render() {
    renderer.render(scene, camera); //执行渲染操作
    requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();

6. 相机控件OrbitControls

平时开发调试代码,或者展示模型的时候,可以通过相机控件OrbitControls实现旋转缩放预览效果。

  • 旋转:拖动鼠标左键
  • 缩放:滚动鼠标中键
  • 平移:拖动鼠标右键

(1) 引入OrbitControls文件库

// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

(2) 使用OrbitControls 

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
    renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件

7. 光源

在threejs中,需要设置光源来照亮我们的场景,常用的光源有点光源PointLight、平行光DirectionalLight、环境光AmbientLight

 平行光和环境光的使用

//环境光:没有特定方向,整体改变场景的光照明暗 
const ambient = new THREE.AmbientLight(0xffffff, 0.4); 
scene.add(ambient); 

// 平行光:有光源位置方向和光源指向方向 
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); 
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算 directionalLight.position.set(80, 100, 50); 
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0 
directionalLight.target = mesh; 
scene.add(directionalLight);

8. gui.js库

gui.js就是一个前端js库,对HTML、CSS和JavaScript进行了封装,学习开发的时候,借助gui.js可以快速创建控制三维场景的UI交互界面

// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 实例化一个gui对象
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';

//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
    x: 30,
};
// gui增加交互界面,用来改变obj对应属性
gui.add(obj, 'x', 0, 100);

 

9. gui.js库方法

// .name()方法 改变gui生成交互界面显示的内容
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度');

// .step()方法 设置交互界面每次改变属性值间隔是多少 
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度').step(0.1);

// .onChange()方法 返回一个监听属性值的函数
const obj = {
    x: 30,
};
// 当obj的x属性变化的时候,就把此时obj.x的值value赋值给mesh的x坐标
gui.add(obj, 'x', 0, 180).onChange(function(value){
    mesh.position.x = value;
	// 你可以写任何你想跟着obj.x同步变化的代码
	// 比如mesh.position.y = value;
});

// .addColor()生成颜色值改变的交互界面
const obj = {
    color:0x00ffff,
};
// .addColor()生成颜色值改变的交互界面
gui.addColor(obj, 'color').onChange(function(value){
    mesh.material.color.set(value);
});

10. gui.js 生成下拉菜单、单选框

// 如果参数3、参数4数据类型为数字,则gui生成拖动条
gui.add(obj, 'x', 0, 180).onChange(function (value) {
    mesh.position.x = value;
});

// 如果参数3数据类型为数组,则gui生成下拉菜单
const obj = {
    scale: 0,
};
gui.add(obj, 'scale', [-100, 0, 100]).name('y坐标').onChange(function (value) {
    mesh.position.y = value;
});

// 如果参数3数据类型为对象,gui也生成下拉菜单
const obj = {
    scale: 0,
};
gui.add(obj, 'scale', {
    left: -100,
    center: 0,
    right: 100
}).name('位置选择').onChange(function (value) {
    mesh.position.x = value;
});

// 如果参数为布尔类型,则gui生成单选框
const obj = {
    bool: false,
};
gui.add(obj, 'bool').name('是否旋转');

11. gui.js 分组

// 当gui交互界面要控制的属性过多的情况下,为了避免混合,需要用到分组管理
// 通过gui对象的.addFolder()方法可以创建一个子菜单
// .close()关闭菜单和.open()展开菜单

const gui = new GUI(); //创建GUI对象 
const obj = {
    color: 0x00ffff,// 材质颜色
};
// 创建材质子菜单
const matFolder = gui.addFolder('材质');
matFolder.close();
// 材质颜色color
matFolder.addColor(obj, 'color').onChange(function(value){
    material.color.set(value);
});
// 材质高光颜色specular
matFolder.addColor(obj, 'specular').onChange(function(value){
    material.specular.set(value);
});
// 创建环境光子菜单
const ambientFolder = gui.addFolder('环境光');
// 环境光强度
ambientFolder.add(ambient, 'intensity',0,2);
// 平行光强度
dirFolder.add(directionalLight, 'intensity',0,2);
// 平行光位置
dirFolder.add(directionalLight.position, 'x',-400,400);
dirFolder.add(directionalLight.position, 'y',-400,400);
dirFolder.add(directionalLight.position, 'z',-400,400);

小案例分享

import * as THREE from 'three';
import {
    OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 创建帧率显示器
const stats = new Stats();
document.body.appendChild(stats.domElement);

// 创建GUI对象
const gui = new GUI();
// 创建三维场景
const scene = new THREE.Scene();

// 创建立方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// 创建材质对象
const material = new THREE.MeshLambertMaterial({
    color: '#008B8B',
    transparent: true, //开启透明
    opacity: 0.7, //设置透明度
});

// 循环创建多个几何体
for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.set(i * 200, 0, j * 200);
        scene.add(mesh);
    }
}

// 创建圆柱体
const CylinderGeometry = new THREE.CylinderGeometry(50, 50, 200, 32);
const MeshBasicMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const cylinder = new THREE.Mesh(CylinderGeometry, MeshBasicMaterial);
cylinder.position.set(-400, 0, -400)
scene.add(cylinder);

// 创建坐标轴
const axesHelper = new THREE.AxesHelper(2000);
scene.add(axesHelper)


// 创建环境光
const ambient = new THREE.AmbientLight('#ffffff', 1.2);
ambient.position.set(80, 120, 70);
scene.add(ambient);

// 创建平行光
const directional = new THREE.DirectionalLight('#ffffff', 2);
directional.position.set(200, 120, 200);
directional.target = cylinder;
scene.add(directional);

gui.add(directional.position, 'x', 0, 2000);
gui.add(directional.position, 'y', 0, 2000);
gui.add(directional.position, 'z', 0, 2000);

// 获取浏览器的宽和高
const width = window.innerWidth;
const height = window.innerHeight;

// 创建透视相机 30:相机角度; width/height:画布宽高比; 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(60, width / height, 10, 6000);
camera.position.set(1000, 3000, 3000);
camera.lookAt(1000, 0, 0);

// 创建渲染器
const renderer = new THREE.WebGLRenderer({
    antialias: true,
});
// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);
// 设置背景颜色
renderer.setClearColor(0x444444, 1);
// 定义渲染区域大小
renderer.setSize(width, height);
// 执行渲染
renderer.render(scene, camera);
// 将渲染器绑定到元素上
document.getElementById('map').appendChild(renderer.domElement);

// 循环渲染
function render () {
    renderer.render(scene, camera);
    //渲染循环中执行stats.update()来刷新时间
    stats.update();
    // 网格绕y轴增加弧度
    cylinder.rotateY(0.005);
    // 在下次重绘之前执行render函数
    window.requestAnimationFrame(render);
}
render();

// 创建相机轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 创建相机轨道控制器后会重置相机的lookAt()参数
controls.target.set(1000, 0, 0);
controls.update();

window.onresize = function () {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
}

 

 文章中部分素材选取自Threejs中文网:Three.js中文网

猜你喜欢

转载自blog.csdn.net/weixin_60645637/article/details/131487422