| import * as THREE from 'three'; |
| import * as TWEEN from '@tweenjs/tween.js'; |
|
|
| const scene = new THREE.Scene(); |
| scene.background = new THREE.Color( |
| |
| 'white' |
| ); |
| const clock = new THREE.Clock(); |
| const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); |
| camera.position.set(0, 30, 50); |
| camera.lookAt(0, 3, 0); |
| const controls = new (<any>THREE).OrbitControls(camera); |
| const ambientLight = new THREE.AmbientLight(0xffffff, 1); |
| scene.add(ambientLight); |
| const renderer = new THREE.WebGLRenderer({ antialias: true }); |
| renderer.setPixelRatio(window.devicePixelRatio); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| document.body.appendChild(renderer.domElement); |
| const stats = new Stats(); |
| document.body.appendChild(stats.dom); |
| |
| const mixers: THREE.AnimationMixer[] = []; |
|
|
| class Assets { |
| private static loadEggMtl(): Promise<THREE.Material[]> { |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).MTLLoader(); |
| loader.load( |
| `models/Egg_from_Poly_uovo/Egg from Poly uovo.mtl`, |
| (materials) => { |
| materials.preload(); |
| resolve(materials); |
| }, |
| (xhr) => {}, |
| reject |
| ); |
| }); |
| } |
| private static loadEggObj(materials: THREE.Material[]): Promise<THREE.Object3D> { |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).OBJLoader(); |
| (<any>loader).setMaterials(materials); |
| loader.load( |
| `models/Egg_from_Poly_uovo/Egg from Poly uovo.obj`, |
| (object: THREE.Object3D) => { |
| resolve(object); |
| }, |
| (xhr) => { |
| |
| }, |
| (error) => { |
| c.error(error); |
| reject(error); |
| } |
| ); |
| }); |
| } |
| static async loadEgg(): Promise<THREE.Object3D> { |
| const materialCreator = await this.loadEggMtl(); |
| return this.loadEggObj(materialCreator); |
| } |
| static loadEggGltf(): Promise<THREE.Scene> { |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).GLTFLoader(); |
| loader.load( |
| `models/Egg_gltf/Egg from Poly uovo copy.gltf`, |
| (gltf) => { |
| c.log(gltf); |
| resolve(gltf.scene); |
| } |
| ); |
| }); |
| } |
| static loadDogDae(): Promise<{ |
| animations: THREE.AnimationClip[]; |
| scene: THREE.Group; |
| }> { |
| |
| |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).ColladaLoader(); |
| loader.load( |
| `models/dog/pup_lohound.dae`, |
| (collada) => { |
| resolve(collada); |
| } |
| ); |
| }); |
| } |
| static loadDogFbx(): Promise<THREE.Group> { |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).FBXLoader(); |
| loader.load( |
| `models/dog_fbx/puppy-snapchat.fbx`, |
| (fbx) => { |
| resolve(fbx); |
| } |
| ); |
| }); |
| } |
| static loadBoloss(): Promise<{ |
| animations: THREE.AnimationClip[]; |
| scene: THREE.Group; |
| }> { |
| return new Promise((resolve, reject) => { |
| const loader: THREE.AnyLoader = new (<any>THREE).ColladaLoader(); |
| loader.load( |
| `models/boloss/Boloss-3d v10.dae`, |
| (collada) => { |
| resolve(collada); |
| } |
| ); |
| }); |
| } |
| } |
| class TUtils { |
| static boundingBox(o: THREE.Object3D): THREE.Box3 { |
| const bbox = new THREE.Box3().setFromObject(o); |
| return bbox; |
| } |
| static flushYZero(o: THREE.Object3D) { |
| o.position.y = -(this.boundingBox(o)).min.y; |
| } |
| static perform(tween: TWEEN.Tween): Promise<void> { |
| return new Promise(resolve => { |
| tween.onComplete(resolve).start(); |
| }); |
| } |
| } |
| (async () => { |
| |
| |
| |
| const gridHelper = new THREE.GridHelper(100, 100); |
| scene.add(gridHelper); |
| const axesHelper = new THREE.AxesHelper(50); |
| scene.add(axesHelper); |
| |
| |
| { |
| const egg = await Assets.loadEgg(); |
| c.log(egg); |
| egg.scale.setScalar(.2); |
| egg.rotateX(-Math.PI / 2); |
| egg.position.x = -18; |
| TUtils.flushYZero(egg); |
| const box = new THREE.BoxHelper(egg); |
| scene.add(box); |
| scene.add(egg); |
| |
| |
| |
| |
| } |
| { |
| const egg = await Assets.loadEggGltf(); |
| c.log(egg); |
| egg.scale.setScalar(100); |
| egg.position.x = -28; |
| TUtils.flushYZero(egg); |
| egg.remove(egg.getObjectByName('Camera')!); |
| scene.add(egg); |
| |
| const box = new THREE.BoxHelper(egg, new THREE.Color('red')); |
| scene.add(box); |
| } |
| { |
| |
| const dog = await Assets.loadDogFbx(); |
| |
| const mixer = new THREE.AnimationMixer(dog); |
| const clip: THREE.AnimationClip = (<any>dog).animations.find(clip => clip.name === "lohound|lohoundAction"); |
| |
| c.log(clip); |
| mixer.clipAction(clip).play(); |
| mixers.push(mixer); |
| const container = new THREE.Group(); |
| container.add(dog); |
| container.scale.setScalar(0.007); |
| container.position.x = -6; |
| scene.add(container); |
| const box = new THREE.BoxHelper(container, new THREE.Color('green')); |
| scene.add(box); |
| } |
| { |
| const boloss = (await Assets.loadBoloss()).scene; |
| c.log(boloss); |
| boloss.position.x = 16; |
| TUtils.flushYZero(boloss); |
| scene.add(boloss); |
| const box = new THREE.BoxHelper(boloss, new THREE.Color('blue')); |
| scene.add(box); |
| |
| const rootModel = boloss.getObjectByName(`SketchUp`)!; |
| const pupilL = boloss.getObjectByName(`Pupil-left`)!; |
| const pupilR = boloss.getObjectByName(`Pupil-right`)!; |
| const pupils = new THREE.Group(); |
| pupils.add(pupilL, pupilR); |
| rootModel.add(pupils); |
| (async () => { |
| while (true) { |
| const translatePupil = new TWEEN.Tween(pupils.position) |
| .to({ x: "-1", y: "-1" }, 200) |
| .easing(TWEEN.Easing.Quadratic.Out) |
| ; |
| const translatePupilRev = new TWEEN.Tween(pupils.position) |
| .to({ x: "+1", y: "+1" }, 200) |
| .easing(TWEEN.Easing.Quadratic.Out) |
| ; |
| await TUtils.perform(translatePupil); |
| await Utils.wait(4, 1); |
| await TUtils.perform(translatePupilRev); |
| await Utils.wait(8, 3); |
| } |
| })(); |
| const eyebrowL = boloss.getObjectByName(`Eyebrow-left`)!; |
| const eyebrowR = boloss.getObjectByName(`Eyebrow-right`)!; |
| const eyebrows = new THREE.Group(); |
| eyebrows.add(eyebrowL, eyebrowR); |
| rootModel.add(eyebrows); |
| (async () => { |
| while (true) { |
| const scaleEyebrow = new TWEEN.Tween(eyebrows.scale) |
| .to({ x: 1.08, y: 1.08, z: 1.08 }, 100) |
| .easing(TWEEN.Easing.Quadratic.InOut) |
| ; |
| const scaleEyebrowRev = new TWEEN.Tween(eyebrows.scale) |
| .to({ x: 1, y: 1, z: 1 }, 100) |
| .easing(TWEEN.Easing.Quadratic.InOut) |
| ; |
| await Utils.wait(6, 6); |
| await TUtils.perform(scaleEyebrow); |
| await TUtils.perform(scaleEyebrowRev); |
| await Utils.wait(0.14); |
| await TUtils.perform(scaleEyebrow); |
| await TUtils.perform(scaleEyebrowRev); |
| } |
| })(); |
| (async () => { |
| while (true) { |
| const angle = Utils.randomFloat(-0.2, 0.3); |
| const dummyL = new THREE.Object3D(); |
| dummyL.rotateOnAxis(new THREE.Vector3(0, 1, 0.8), angle); |
| const dummyR = new THREE.Object3D(); |
| dummyR.rotateOnAxis(new THREE.Vector3(0, -1, -0.8), angle); |
| |
| const rotateBrowL = new TWEEN.Tween(eyebrowL.rotation) |
| .to({ |
| x: dummyL.rotation.x, |
| y: dummyL.rotation.y, |
| z: dummyL.rotation.z, |
| }, 300) |
| ; |
| const rotateBrowR = new TWEEN.Tween(eyebrowR.rotation) |
| .to({ |
| x: dummyR.rotation.x, |
| y: dummyR.rotation.y, |
| z: dummyR.rotation.z, |
| }, 300) |
| ; |
| await Promise.all([ |
| TUtils.perform(rotateBrowL), |
| TUtils.perform(rotateBrowR), |
| ]); |
| await Utils.wait(1, 1); |
| await Promise.all([ |
| TUtils.perform( |
| new TWEEN.Tween(eyebrowL.rotation).to({ x: 0, y: 0, z: 0 }, 300) |
| ), |
| TUtils.perform( |
| new TWEEN.Tween(eyebrowR.rotation).to({ x: 0, y: 0, z: 0 }, 300) |
| ), |
| ]); |
| await Utils.wait(1, 1); |
| |
| } |
| })(); |
| } |
|
|
| })(); |
|
|
| |
| |
| |
| window.addEventListener('resize', onWindowResize, false); |
| function onWindowResize() { |
| camera.aspect = window.innerWidth / window.innerHeight; |
| camera.updateProjectionMatrix(); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| } |
| function render() { |
| const delta = clock.getDelta(); |
| for (const mixer of mixers) { |
| mixer.update(delta); |
| } |
| renderer.render(scene, camera); |
| } |
| function animate() { |
| requestAnimationFrame(animate); |
| TWEEN.update(); |
| render(); |
| stats.update(); |
| } |
| animate(); |
|
|
|
|