feat: 数字城市示例增加入场相机动画、添加加载进度显示.

This commit is contained in:
dragonir 2022-01-04 10:34:35 +08:00
parent 904825aa5c
commit 9190ee71b0
3 changed files with 102 additions and 4 deletions

View File

@ -0,0 +1,44 @@
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";
const Animations = {
//相机移动实现漫游等动画
animateCamera: (camera, controls, newP, newT, time = 2000, callBack) => {
console.log(camera, controls, newP, newT)
var tween = new TWEEN.Tween({
x1: camera.position.x, // 相机x
y1: camera.position.y, // 相机y
z1: camera.position.z, // 相机z
x2: controls.target.x, // 控制点的中心点x
y2: controls.target.y, // 控制点的中心点y
z2: controls.target.z, // 控制点的中心点z
});
console.log(tween)
tween.to({
x1: newP.x,
y1: newP.y,
z1: newP.z,
x2: newT.x,
y2: newT.y,
z2: newT.z,
},
time
);
tween.onUpdate(function (object) {
camera.position.x = object.x1;
camera.position.y = object.y1;
camera.position.z = object.z1;
controls.target.x = object.x2;
controls.target.y = object.y2;
controls.target.z = object.z2;
controls.update();
});
tween.onComplete(function () {
controls.enabled = true;
console.log('complete')
callBack();
});
tween.easing(TWEEN.Easing.Cubic.InOut);
tween.start();
},
}
export default Animations;

View File

@ -0,0 +1,29 @@
#loading {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background: #582424;
background: -webkit-linear-gradient(to right, #97444f, #582424);
background: linear-gradient(to right, #97444f, #582424);
display: flex;
justify-content: space-around;
align-items: center;
font-size: 64px;
color: #FFFFFF;
text-shadow: 0 1px 0 hsl(174,5%,80%),
0 2px 0 hsl(174,5%,75%),
0 3px 0 hsl(174,5%,70%),
0 4px 0 hsl(174,5%,66%),
0 5px 0 hsl(174,5%,64%),
0 6px 0 hsl(174,5%,62%),
0 7px 0 hsl(174,5%,61%),
0 8px 0 hsl(174,5%,60%),
0 0 5px rgba(0,0,0,.05),
0 1px 3px rgba(0,0,0,.2),
0 3px 5px rgba(0,0,0,.2),
0 5px 10px rgba(0,0,0,.2),
0 10px 10px rgba(0,0,0,.2),
0 20px 20px rgba(0,0,0,.3);
}

View File

@ -5,6 +5,9 @@ import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module";
import cityModel from './models/city.fbx';
import Animations from './animations';
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";
import './index.css';
export default class City extends React.Component {
@ -12,6 +15,11 @@ export default class City extends React.Component {
super(props);
}
state = {
// 页面模型加载进度0未加载100加载完成
loadingProcess: 0
}
componentDidMount() {
this.initThree()
}
@ -19,14 +27,15 @@ export default class City extends React.Component {
initThree = () => {
var container, controls, stats;
var camera, scene, renderer, light, cityMeshes = [];
let _this = this;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container = document.getElementById('container');
container.appendChild(renderer.domElement);
// 场景
scene = new THREE.Scene();
@ -34,7 +43,7 @@ export default class City extends React.Component {
scene.fog = new THREE.Fog(0xeeeeee, 0, 100);
// 透视相机:视场、长宽比、近面、远面
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20);
camera.position.set(120, 100, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 半球光源:创建室外效果更加自然的光源
const cubeGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);
@ -71,7 +80,7 @@ export default class City extends React.Component {
// 加载模型
var loader = new FBXLoader();
loader.load(cityModel, function (mesh) {
loader.load(cityModel, mesh => {
mesh.traverse(function (child) {
if (child.isMesh) {
child.castShadow = true;
@ -84,6 +93,13 @@ export default class City extends React.Component {
mesh.position.set(40, 0, -50);
mesh.scale.set(1, 1, 1);
scene.add(mesh);
}, res => {
if (Number((res.loaded / res.total * 100).toFixed(0)) === 100) {
Animations.animateCamera(camera, controls, { x: 0, y: 10, z: 20 }, { x: 0, y: 0, z: 0 }, 4000, () => {});
}
_this.setState({ loadingProcess: Math.floor(res.loaded / res.total * 100) });
}, err => {
console.log(err);
});
controls = new OrbitControls(camera, renderer.domElement);
@ -105,6 +121,7 @@ export default class City extends React.Component {
requestAnimationFrame(animate);
renderer.render(scene, camera);
stats && stats.update();
TWEEN && TWEEN.update();
}
// 增加点击事件声明raycaster和mouse变量
@ -127,7 +144,15 @@ export default class City extends React.Component {
render () {
return (
<div id="container"></div>
<div>
<div id="container"></div>
{this.state.loadingProcess === 100 ? '' : (
<div id="loading">
<div className="box">{this.state.loadingProcess} %</div>
</div>
)
}
</div>
)
}
}