自学内容网 自学内容网

Three.js 官方文档学习笔记

Address:Three.js中文网 (webgl3d.cn)

Author:方越 50041588

Date:2024-07-19

img

第一个3D案例—创建3D场景

创建3D场景对象Scene:

const scene = new THREE.Scene();

创建一个长方体几何对象Geometry:

const geometry = new THREE.BoxGeometry(100, 100, 100); 

常见几何体对象如下:

创建一个材质对象Material:

const material = new THREE.MeshBasicMaterial({
    color: 0xff0000,//0xff0000设置材质颜色为红色
}); 

常见材质对象如下:

创建一个网格模型对象Mesh,两个参数分别为几何体geometry、材质material:

const mesh = new THREE.Mesh(geometry, material);

设置网格模型在三维空间中的位置坐标,默认是坐标原点:

mesh.position.set(0,10,0);

把网格模型mesh添加到三维场景scene中:

scene.add(mesh); 

第一个3D案例—透视投影相机

实例化一个透视投影相机对象:

const camera = new THREE.PerspectiveCamera();

相机在Three.js三维坐标系中的位置,根据需要设置相机位置具体值:

camera.position.set(200, 200, 200); 

相机观察目标指向Threejs 3D空间中某个位置:

camera.lookAt(0, 0, 0); //坐标原点
camera.lookAt(0, 10, 0);  //y轴上位置10
camera.lookAt(mesh.position);//指向mesh对应的位置

img

透视投影相机的四个参数fov, aspect, near, far构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上:

// 30:视场角度(fov)
// width / height:Canvas画布宽高比(aspect)
// 1:近裁截面(near)
// 3000:远裁截面(far)
camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

视锥体

第一个3D案例—渲染器

创建渲染器对象:

const renderer = new THREE.WebGLRenderer();

定义threejs输出画布的尺寸(单位:像素px):

const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸

执行渲染操作:

renderer.render(scene, camera);

Canvas画布插入到任意HTML元素中:

<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>
document.getElementById('webgl').appendChild(renderer.domElement);

三维坐标系-加强三维空间认识

辅助观察的坐标系AxesHelper:

const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);

设置材质半透明,这样可以看到坐标系的坐标原点:

const material = new THREE.MeshBasicMaterial({
    color: 0x0000ff, //设置材质颜色
    transparent:true,//开启透明
    opacity:0.5,//设置透明度
});

光源对物体表面影响

MeshBasicMaterial不受光照影响:

const material = new THREE.MeshBasicMaterial(); 

MeshLambertMaterial受光照影响:

const material = new THREE.MeshLambertMaterial(); 

光源对物体表面影响关系如下:

常见光源分类如下:

点光源:两个参数分别表示光源颜色和光照强度:

// 参数1:0xffffff是纯白光,表示光源颜色
// 参数2:1.0,表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);

光源衰减属性decay默认值是2.0,如果不希望衰减可以设置为0.0:

pointLight.decay = 0.0;//设置光源不随距离衰减

设置点光源位置:

pointLight.position.set(400, 0, 0);//点光源放在x轴上

点光源添加到场景中:

scene.add(pointLight); 

相机控件OrbitControls

引入轨道控制器扩展库OrbitControls.js:

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

设置相机控件轨道控制器OrbitControls:

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

平行光与环境光

点光源辅助观察:

const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
scene.add(pointLightHelper);

环境光:没有特定方向,整体改变场景的光照明暗:

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);

可视化平行光DirectionalLightHelper:

const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000);
scene.add(dirLightHelper);

动作渲染循环

requestAnimationFrame实现周期性循环执行,用其实现threejs旋转动画:

const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

function render() {
    renderer.render(scene, camera); //执行渲染操作
    mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
    requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();

Canvas画布布局和全屏

全屏渲染canvas:

// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
const height = window.innerHeight; //窗口文档显示区的高度作为画布高度
const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);

onresize 事件会在窗口被调整大小时发生,实现宽高度动态变化:

window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
    renderer.setSize(window.innerWidth, window.innerHeight);
    // 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
    camera.aspect = window.innerWidth / window.innerHeight;
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
    // 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
    camera.updateProjectionMatrix();
};

stats查看threejs渲染帧率

引入性能监视器stats.js:

import Stats from 'three/addons/libs/stats.module.js';

创建stats对象:

