// 传入几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material)
// 设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0, 0, 0)
scene.add(mesh)
本质上是模拟人眼观察这个世界的规律,透视投影相机的四个参数 fov, aspect, near, far 构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。
宽高比 aspect = width / height
参数 | 含义 | 默认值 |
---|---|---|
fov | 相机视椎体竖直方向视野角度 | 50 |
aspect | 相机视椎体水平方向和竖直方向长度比,一般设置为 Canvas 画布宽高比 width/height | 1 |
near | 相机视椎体近裁界面相对相机距离 | 0.1 |
far | 相机视椎体远裁面相对相机距离,far-near构成了视椎体高度方向 | 2000 |
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera()
camera.position.set(200, 200, 200)
camera.lookAt(0, 0, 0)
camera.lookAt(mesh.position)
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer()
// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
渲染器 WebGLRenderer 通过属性 .domElement 可以获得渲染方法 .render() 生成的 Canvas 画布,.domElement 本质上就是一个 HTML 元素: Canvas 画布。
document.body.appendChild(renderer.domElement);
渲染器 WebGLRenderer 执行渲染方法 .render() 就可以生成一个 Canvas画布(照片),并把三维场景 Scene 呈现在 canvas 画布上面,你可以把 .render() 理解为相机的拍照动作“咔”。
renderer.render(scene, camera); //执行渲染操作
// 使用 requestAnimationFrame 渲染
const render = () => {
requestAnimationFrame(render);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
THREE.AxesHelper() 的参数表示坐标系坐标轴线段尺寸大小,你可以根据需要改变尺寸。
const axesHelper = new THREE.AxesHelper(150)
scene.add(axesHelper)
three.js 坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴,对于 three.js 的3D坐标系默认y轴朝上。
基础材质不受光照影响,漫反射材质、高光材质、物理材质 受光照影响
//点光源:两个参数分别表示光源颜色和光照强度
// 参数1:0xffffff是纯白光,表示光源颜色
// 参数2:1.0,表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);
//点光源位置
pointLight.position.set(50, 0, 0); //点光源放在x轴上
scene.add(directionalLight); //点光源添加到场景中
通过点光源辅助观察对象 PointLightHelper 可视化光源
// 光源辅助观察
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10)
scene.add(pointLightHelper)
开发时可以通过相机控件 OrbitControls 实现旋转缩放预览效果。需要另外引入轨道控制器扩展库OrbitControls.js。
// 引入轨道控制器扩展库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); //执行渲染操作, 在render 里渲染了这里就不用重复了
// 浏览器控制台查看相机位置变化
console.log('camera.position',camera.position);
});//监听鼠标、键盘事件
OrbitControls 本质上就是改变相机的参数,比如相机的位置属性,改变相机位置也可以改变相机拍照场景中模型的角度,实现模型的360度旋转预览效果,改变透视投影相机距离模型的距离,就可以改变相机能看到的视野范围
使用 window.innerWidth 、window.innerHeight 设置画布宽高。记得设置 css
body {
overflow: hidden;
margin: 0px;
}
canvas 画布宽高动态变化,需要更新相机和渲染参数,否则无法正常渲染
// 窗口大小变化
window.resize = function() {
// 重置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 全屏下,设置观察范围长宽比 aspect 为窗口宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行 renderer 方法的时候会读取相机对象的投影矩阵属性 projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵,节约计算资源
// 如果相机的一些属性发生了变化,需要执行 updateProjectionMatrix() 方法更新相机的投影矩阵
camera.updateProjectionMatrix();
}
threejs 每执行 WebGL 渲染器的 .render() 方法一次,就在画布上得到一帧图像,所以场景越复杂则渲染性能越低,也就每秒钟执行 .render() 的次数越低。
通过 stats.js 库可以查看 threejs 当前的渲染性能,即渲染帧率(FPS),一般渲染达到每秒 60 次为最佳状态。
// 引入 stats.js
import Stats from 'three/addons/libs/stats.module.js';
// 创建 stats 对象
const stats = new Stats()
document.body.appendChild(stats.domElement)
// 渲染函数
// 使用 requestAnimationFrame 渲染
const render = () => {
// 调用 stats.update
stats.update();
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
// light.rotation.x += 0.1;
// light.rotation.y += 0.1;
// 渲染
renderer.render(scene, camera);
window.requestAnimationFrame(render);
}
render();
// stats.domElement显示:渲染帧率 刷新频率 和 一秒渲染次数
stats.setMode(0);//默认模式
//stats.domElement显示:渲染周期 渲染一帧多长时间(单位:毫秒ms)
stats.setMode(1);
控制长方体模型数量,增加或减少看看帧率变化,这也与电脑性能有关
const getRandomColor = () => {
let hex = Math.floor(Math.random() * 16777216).toString(16);
while(hex.length < 6) {
hex = '0' + hex;
}
return '#' + hex;
}
// 随机创建大量的模型,测试渲染性能,调整 num 值查看页面帧率变化
const num = 10; //控制长方体模型数量
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
for (let k = 0; k < num; k++) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({
color: getRandomColor(),
transparent: true,
opacity: 0.8,
});
const mesh = new THREE.Mesh(geometry, material);
// 随机生成长方体xyz坐标
const x = i * 2
const y = k * 2
const z = j * 2
mesh.position.set(x, y, z)
scene.add(mesh); // 模型对象插入场景中
}
}
}
threejs 的材质默认正面可见,反面不可见,对于矩形平面 PlaneGeometry、圆形平面 如果想看到两面,可以设置 side: THREE.DoubleSide
//默认只有正面可见
new THREE.MeshBasicMaterial({
side: THREE.FrontSide,
});
// 设置 两面可见
new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
});
// 球体 几何体
const sphereGeometry = new THREE.SphereGeometry(2);
// 高光网格材质
// 模拟镜面反射,产生一个高光效果
const phongMaterial = new THREE.MeshPhongMaterial({
color: 0xF80888,
shininess: 40, //高光部分的亮度,默认30
specular: 0xFFFFFF, //高光部分的颜色
});
// 网格模型
const mesh2 = new THREE.Mesh(sphereGeometry, phongMaterial);
// 网格模型位置,默认原点
mesh2.position.set(10, 20, 10);
scene.add(mesh2);
// 开启锯齿模糊,几何体过渡更加平滑自然
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
// 或者
renderer.antialias = true;
如果你遇到你的 canvas 画布输出模糊问题,注意设置 renderer.setPixelRatio(window.devicePixelRatio)
注意:注意你的硬件设备设备像素比window.devicePixelRatio刚好是1,那么是否执行.setPixelRatio()不会有明显差异,不过为了适应不同的硬件设备屏幕,通常需要执行该方法。
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x444444, 1); //设置背景颜色
dat.gui.js 是一个前端js库,对HTML、CSS和JavaScript进行了封装,借助dat.gui.js可以快速创建控制三维场景的UI交互界面,场景中的参数往往需要以可视化的方式调试出来。
gui 实例主要包含以下方法:
// 引入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改变对象属性,其余参数为数值
gui.add(pointLight, 'intensity', 0, 2.0).name('环境光强度');
gui.add(mesh.position, 'y', 0, 30).step(2).name('y轴');
// .add 的其余参数为对象 、 数组,gui界面为下拉选择
gui.add(material, 'transparent', { 开: true, 关: false}).name('开启透明');
gui.add(material, 'opacity', [0.2, 0.4, 0.6, 0.8, 1]).name('透明度');
// .add 的其余参数为 布尔值
const isMove = { bool: true };
gui.add(isMove, 'bool').name('矩形动画');
// 球体颜色
gui.addColor(phongMaterial, 'color').name('球体颜色').onChange(function(color) {
// renderer.setClearColor(color, 1);
});
gui 页面分组可 嵌套
// 创建子菜单
const boxFolder = gui.addFolder('矩形');
// 折叠,对应的 .open() , 默认是 open
boxFolder.close();
boxFolder.add(mesh.position, 'y', 0, 30).step(2).name('y轴');
const isMove = { bool: true };
boxFolder.add(isMove, 'bool').name('矩形动画');
// 嵌套子菜单
const transparentFolder = boxFolder.addFolder('透明');
transparentFolder.add(material, 'transparent', { 开: true, 关: false}).name('开启透明');
transparentFolder.add(material, 'opacity', [0.2, 0.4, 0.6, 0.8, 1]).name('透明度');
// 创建子菜单
const sphereFolder = gui.addFolder('球体');
// 球体颜色
sphereFolder.addColor(phongMaterial, 'color').name('球体颜色').onChange(function(color) {
// renderer.setClearColor(color, 1);
});
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。