学习: Threejs (1)

Three.js中文网:http://www.webgl3d.cn/

一、简介

开启 Web 3D 之门:WebGL与Three.js简介 | Threejs指南

二、three.js下载

Three.js -- JavaScript 3D Library

mrdoob/three.js: JavaScript 3D Library.

three.js: JavaScript 3D Library. - Gitee.com

文档

案例

三、开发和学习环境,引入threejs库

除了three.js核心库以外,在threejs文件包中examples/jsm目录下,扩展库很多

复制代码
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

1.script标签引入

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js中文网:http://www.webgl3d.cn/</title>
    <!-- 引入three.js -->
    <script src="./build/three.js"></script>
</head>

<body>
    <script>
        // 浏览器控制台测试,是否引入成功
        console.log(THREE.Scene);
    </script>
</body>

</html>

2.import方式

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>

<body>
    <script type="module">
        // ES6写法import引入
        import * as THREE from './build/three.module.js';
        // 浏览器控制台测试,是否引入成功
        console.log(THREE.Scene);
    </script>
</body>

</html>

3.模拟npm安装的写法

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>

<body>
    <!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
    <script type="importmap">
        {
			"imports": {
				"three": "../../../three.js/build/three.module.js"
			}
		}
	</script>
    <script type="module">
        // 引入three.js库:借助<script type="importmap">,和nodejs开发环境中写法一样
        import * as THREE from 'three';
        // 浏览器控制台测试,是否引入成功
        console.log(THREE.Scene);
    </script>
</body>

</html>

4.扩展库---模拟npm安装的写法

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>

<body>
    <!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
    <script type="importmap">
        {
			"imports": {
				"three": "../../../three.js/build/three.module.js",
                "three/addons/": "../../../three.js/examples/jsm/"
			}
		}
	</script>
    <script type="module">
        // 引入three.js库:借助<script type="importmap">,和nodejs开发环境中写法一样
        import * as THREE from 'three';
        // 浏览器控制台测试,是否引入成功
        console.log(THREE.Scene);

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

        console.log(OrbitControls);
        console.log(GLTFLoader);
    </script>
</body>

</html>

四、第一个3D案例

创建3D场景

复制代码
// 引入three.js
import * as THREE from "three";
/**
 * 创建3D场景对象Scene
 */
