持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
写在前面
本文用vue+threejs实现标注跳跃动画。
演示gif:
代码说明
首先,是threejs场景、相机、灯光、渲染器、轨道控制器的创建,然后是模型的加载,这些步骤在前面的文章中已经说过很多次了,这里就不再多说,这里主要说明跳跃动画的实现代码。
我们先需要给加载的模型添加标注,使用的是threejs提供的CSS2DRenderer和CSS2DObject,在mounted()方法中调用initLabelRenderer()方法创建CSS 2D渲染器,然后将标注元素节点添加到CSS2DObject中 const RabbitTag = new CSS2DObject(this.Rabbit);,并设置标注的位置RabbitTag.position.set(gltf.scene.position.x,0.15,gltf.scene.position.z);,将标注的x、z位置设置为模型所在的位置,y位置设置为模型的上方,这里值为0.15,最后在render()的时候会调用this.labelRenderer.render(this.scene, this.camera);,此时标注就会和模型一起渲染在界面上。
然后是标注的跳跃动画,实现该动画用的是css的animation,通过给标注元素添加css动画animation: aniName linear 1s infinite;,动画的名称是aniName,动画的速度曲线是linear,动画的执行时间是1s,动画的执行次数的无数次infinite。
动画0%,100%的时候设置transform为translateY(0),80%的时候设置transform为translateY(-30px)。标注就会在相应的进度改变的时候改变他在y方向的位置。
至此,标注的跳跃动画就完成了。
完整代码
<template>
<div class="item">
<div id="THREE54">
<div id="Rabbit">
<div class="name"><img src="../../assets/imgs/point.png" alt="" width="20px"> 森林小屋</div>
</div>
</div>
</div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import {
CSS2DRenderer,
CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js"; // CSS 2D渲染器
export default {
data() {
return {
camera: null,
scene: null,
gltfLoader: null,
renderer: null,
controls: null,
labelRenderer: null,
};
},
mounted() {
this.gltfLoader = new GLTFLoader();
this.initScene(); // 创建场景
this.initCamera(); // 创建相机
this.initLight(); // 创建灯光
this.initRenderer(); // 创建渲染器
this.initLabelRenderer(); // 创建 CSS 2D渲染器
this.initControls(); //创建轨道控制器
this.initModel(); // 加载模型
},
methods: {
initScene() {
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0x000000); // 设置场景背景颜色
},
initCamera() {
this.camera = new THREE.PerspectiveCamera(
35,
(window.innerWidth - 201) / window.innerHeight,
1,
500
); // 透视相机
this.camera.position.x = 0.5;
this.camera.position.y = 0.5; // 设置相机的位置
this.camera.position.z = 1.8;
this.scene.add(this.camera); // 将相机添加到场景中
},
initLight() {
const light = new THREE.DirectionalLight(0xffffff); // 平行光
light.position.set(0.5, 1.0, 0.5).normalize(); // 设置平行光的方向,从(0.5, 1.0, 0.5)->target一般(0, 0, 0)
this.scene.add(light); // 将灯光添加到场景中
const ambLight = new THREE.AmbientLight(0xf0f0f0, 0.1); // 环境光
this.scene.add(ambLight);
},
initRenderer() {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth - 201, window.innerHeight);
document.getElementById("THREE54").appendChild(this.renderer.domElement);
},
initLabelRenderer() {
this.labelRenderer = new CSS2DRenderer();
this.labelRenderer.setSize(window.innerWidth - 201, window.innerHeight);
this.labelRenderer.domElement.style.position = "absolute";
this.labelRenderer.domElement.style.top = "0px";
document
.getElementById("THREE54")
.appendChild(this.labelRenderer.domElement);
},
initControls() {
this.controls = new OrbitControls(
this.camera,
this.labelRenderer.domElement
);
this.controls.addEventListener("change", this.render);
this.controls.enableDamping = true; // 开启惯性
},
initModel() {
this.gltfLoader.load(
"/models/models/gltf/forest_house/scene.gltf",
(gltf) => {
gltf.scene.scale.set(3, 3, 3);
this.Rabbit = document.getElementById("Rabbit");
const RabbitTag = new CSS2DObject(this.Rabbit);
RabbitTag.position.set(
gltf.scene.position.x,
0.15,
gltf.scene.position.z
);
gltf.scene.add(RabbitTag);
RabbitTag.layers.set(0);
this.scene.add(gltf.scene);
this.animate();
}
);
},
animate() {
requestAnimationFrame(this.animate);
this.controls.update();
this.render();
},
render() {
this.renderer.render(this.scene, this.camera);
this.labelRenderer.render(this.scene, this.camera);
},
},
};
</script>
<style lang="less" scoped>
#Rabbit {
position: relative;
.name {
position: absolute;
width: 100px;
height: 30px;
line-height: 20px;
left: -40px;
top: 6px;
left: -36px;
text-align: center;
font-size: 16px;
font-weight: bold;
color: rgb(63, 26, 224);
background-color: #fff;
animation: aniName linear 1s infinite;
img {
position: relative;
top: 3px;
}
}
@keyframes aniName {
0%,
100% {
transform: translateY(0);
}
80% {
transform: translateY(-30px);
}
}
}
</style>
写在最后
以上就是所有的代码和说明。