diff --git a/src/containers/City/animations.js b/src/containers/City/animations.js new file mode 100644 index 0000000..1f98a4f --- /dev/null +++ b/src/containers/City/animations.js @@ -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; \ No newline at end of file diff --git a/src/containers/City/index.css b/src/containers/City/index.css new file mode 100644 index 0000000..fdb2165 --- /dev/null +++ b/src/containers/City/index.css @@ -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); +} diff --git a/src/containers/City/index.js b/src/containers/City/index.js index 1092056..a4b890f 100644 --- a/src/containers/City/index.js +++ b/src/containers/City/index.js @@ -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 ( -
+