const scene = new THREE.Scene();
/**
 * 创建网格模型
 */
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material
const material = new THREE.MeshBasicMaterial({
  color: 0x0000ff, //设置材质颜色
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0, 10, 0);
//网格模型添加到场景中
scene.add(mesh); 

console.log('三维场景',scene);

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Threejs中文网:www.webgl3d.cn</title>
</head>

<body>
    <!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
    <script type="importmap">
        {
			"imports": {
				"three": "../../../three.js/build/three.module.js"
			}
		}
	</script>
    <script src="./index.js" type="module">  
    </script>
</body>

</html>

透视投影相机

如果想把三维场景Scene渲染到web网页上,还需要定义一个虚拟相机

复制代码
// 创建一个透视投影相机对象
// width和height用来设置渲染后,输出的画布宽高度。
const width = 800; //宽度
const height = 500; //高度
/**
 * 透视投影相机设置,相机对象Camera具有位置属性.position,通过位置属性.position可以设置相机的位置。
 */
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置

// camera.lookAt(0, 1, 0); //y轴上一点
// camera.lookAt(mesh.position);//指向网络模型mesh
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点

渲染器

复制代码
/**
 * 创建渲染器对象
 */
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.render(scene, camera); //执行渲染操作
//three.js执行渲染命令会输出一个canvas画布,也就是一个HTML元素,你可以插入到web页面中
document.body.appendChild(renderer.domElement);
复制代码
<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>

// 将渲染器的DOM元素添加到页面中id为'webgl'的元素内
document.getElementById('webgl').appendChild(renderer.domElement);

五、Threejs三维坐标系

javascript 复制代码
/**
 * 创建网格模型
 */
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material
const material = new THREE.MeshBasicMaterial({
  color: 0xffffff, //设置材质颜色
  transparent: true, //开启透明
  opacity: 0.5, //设置透明度
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
// mesh.position.set(0,10,0);
scene.add(mesh); //网格模型添加到场景中

// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);

六、光源对物体表面影响

七、相机控件轨道控制器OrbitControls

index.html

html 复制代码
 <script type="importmap">
        {
			"imports": {
				"three": "../../../three.js/build/three.module.js",
                "three/addons/": "../../../three.js/examples/jsm/"
			}
		}
</script>
javascript 复制代码
// 引入轨道控制器扩展库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); //执行渲染操作
  // 浏览器控制台查看相机位置变化
  console.log("camera.position", camera.position);
}); //监听鼠标、键盘事件

控制台

八、平行光与环境光

可视化点光源

javascript 复制代码
/**
 * 光源设置
 */
// //点光源
const pointLight = new THREE.PointLight(0xffffff, 1.0);
// //点光源位置
pointLight.position.set(400, 200, 300);
pointLight.decay = 0.0; //不随着距离的改变而衰减,默认衰减2.0
scene.add(pointLight); //点光源添加到场景中
 //可视化点光源
const pointLightHelper = new THREE.PointLightHelper(pointLight, 5, 0xff0000);
scene.add(pointLightHelper);

环境光

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

平行光

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

// DirectionalLightHelper:可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5,0xff0000);
scene.add(dirLightHelper);

九、动画渲染循环

请求动画帧

javascript 复制代码
<script>
        // requestAnimationFrame实现周期性循环执行
        // requestAnimationFrame默认每秒钟执行60次,但不一定能做到,要看代码的性能
        let i = 0;
        function render() {
            i+=1;
            console.log('执行次数'+i);
            requestAnimationFrame(render);//请求再次执行函数render
        }
        render();
    </script>

渲染循环

javascript 复制代码
/**
 * 创建渲染器对象
 */
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
// renderer.render(scene, camera); //执行渲染操作
//three.js执行渲染命令会输出一个canvas画布,也就是一个HTML元素,你可以插入到web页面中
document.body.appendChild(renderer.domElement);


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

计算两帧时间间隔

javascript 复制代码
// 渲染循环
const clock = new THREE.Clock();
function render() {
    const spt = clock.getDelta()*1000;//毫秒
    console.log('两帧渲染时间间隔(毫秒)',spt);
    console.log('帧率FPS',1000/spt);
    renderer.render(scene, camera); //执行渲染操作
    mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
    requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();

渲染循环+OrbitControls相机控件

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

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

十、Canvas画布布局和全屏

插入到body元素中

插入到任意div元素中

全屏

javascript 复制代码
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
// const width = 800; //宽度
// const height = 500; //高度
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
const height = window.innerHeight; //窗口文档显示区的高度作为画布高度
javascript 复制代码
    <style>
        body{
            overflow: hidden;/* 隐藏滚动条 */
            margin: 0px;
        }
    </style>

canvas画布宽高度动态变化

javascript 复制代码
// 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渲染帧率

javascript 复制代码
//引入性能监视器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);

创建大量物体,测试性能

javascript 复制代码
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
//引入性能监视器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);

// 三维场景
const scene = new THREE.Scene();

// 随机创建大量的模型,测试渲染性能
const num = 1000; //控制长方体模型数量,你可以一直增加或减少看看帧率变化,电脑性能不同结果不同
for (let i = 0; i < num; i++) {
  const geometry = new THREE.BoxGeometry(5, 5, 5);
  const material = new THREE.MeshLambertMaterial({
    color: 0xffffff,
  });
  const mesh = new THREE.Mesh(geometry, material);
  // 随机生成长方体xyz坐标
  const x = (Math.random() - 0.5) * 200;
  const y = (Math.random() - 0.5) * 200;
  const z = (Math.random() - 0.5) * 200;
  mesh.position.set(x, y, z);
  scene.add(mesh); // 模型对象插入场景中
}

//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);

//光源设置
const pointLight = new THREE.PointLight(0xffffff, 1.0);
pointLight.decay = 0;
pointLight.position.set(400, 200, 300);
scene.add(pointLight);
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);

//渲染器和相机
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);

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

