父组件:
DOM:
<device-info-animate
:depth-value='depthValue'
:scope-value='scopeValue'
:rotate-value='rotateValue'
:propeller-run='true'
style='height: 180px'>
</device-info-animate>
data(){
return{
depthValue:0,
scopeValue:0,
rotateValue:0
}
}
动画组件:
<template>
<div id='container' class='device_info_animate'></div>
</template>
<script>
import * as THREE from 'three';
import { cloneDeep } from 'lodash';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
let _scene = undefined;
let _camera = undefined;
let _renderer = undefined;
let _renderXFrame_new = undefined;
let _renderZFrame_new = undefined;
let _renderYFrame_new = undefined;
let _animateFrame = undefined;
export default {
name: 'DeviceInfoAnimate',
props: {
depthValue: {
type: Number,
value: 0,
},
scopeValue: {
type: Number,
value: 0,
},
rotateValue: {
type: Number,
value: 0,
},
propellerRun: {
type: Boolean,
value: true,
},
},
watch: {
depthValue: {
handler(val) {
if (val || val === 0) {
let num = Number(val).toFixed(2);
this.cDepthValueNew = Number(Math.round(num / 0.2) * 0.2);
this.animateXRenderNew();
}
},
immediate: true,
},
scopeValue: {
handler(val) {
if (val || val === 0) {
let num = Number(val).toFixed(2);
this.cScopeValueNew = Number(Math.round(num / 0.2) * 0.2);
this.animateZRenderNew();
}
},
immediate: true,
},
rotateValue: {
handler(val) {
if (val || val === 0) {
let num = Number(val).toFixed(2);
this.cRotateValueNew = Number(Math.round(num / 0.2) * 0.2);
this.animateYRenderNew();
}
},
immediate: true,
},
propellerRun: {
handler(val) {
if (val) {
if (this.AnimationAction) {
this.AnimationAction.play();
}
} else {
if (this.AnimationAction) {
this.AnimationAction.stop();
}
}
},
immediate: true,
},
},
data() {
return {
mixer: undefined,
clock: undefined,
saveDepthPositionNew: 0, // 当前depth的值
saveScopePositionNew: 0, // 当前depth的值
saveRotatePositionNew: 0, // 当前depth的值
cDepthValueNew: 0, // 当前需要转动到的depth目标值
cScopeValueNew: 0, // 当前需要转动到的scope目标值
cRotateValueNew: 0, // 当前需要转动到的rotate目标值
AnimationAction: undefined,
renderXaxis: 0,
renderYaxis: 0,
renderZaxis: 0,
};
},
mounted() {
this.init();
},
destroyed() {},
methods: {
initAnimation() {
window.cancelAnimationFrame(_renderXFrame_new); //可以取消该次动画。
this.animateXRenderNew();
window.cancelAnimationFrame(_renderZFrame_new); //可以取消该次动画。
this.animateZRenderNew();
window.cancelAnimationFrame(_renderYFrame_new); //可以取消该次动画。
this.animateYRenderNew();
},
async init() {
let _this = this;
_scene = new THREE.Scene();
// 立方体网格模型
let geometry1 = new THREE.BoxGeometry(30, 20, 50);
let material1 = new THREE.MeshLambertMaterial({
color: 0xff0000,
}); //材质对象Material
let cube = new THREE.Mesh(geometry1, material1); //网格模型对象Mesh
cube.name='sheng-max'
_scene.add(cube)
let axesHelper = new THREE.AxesHelper(250);
_scene.add(axesHelper);
console.log('______scene', _scene);
_this.renderXaxis = new THREE.Vector3(500, 0, 500); //创建一个三维向量
_this.renderYaxis = new THREE.Vector3(0, 500, 0); //创建一个三维向量
_this.renderZaxis = new THREE.Vector3(500, 0, -500); //创建一个三维向量
// // 环境光
// let ambient = new THREE.AmbientLight(0xffffff, 0.5);
// _scene.add(ambient);
// 方向光1
let _directionalLight = new THREE.DirectionalLight(0xffffff, 1);
_directionalLight.position.set(-50, 5, -50);
_scene.add(_directionalLight);
// 方向光2
let directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);
directionalLight.position.set(50, 50, 50);
_scene.add(directionalLight);
// 方向光2
let directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.7);
directionalLight2.position.set(-70, 5, 50);
_scene.add(directionalLight2);
// 方向光2
let directionalLight3 = new THREE.DirectionalLight(0xffffff, 0.7);
directionalLight3.position.set(70, 5, -50);
_scene.add(directionalLight3);
const element = document.getElementById('container');
const width = element.clientWidth; // 窗口宽度
const height = element.clientHeight; // 窗口高度
const k = width / height; // 窗口宽高比
let s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
// PerspectiveCamera( fov, aspect, near, far )
_camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
_camera.position.set(200, 300, 200); //设置相机位置
_camera.lookAt(_scene.position); //设置相机方向(指向的场景对象)
_scene.add(_camera);
_renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: false,
});
_renderer.setSize(element.clientWidth, element.clientHeight); // 设置渲染区域尺寸
_renderer.shadowMap.enabled = true; // 显示阴影
// _renderer.shadowMap.type = THREE.PCFSoftShadowMap;
_renderer.setClearColor(0x000000, 0); // 设置背景颜色
element.appendChild(_renderer.domElement);
let _controls;
_controls = new OrbitControls(_camera, _renderer.domElement);
this.render();
},
render() {
_renderer.render(_scene, _camera); //执行渲染操作
},
animateXRenderNew() {
let model = undefined;
if (_scene && _scene.children) {
_scene.children.forEach((item) => {
if (item.name === 'sheng-max') {
model = item;
}
});
}
let rotWorldMatrix = new THREE.Matrix4(); //创建一个4*4矩阵
// console.log('_________rotWorldMatrix', rotWorldMatrix);
if (Number(this.saveDepthPositionNew) === this.cDepthValueNew) {
window.cancelAnimationFrame(_renderXFrame_new); // 取消该次动画。
} else {
let geometry = new THREE.SphereGeometry(3); //创建一个球体几何对象
let material = new THREE.MeshLambertMaterial({
color: 0x0000ff,
}); //材质对象Material
let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
_scene.add(mesh); //网格模型添加到场景中
// 'AxesHelper'
let arr1 = [];
_scene.children.forEach((obj) => {
if (obj.type !== 'AxesHelper') {
arr1.push(obj);
}
});
this.$set(_scene, 'children', arr1);
let axesHelper = new THREE.AxesHelper(250);
_scene.add(axesHelper);
// console.log('________normalize', this.renderXaxis.normalize());
if (model && model.matrix) {
if (this.cDepthValueNew === 0) {
if (Number(this.saveDepthPositionNew) > 0) {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else if (Number(this.saveDepthPositionNew) < 0) {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
if (this.cDepthValueNew > 0 && this.cDepthValueNew <= 90) {
if (Number(this.saveDepthPositionNew) <= 0) {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cDepthValueNew > this.saveDepthPositionNew) {
this.saveDepthPositionNew = Number(
Number(Number(this.saveDepthPositionNew)) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cDepthValueNew < 0 && this.cDepthValueNew >= -90) {
if (Number(this.saveDepthPositionNew) >= 0) {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cDepthValueNew > this.saveDepthPositionNew) {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveDepthPositionNew = Number(
Number(this.saveDepthPositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderXaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cDepthValueNew < -90 || this.cDepthValueNew > 90) {
window.cancelAnimationFrame(_renderXFrame_new); // 取消该次动画。
}
_renderXFrame_new = requestAnimationFrame(this.animateXRenderNew);
}
}
},
animateYRenderNew() {
let model = undefined;
if (_scene && _scene.children) {
_scene.children.forEach((item) => {
if (item.name === 'sheng-max') {
model = item;
}
});
}
let rotWorldMatrix = new THREE.Matrix4(); //创建一个4*4矩阵
if (Number(this.saveRotatePositionNew) === this.cRotateValueNew) {
window.cancelAnimationFrame(_renderYFrame_new); // 取消该次动画。
} else {
if (model && model.matrix) {
if (this.cRotateValueNew === 0) {
if (Number(this.saveRotatePositionNew) > 0) {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else if (Number(this.saveRotatePositionNew) < 0) {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
if (this.cRotateValueNew > 0 && this.cRotateValueNew <= 180) {
if (Number(this.saveRotatePositionNew) <= 0) {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cRotateValueNew > this.saveRotatePositionNew) {
this.saveRotatePositionNew = Number(
Number(Number(this.saveRotatePositionNew)) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cRotateValueNew < 0 && this.cRotateValueNew >= -180) {
if (Number(this.saveRotatePositionNew) >= 0) {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cRotateValueNew > this.saveRotatePositionNew) {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveRotatePositionNew = Number(
Number(this.saveRotatePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderYaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cRotateValueNew < -180 || this.cRotateValueNew > 180) {
window.cancelAnimationFrame(_renderYFrame_new); // 取消该次动画。
}
_renderYFrame_new = requestAnimationFrame(this.animateYRenderNew);
}
}
},
animateZRenderNew() {
let model = undefined;
if (_scene && _scene.children) {
_scene.children.forEach((item) => {
if (item.name === 'sheng-max') {
model = item;
}
});
}
let rotWorldMatrix = new THREE.Matrix4(); //创建一个4*4矩阵
if (Number(this.saveScopePositionNew) === this.cScopeValueNew) {
window.cancelAnimationFrame(_renderZFrame_new); // 取消该次动画。
} else {
if (model && model.matrix) {
if (this.cScopeValueNew === 0) {
if (Number(this.saveScopePositionNew) > 0) {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else if (Number(this.saveScopePositionNew) < 0) {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
if (this.cScopeValueNew > 0 && this.cScopeValueNew <= 90) {
if (Number(this.saveScopePositionNew) <= 0) {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cScopeValueNew > this.saveScopePositionNew) {
this.saveScopePositionNew = Number(
Number(Number(this.saveScopePositionNew)) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cScopeValueNew < 0 && this.cScopeValueNew >= -90) {
if (Number(this.saveScopePositionNew) >= 0) {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
if (this.cScopeValueNew > this.saveScopePositionNew) {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) + 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
} else {
this.saveScopePositionNew = Number(
Number(this.saveScopePositionNew) - 1.0
).toFixed(2);
rotWorldMatrix.makeRotationAxis(
this.renderZaxis.normalize(),
(-1.0 * Math.PI) / 180
);
rotWorldMatrix.multiply(model.matrix);
model.matrix = rotWorldMatrix;
model.rotation.setFromRotationMatrix(rotWorldMatrix);
}
}
}
if (this.cScopeValueNew < -90 || this.cScopeValueNew > 90) {
window.cancelAnimationFrame(_renderZFrame_new); // 取消该次动画。
}
_renderZFrame_new = requestAnimationFrame(this.animateZRenderNew);
}
}
},
animate() {
_animateFrame = requestAnimationFrame(this.animate);
// _controls.update();
if (this.mixer) {
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
this.mixer.update(this.clock.getDelta());
}
_renderer.render(_scene, _camera);
},
},
beforeDestroy() {
window.cancelAnimationFrame(_renderXFrame_new); //可以取消该次动画。
window.cancelAnimationFrame(_renderZFrame_new); //可以取消该次动画。
window.cancelAnimationFrame(_renderYFrame_new); //可以取消该次动画。
window.cancelAnimationFrame(_animateFrame); //可以取消该次动画。
},
};
</script>
<style lang='scss' scoped>
.device_info_animate {
width: 96%;
height: 100%;
margin-left: 2%;
margin-top: 8px;
border-radius: 6px;
//background-color: rgba(0, 0, 0, 0);
background: rgba(255, 255, 255, 0.15);
overflow: hidden;
}
</style>
问题描述:
子组件实时就收三个方向的角度值。其中 -90<=depthValue<=90
绕固定轴旋转;-90<=scopeValue<=90
绕固定轴旋转;-180<=rotateValue<=180
绕固定轴旋转
当传递一个值 执行动画时不会又问题,但是当一个动画在运行当中,接收到另外一个值或两个值,模型转动就回偏离预期效果,
例如:当接收 depthValue = 90
时开始执行动画,当执行到一半接收到 scopeValue = 90
,scopeValue
转动动画的转动方向不对了,当两个动画都结束后,分别接收 depthValue = 0与scopeValue = 0;
模型不会回到转动前的初始位置;为什么?解决方案与代码实现是什么?
你说 depthValue 会控制转动,但是我又没有看到你基于这个值做赋值。
那么大概是自动转,那么就有一个问题,比如说你基于 90 做旋转,旋转到 45 的时候,重新赋值了,暂停定时器,重新开始 90 的选择,那么这个时候结束的位置其实是 135。
所以解决办法有两个