本文已参加「新人创作礼」活动,一起开启掘金创作之旅。
写在前面
看了一下thingjs的例子,它的模型闪烁是根据Clock启动时间的变化进行透明度的改变实现功能。
根据它的写法,尝试使用vue+threejs进行模型闪烁功能的实现。
效果演示
使用的模型是threejs官网例子里的一个小车模型
完整代码说明
- 创建一个容器
<template>
<div class="item">
<div id="THREE31"></div>
</div>
</template>
- 引入用到的threejs模块和GUI
OrbitControls是threejs提供的轨道控制器,用了它,整个场景就能随鼠标的操作进行旋转缩放。
ThreeMFLoader是thrrejs提供的一个文件加载器,可以用来加载.3mf文件,因为我选的模型是.3mf的,所以引入该模块,threejs还支持其他很多文件类型的模型的加载器,感兴趣的可以自己去thrrejs的官网看看。
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { ThreeMFLoader } from "three/examples/jsm/loaders/3MFLoader.js";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
- vue的mounted()方法,用来初始化threejs
mounted() {
this.initThreejs();
},
- initThreejs()的代码
initThreejs() {
let camera, scene, renderer;
let model, settings;
let clock;
init();
function init() {
// threejs的代码
}
function createPanel() {
// gui的代码
}
function animate() {
// ...
}
function render() {
renderer.render(scene, camera);
}
},
- init()的代码,包括场景、相机、灯光(半球光和平行光)、渲染器、地面模型、轨道控制器的创建
// 场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0x8cc7de); // 场景的背景颜色
scene.fog = new THREE.Fog(0xa0a0a0, 10, 500);
// 相机,这里创建的是一个透视相机
camera = new THREE.PerspectiveCamera(
35,
(window.innerWidth - 201) / window.innerHeight,
1,
500
);
camera.position.set(-100, 80, 100); // 相机的位置
scene.add(camera);
// 半球光
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); // 天空发出的光的颜色是0xffffff,地面发出的光的颜色是0x444444
hemiLight.position.set(0, 100, 0); // 灯光的位置
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);
scene.add(dirLight);
// 渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth - 201, window.innerHeight);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.shadowMap.enabled = true; // 是否允许阴影贴图
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.getElementById("THREE31").appendChild(renderer.domElement);
// 地面
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(1000, 1000), // 一个长1000,宽1000的正方形
new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false })
);
ground.rotation.x = -Math.PI / 2; // 绕x轴旋转90度
ground.position.y = 11;
ground.receiveShadow = true; // 地面接收阴影
scene.add(ground);
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", 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();
// 加载.3mf模型
const loader = new ThreeMFLoader();
loader.load("models/models/3mf/truck.3mf", function (object) {
object.quaternion.setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0));
object.traverse(function (child) {
child.castShadow = true;
if (child.material) {
child.material.transparent = true; // 每个材质都开启透明度设置,这个不开启改了opacity的值也不会生效
child.material.opacity = 1; // 默认设置透明度为1
}
});
model = object;
scene.add(object);
// 生成gui
createPanel();
// 渲染
animate();
});
- createPanel()的代码,使用了gui,用来控制是否开启闪烁效果
function createPanel() {
const panel = new GUI({ width: 310 });
const folder1 = panel.addFolder("物体效果");
settings = {
闪烁: false,
};
folder1.add(settings, "闪烁");
folder1.open();
}
- animate()的代码,requestAnimationFrame(animate);这个要加上,没有这个改了透明度页面没有变化,本来是按照thingjs那样用的sin函数,但是透明度一开始是1,而一开始的elapsed是0,会使透明度突然从1变成0.5,就会有卡顿的感觉,所以改成了cos函数。
function animate() {
requestAnimationFrame(animate);
if (settings && settings["闪烁"]) {
const elapsed = clock.getElapsedTime();
model.traverse(function (child) {
if (child.material) {
// getElapsedTime 获取自时钟启动后的秒数
// 让透明度根据秒数的增加呈函数式变化
let opacity = 0.5 + 0.5 * Math.cos(2 * elapsed);
child.material.opacity = opacity;
}
});
}
render();
}
写在最后
以上就是所有的代码以及说明~