// 渲染循环
function render() {
  stats.update(); //渲染循环中执行stats.update()来刷新时间
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render();

const controls = new OrbitControls(camera, renderer.domElement);

// 画布跟随窗口变化
window.onresize = function () {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
};
javascript 复制代码
//创建stats对象
const stats = new Stats();
 //stats.setMode(0); //默认模式
stats.setMode(1);
//Stats.domElement:web页面上输出计算结果,一个div元素
document.body.appendChild(stats.domElement);
复制代码
(0: fps, 1: ms, 2: mb)

十二、阵列立方体和相机适配体验

立方体阵列一排

javascript 复制代码
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
    color: 0xffffff, 
    transparent: true, 
    opacity: 0.5, 
});
// 沿着x轴等间距创建一系列网格模型
for (let i = 0; i < 10; i++) {
    // 所有模型对象共享同一个几何体或材质
    const mesh = new THREE.Mesh(geometry, material); 
    // 沿着x轴分布
    mesh.position.set(i * 200, 0, 0);
    scene.add(mesh); //网格模型添加到场景中
}

立方体行列阵列

javascript 复制代码
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
    color: 0xffffff, 
    transparent: true, 
    opacity: 0.5, 
});
for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
        // 在XOZ平面上分布
        mesh.position.set(i * 200, 0, j * 200);
        scene.add(mesh); //网格模型添加到场景中
    }

}

调整相机参数

立方体阵列为基础

javascript 复制代码
/**
 * 透视投影相机设置
 */
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 8000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
// 1. 相机位置拉远,可以看到更大的观察范围
//camera.position.set(800, 800, 800);
// 2. 超出视锥体远裁界面的范围的会被剪裁掉,不渲染  可以调整far参数适配
//camera.position.set(2000, 2000, 2000);
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
// 3. 改变相机观察目标点
// camera.lookAt(1000, 0, 1000);
// 4. 一个物体:体验透视投影相机远小近大的投影规律
// 5. 视野角度fov越大,观察范围越大

相机控件影响lookAt值,camera.lookAt(0, 0, 0); camera.lookAt(1000, 0, 1000);

javascript 复制代码
/**
 * 透视投影相机设置
 */
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 8000);
// camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
// 1. 相机位置拉远,可以看到更大的观察范围
// camera.position.set(800, 800, 800);
// 2. 超出视锥体远裁界面的范围的会被剪裁掉,不渲染  可以调整far参数适配
camera.position.set(2000, 2000, 2000);
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
// 3. 改变相机观察目标点
// camera.lookAt(1000, 0, 1000);
// 4. 一个物体:体验透视投影相机远小近大的投影规律
// 5. 视野角度fov越大,观察范围越大

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

// 渲染循环
function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render();

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

十三、Threejs常见简单几何体简介

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

十四、高光网格材质MeshPhongMaterial

javascript 复制代码
// 创建网格模型

//BoxGeometry:长方体
// const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);

// MeshBasicMaterial不受光照影响
// const material = new THREE.MeshBasicMaterial({
//     color: 0xff0000, 
// });

// 漫反射,没有镜面反射效果,不会产生局部高光效果
// const material = new THREE.MeshLambertMaterial({
//     color: 0xff0000, 
// });

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

漫反射,没有镜面反射效果,不会产生局部高光效果(左

十五、WebGL渲染器设置(锯齿模糊、背景颜色)

渲染器锯齿属性.antialias

javascript 复制代码
// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
  antialias: true, //开启优化锯齿
});

设备像素比window.devicePixelRatio

javascript 复制代码
// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log("查看当前屏幕设备像素比", window.devicePixelRatio);

2560*1440

1920*1080

设置设备像素比.setPixelRatio()

javascript 复制代码
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);

设置背景颜色.setClearColor()

javascript 复制代码
renderer.setClearColor(0x0a3e1e, 0.8); //设置背景颜色

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

gui基本语法

javascript 复制代码
// 从threejs扩展库引入gui.js
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';


//创建一个GUI对象,你可以看到浏览器右上角多了一个交互界面,GUI本质上就是一个前端js库。
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';


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

// 可以不停地打印obj的值,这样通过gui界面拖动改变obj对象属性的的时候,便于观察obj的变化
setInterval(function () {
    console.log('x', obj.x);
    // console.log('y',obj.y);
    // console.log('z',obj.z);
}, 10)

style属性

对象属性

改变obj对应属性

gui改变光照参数

javascript 复制代码
// 光照强度属性.intensity
console.log("ambient.intensity", ambient.intensity);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(ambient, "intensity", 0, 2.0);

gui改变threejs模型位置