const stats = new Stats();
//stats.domElement:web页面上输出计算结果,一个div元素,
document.body.appendChild(stats.domElement);
function render() {
//requestAnimationFrame循环调用的函数中调用方法update(),来刷新时间
stats.update();
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}
render();

通过setMode()方法的参数mode的数值设置首次打开页面,测试结果的显示模式:

//stats.domElement显示:渲染帧率 刷新频率,一秒渲染次数 
stats.setMode(0);//默认模式
//stats.domElement显示:渲染周期 渲染一帧多长时间(单位:毫秒ms)
stats.setMode(1);

阵列立方体和相机适配体验

相机控件OrbitControls会影响lookAt设置,注意手动设置OrbitControls的目标参数:

const controls = new OrbitControls(camera, renderer.domElement);
// 相机控件.target属性在OrbitControls.js内部表示相机目标观察点,默认0,0,0
// console.log('controls.target', controls.target);
controls.target.set(1000, 0, 1000);
controls.update();//update()函数内会执行camera.lookAt(controls.target)

Threejs常见几何体简介

常见几何体对象:

//BoxGeometry:长方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圆柱
const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);

Three.js的材质默认正面可见,反面不可见,对于矩形平面、圆形平面如果你想看到两面,可以设置side:

new THREE.MeshBasicMaterial({
side: THREE.FrontSide, //默认只有正面可见
});
new THREE.MeshBasicMaterial({
 side: THREE.DoubleSide, //两面可见
});

高光网格材质Phong

MeshPhongMaterial 可以提供一个镜面反射效果,可以类比你生活中拿一面镜子,放在太阳光下,调整角度,可以把太阳光反射到其它地方,如果反射光对着眼睛,也就是反射光线和视线平行的时候,会非常刺眼。

MeshLambertMaterial 对应的Mesh受到光线照射,没有镜面反射的效果,只是一个漫反射,也就是光线向四周反射。

// 模拟镜面反射,产生一个高光效果
const material = new THREE.MeshPhongMaterial({
color: 0xff0000,
shininess: 20, //高光部分的亮度,默认30
specular: 0x444444, //高光部分的颜色
});

WebGL渲染器设置(锯齿模糊)

设置锯齿属性:

renderer.antialias = true; 

获取你屏幕对应的设备像素比devicePixelRatio,告诉threejs,以免渲染模糊问题:

renderer.setPixelRatio(window.devicePixelRatio);

设置背景颜色:

renderer.setClearColor(0x444444, 1); 

gui.js库(可视化改变三维场景)

引入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的add()方法可以快速创建一个UI交互界面:

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

gui调试界面2-颜色命名等

通过name()方法改变gui生成交互界面显示的内容:

gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度');
gui.add(directionalLight, 'intensity', 0, 2.0).name('平行光强度');

通过step()方法设置步长:

gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度').step(0.1);

当gui界面某个值的时候,onChange()方法就会执行,可以根据需要通过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);
});

gui调试3-下拉菜单、单选框

参数3和参数4,分别是一个数字,交互界面是一个鼠标可以拖动的拖动条,可以在一个区间改变属性的值:

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

参数3是一个数组,生成交互界面是下拉菜单:

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

参数3是一个对象,生成交互界面是下拉菜单:

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

参数3是布尔值,生成交互界面是单选框

const obj3 = {
bool: false,
};
// 改变的obj属性数据类型是布尔值,交互界面是单选框
gui.add(obj3, 'bool').name('是否旋转').onChange(function (value) {
// 点击单选框,控制台打印obj.bool变化
console.log('obj.bool',value);
});

gui.js库(分组)

new GUI() 实例化一个gui对象,默认创建一个总的菜单,通过gui对象的addFolder()方法可以创建一个子菜单,当你通过GUI控制的属性比较多的时候,可以使用addFolder()进行分组。addFolder()返回的子文件夹对象,同样具有gui对象的add()、onChange()、addColor()等等属性。

// 创建材质子菜单
const matFolder = gui.addFolder('材质');
matFolder.close();
// 材质颜色color
matFolder.addColor(obj, 'color').onChange(function(value){
    material.color.set(value);
});

gui对象创建的总菜单或gui.addFolder()创建的子菜单都可以用代码控制交互界面关闭或开展状态:

gui.open(); // 展开菜单
gui.close(); // 关闭菜单

原文地址:https://blog.csdn.net/m0_62484615/article/details/140635114

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!