持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
写在前面
本文用vue和threejs写物体的缩放效果。
下面是gif展示:
完整代码说明
- html写一个id容器,用于展示threejs,并且引入需要的threejs 模块
<div class="item">
<div id="THREE31"></div>
</div>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 轨道控制器
import { ThreeMFLoader } from "three/examples/jsm/loaders/3MFLoader.js"; // .3mf模型加载器
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js"; // GUI面板
- 创建场景
创建场景并设置背景。
initScene() {
this.scene = new THREE.Scene(); // 创建场景
this.scene.background = new THREE.Color(0x8cc7de); // 设置背景颜色
this.scene.fog = new THREE.Fog(0xa0a0a0, 10, 500); // 雾化效果
},
- 创建相机
创建一个透视相机(相机垂直角度,长宽比,近端面,远端面),并设置相机的位置。
initCamera() {
this.camera = new THREE.PerspectiveCamera(
35,
(window.innerWidth - 201) / window.innerHeight,
1,
500
); // 创建透视相机
this.camera.position.set(-100, 80, 100); // 设置相机位置
this.scene.add(this.camera); // 将相机添加到场景中
},
- 创建灯光
创建一个半球光HemisphereLight,天空颜色为白色0xffffff,地面颜色为0x444444。
创建一个平行光DirectionalLight,允许该平行光产生阴影。
initLights() {
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); // 创建半球光
hemiLight.position.set(0, 100, 0); // 设置半球光位置
this.scene.add(hemiLight); // 将半球光添加到场景中
const dirLight = new THREE.DirectionalLight(0xffffff); // 创建平行光
dirLight.position.set(-0, 40, 50); // 设置平行光位置
dirLight.castShadow = true; // 允许产生阴影
dirLight.shadow.camera.top = 50;
dirLight.shadow.camera.bottom = -25;
dirLight.shadow.camera.left = -25;
dirLight.shadow.camera.right = 25;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 200;
dirLight.shadow.mapSize.set(1024, 1024);
this.scene.add(dirLight); // 将平行光添加到场景中
},
- 创建渲染器
创建渲染器WebGLRenderer,并设置设备像素比,并调整画布大小,并且允许渲染阴影。
initRenderer() {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比
this.renderer.setSize(window.innerWidth - 201, window.innerHeight); // 考虑设备像素比调整画布大小
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.renderer.shadowMap.enabled = true; // 允许渲染阴影
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.getElementById("THREE31").appendChild(this.renderer.domElement);
},
- 加载模型
加载.3mf模型,并且设置模型允许产生阴影child.castShadow = true;。
在加载完模型后,生成GUI面板,并且开始渲染。
initTruckModel() {
const loader = new ThreeMFLoader();
// 加载模型
loader.load("models/models/3mf/truck.3mf", (object) => {
object.quaternion.setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0)); // z-up conversion
object.traverse((child) => {
child.castShadow = true;
});
this.truckModel = object;
this.scene.add(object); // 将模型添加到场景中
this.createPanel(); // 生成GUI面板
this.animate(); // 渲染
});
},
- 创建地面
创建一个平面PlaneGeometry,给它加上颜色材质MeshPhongMaterial,形成一个平面网格模型Mesh,将平面旋转90度即变成一个地面,并且设置允许地面接收阴影ground.receiveShadow = true;。
initGround() {
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(1000, 1000),
new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false })
); // 创建一个平面
ground.rotation.x = -Math.PI / 2; // 将平面旋转90度变成地面
ground.position.y = 11;
ground.receiveShadow = true; // 允许地面接收阴影
this.scene.add(ground); // 将地面添加到场景中
},
- 创建轨道控制器
使用引入的OrbitControls创建轨道控制器,能使用鼠标进行画面的操作,但对画面的切换范围做了一些限制controls.minDistance controls.maxDistance controls.minPolarAngle controls.maxPolarAngle controls.enablePan,在代码中都进行了解释。
initControls() {
// 创建轨道控制器
const controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.addEventListener("change", this.render);
controls.minDistance = 50; // 相机能向内移动的距离
controls.maxDistance = 200; // 相机能向外移动的距离
controls.minPolarAngle = 0; // 相机能向下垂直旋转的角度
controls.maxPolarAngle = Math.PI / 2; // 相机能向上垂直旋转的角度
controls.enablePan = false; // 禁止摄像机平移
controls.target.set(0, 20, 0); // 控制器的焦点
controls.update();
},
- 生成GUI面板
创建一个GUI面板,添加一个折叠面板,折叠面板的标题为物体效果
,该折叠面板下有一个子项,为缩放,初始值为1,能控制的范围为(0.5, 2.0),缩放值变化的步长为0.1,绑定了一个change事件,触发后对模型进行缩放操作this.truckModel.scale.set(val, val, val);,默认该折叠面板是打开的folder1.open();。
createPanel() {
const panel = new GUI({ width: 310 }); // 创建一个长310的面板
const folder1 = panel.addFolder("物体效果");
let settings = {
缩放: 1,
};
folder1.add(settings, "缩放", 0.5, 2.0, 0.1).onChange((val) => {
this.truckModel.scale.set(val, val, val);
});
folder1.open();
},
- 渲染
一个帧动画requestAnimationFrame(this.animate)+渲染器渲染this.renderer.render(this.scene, this.camera)。
animate() {
requestAnimationFrame(this.animate);
this.render();
},
render() {
this.renderer.render(this.scene, this.camera);
},
- mounted方法
在mounted方法中一次调用。
mounted() {
this.initScene(); // 创建场景
this.initCamera(); // 创建相机
this.initLights(); // 创建灯光
this.initRenderer(); // 创建渲染器
this.initTruckModel(); // 加载模型
this.initGround(); // 创建地面
this.initControls(); // 创建轨道控制器
},
写在最后
以上就是全部代码和说明。