javascript 复制代码
// 浏览器控制可以知道mesh.position是一个具有x、y、z属性的对象
// mesh.position是一个具有x、y、z属性表示模型的xyz坐标
console.log('mesh.position',mesh.position);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(mesh.position, 'x', 0, 180);
gui.add(mesh.position, 'y', 0, 180);
gui.add(mesh.position, 'z', 0, 180);

十七、gui.js库(颜色、命名、步长、事件)

颜色

javascript 复制代码
// .addColor()生成颜色值改变的交互界面
gui.addColor(obj, 'color').onChange(function(value){
    // console.log('obj.color',obj.color);
    mesh.material.color.set(value);
});

命名

javascript 复制代码
// 光照强度属性.intensity
console.log('ambient.intensity',ambient.intensity);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度');
gui.add(directionalLight, 'intensity', 0, 2.0).name('平行光强度');

步长

javascript 复制代码
gui.add(ambient, "intensity", 0, 2.0).name("环境光强度").step(0.1);

事件

javascript 复制代码
// 当obj的x属性变化的时候,就把此时obj.x的值value赋值给mesh的x坐标
gui.add(obj, "x", 0, 180).onChange(function (value) {
  // console.log('obj.x',obj.x);
  mesh.position.x = value;
});

对比


// 通过GUI改变mesh.position对象的xyz属性
gui.add(mesh.position, 'x', 0, 180);

十八、gui.js库(下拉菜单、单选框)

javascript 复制代码
// 1. 参数3、参数4数据类型:数字(拖动条)
gui.add(obj, 'x', 0, 180).onChange(function (value) {
    mesh.position.x = value;
});
// 2. 参数3数据类型:数组(下拉菜单)
gui.add(obj, 'scale', [-100, 0, 100]).name('y坐标').onChange(function (value) {
    mesh.position.y = value;
});
// 3. 参数3数据类型:对象(下拉菜单)
gui.add(obj, 'scale', {
    left: -100,
    center: 0,
    right: 100
    // 左: -100,//可以用中文
    // 中: 0,
    // 右: 100
}).name('位置选择').onChange(function (value) {
    mesh.position.x = value;
});
// 3. 参数3数据类型:布尔值(单选框)
gui.add(obj, 'bool').name('是否旋转');
javascript 复制代码
// 渲染循环
function render() {
  // 当gui界面设置obj.bool为true,mesh执行旋转动画
  if (obj.bool) mesh.rotateY(0.01);
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

十九、gui.js库(分组)

javascript 复制代码
const gui = new GUI(); //创建GUI对象 
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
    color: 0x00ffff,// 材质颜色
    specular: 0x111111,// 材质高光颜色
};


// 材质颜色color
gui.addColor(obj, 'color').onChange(function(value){
    material.color.set(value);
});
// 材质高光颜色specular
gui.addColor(obj, 'specular').onChange(function(value){
    material.specular.set(value);
});

// 环境光强度
gui.add(ambient, 'intensity',0,2);
// 平行光强度
gui.add(directionalLight, 'intensity',0,2);
// 平行光位置
gui.add(directionalLight.position, 'x',-400,400);
gui.add(directionalLight.position, 'y',-400,400);
gui.add(directionalLight.position, 'z',-400,400);

.addFolder()分组

材质子菜单

环境光子菜单

javascript 复制代码
// 环境光子菜单
const ambientFolder = gui.addFolder("环境光");
// 环境光强度
ambientFolder.add(ambient, "intensity", 0, 2).name("环境强度");

平行光子菜单

javascript 复制代码
// 平行光子菜单
const dirFolder = gui.addFolder("平行光");
// 平行光强度
dirFolder.add(directionalLight, "intensity", 0, 2).name("平行光强度");
// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);

javascript 复制代码
const gui = new GUI(); //创建GUI对象
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
  color: 0xafafaf, // 材质颜色
  specular: 0xffffff, // 材质高光颜色
};
// 创建材质子菜单
const matFolder = gui.addFolder("材质");
// 材质颜色color
matFolder
  .addColor(obj, "color")
  .name("材质颜色")
  .onChange(function (value) {
    material.color.set(value);
  });
// 材质高光颜色specular
matFolder
  .addColor(obj, "specular")
  .name("高光颜色")
  .onChange(function (value) {
    material.specular.set(value);
  });
// 环境光子菜单
const ambientFolder = gui.addFolder("环境光");
// 环境光强度
ambientFolder.add(ambient, "intensity", 0, 2).name("环境颜色");
// 平行光子菜单
const dirFolder = gui.addFolder("平行光");
// 平行光强度
dirFolder.add(directionalLight, "intensity", 0, 2).name("平行光强度");
// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);

二十、threejs语法总结

23. threejs语法总结 | Three.js中文网

javascript 复制代码
// 引入three.js
import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

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

// 创建网格模型
const geometry = new THREE.PlaneGeometry(100, 50);

// // new实例化类THREE.MeshLambertMaterial,创建一个材质对象
// const material = new THREE.MeshLambertMaterial();
// // 可以看到材质对象的属性color、side、opacity、transparent...
// // 通过属性可以看到threejs默认的属性值
// console.log('查看材质对象',material);
// // 查看材质默认属性值
// console.log('material.color',material.color);
// console.log('material.side',material.side);
// console.log('material.transparent',material.transparent);
// console.log('material.opacity',material.opacity);

const material = new THREE.MeshLambertMaterial({
  // 通过选项参数设置材质属性
  color: 0xffffff,
  side: THREE.DoubleSide,
  transparent: true,
  opacity: 0.5,
});
// 访问对象属性改变属性的值
material.transparent = false;
material.opacity = 1.0;

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

console.log("模型位置属性", mesh.position);
mesh.position.x = 50; //访问属性改变位置x坐标
mesh.translateX(50); //执行方法改变位置属性

//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);

//光源设置
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
console.log("directionalLight", ambient.intensity);
directionalLight.intensity = 0.1; //改变光源强度

//相机
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);

// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
  antialias: true, //开启优化锯齿
});
renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);

// 渲染循环
function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render();

// 画布跟随窗口变化
window.onresize = function () {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
};

二十一、【选修】Vue + Threejs 开发环境( 可跳过 )

javascript 复制代码
npm create  vite@latest
javascript 复制代码
# 安装 Three.js 核心库
npm install three

清理工程

src\App.vue

javascript 复制代码
<script setup>

</script>

<template>

</template>

<style scoped>

</style>

src\style.css

javascript 复制代码
body{
  margin: 0;
}

新建index.js

导入

javascript 复制代码
import * as THREE from "three";

// 三维场景
const scene = new THREE.Scene();
// 模型对象
const geometry = new THREE.BoxGeometry(50, 50, 50);
const material = new THREE.MeshBasicMaterial({
  color: 0xffffff,
  transparent: true,
  opacity: 0.8,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(250);
scene.add(axesHelper);
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度

// 相机
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);
// WebGL渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.render(scene, camera);
//three.js执行渲染命令会输出一个canvas画布(HTML元素),你可以插入到web页面中
document.body.appendChild(renderer.domElement);

引入到vue的main.js文件中

javascript 复制代码
// main.js文件
import './index.js'// 执行threejs代码

引入相机控件

javascript 复制代码
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
javascript 复制代码
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
  renderer.render(scene, camera); //执行渲染操作
}); //监听鼠标、键盘事件
相关推荐
副露のmagic14 小时前
更弱智的算法学习 day24
python·学习·算法
Van_Moonlight14 小时前
RN for OpenHarmony 实战 TodoList 项目:加载状态 Loading
javascript·开源·harmonyos
程序猿零零漆14 小时前
Spring之旅 - 记录学习 Spring 框架的过程和经验(十一)基于XML方式、注解的声明式事务控制、Spring整合Web环境
xml·学习·spring
半夏知半秋14 小时前
rust学习-闭包
开发语言·笔记·后端·学习·rust
sheji341615 小时前
【开题答辩全过程】以 基于微信小程序的在线学习系统为例,包含答辩的问题和答案
学习·微信小程序·小程序
IT=>小脑虎15 小时前
Go语言零基础小白学习知识点【基础版详解】
开发语言·后端·学习·golang
qq_4061761415 小时前
关于JavaScript中的filter方法
开发语言·前端·javascript·ajax·原型模式
@@小旭15 小时前
实现头部Sticky 粘性布局,并且点击菜单滑动到相应位置
前端·javascript·css
hkNaruto16 小时前
【AI】AI学习笔记:A2A(智能体协作)入门指南:从概念到实践
人工智能·笔记·学习