Merge pull request #12 from printempw/master

Refactor animations and some minor updates
This commit is contained in:
Haowei Wen 2018-02-12 13:42:31 +08:00 committed by GitHub
commit e09af4093d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 182 additions and 62 deletions

View File

@ -28,28 +28,37 @@ Three.js powered Minecraft skin viewer.
capeUrl: "img/cape.png" capeUrl: "img/cape.png"
}); });
// change the skin and cape // Change the textures
// skinViewer.skinUrl = "img/skin.png"; skinViewer.skinUrl = "img/skin2.png";
// skinViewer.capeUrl = "img/cape.png"; skinViewer.capeUrl = "img/cape2.png";
// change the width and height // Resize the skin viewer
// skinViewer.width = 300; skinViewer.width = 300;
// skinViewer.height = 400; skinViewer.height = 400;
// enable the mouse control feature // Control objects with your mouse!
let control = new skinview3d.SkinControl(skinViewer); let control = skinview3d.createOrbitControls(skinViewer);
control.enableRotate = true;
// disable the 'right click to play/pause' feature control.enableZoom = false;
// control.enableAnimationControl = false; control.enablePan = false;
skinViewer.animation = new skinview3d.CompositeAnimation(); skinViewer.animation = new skinview3d.CompositeAnimation();
// add an animation // Add an animation
let walk = skinViewer.animation.add(skinview3d.WalkAnimation); let walk = skinViewer.animation.add(skinview3d.WalkingAnimation);
// Add another animation
let rotate = skinViewer.animation.add(skinview3d.RotatingAnimation);
// Remove an animation, stop walking dude
walk.remove();
// And run for now!
let run = skinViewer.animation.add(skinview3d.RunningAnimation);
// set its speed and some others // Set the speed of an animation
walk.speed = 1.5; run.speed = 3;
// walk.paused = true; // Pause single animation
run.paused = true;
// Pause all animations!
skinViewer.animationPaused = true;
</script> </script>
``` ```

View File

@ -55,17 +55,73 @@ class CompositeAnimation {
} }
} }
let WalkAnimation = (player, time) => { let WalkingAnimation = (player, time) => {
let skin = player.skin; let skin = player.skin;
let angleRot = time + Math.PI / 2;
// Leg Swing // Multiply by animation's natural speed
skin.leftLeg.rotation.x = Math.cos(angleRot); time *= 8;
skin.rightLeg.rotation.x = Math.cos(angleRot + (Math.PI));
// Arm Swing // Leg swing
skin.leftArm.rotation.x = Math.cos(angleRot + (Math.PI)); skin.leftLeg.rotation.x = Math.sin(time) * 0.5;
skin.rightArm.rotation.x = Math.cos(angleRot); skin.rightLeg.rotation.x = Math.sin(time + Math.PI) * 0.5;
// Arm swing
skin.leftArm.rotation.x = Math.sin(time + Math.PI) * 0.5;
skin.rightArm.rotation.x = Math.sin(time) * 0.5;
let basicArmRotationZ = Math.PI * 0.02;
skin.leftArm.rotation.z = Math.cos(time) * 0.03 + basicArmRotationZ;
skin.rightArm.rotation.z = Math.cos(time + Math.PI) * 0.03 - basicArmRotationZ;
// Head shaking with different frequency & amplitude
skin.head.rotation.y = Math.sin(time / 4) * 0.2;
skin.head.rotation.x = Math.sin(time / 5) * 0.1;
// Always add an angle for cape around the x axis
let basicCapeRotationX = Math.PI * 0.06;
player.cape.rotation.x = Math.sin(time / 1.5) * 0.06 + basicCapeRotationX;
}; };
export { CompositeAnimation, WalkAnimation, invokeAnimation }; let RunningAnimation = (player, time) => {
let skin = player.skin;
time *= 15;
// Leg swing with larger amplitude
skin.leftLeg.rotation.x = Math.cos(time + Math.PI) * 1.3;
skin.rightLeg.rotation.x = Math.cos(time) * 1.3;
// Arm swing
skin.leftArm.rotation.x = Math.cos(time) * 1.5;
skin.rightArm.rotation.x = Math.cos(time + Math.PI) * 1.5;
let basicArmRotationZ = Math.PI * 0.1;
skin.leftArm.rotation.z = Math.cos(time) * 0.1 + basicArmRotationZ;
skin.rightArm.rotation.z = Math.cos(time + Math.PI) * 0.1 - basicArmRotationZ;
// Jumping
player.position.y = Math.cos(time * 2);
// Dodging when running
player.position.x = Math.cos(time) * 0.15;
// Slightly tilting when running
player.rotation.z = Math.cos(time + Math.PI) * 0.01;
// Apply higher swing frequency, lower amplitude,
// and greater basic rotation around x axis,
// to cape when running.
let basicCapeRotationX = Math.PI * 0.3;
player.cape.rotation.x = Math.sin(time * 2) * 0.1 + basicCapeRotationX;
// What about head shaking?
// You shouldn't glance right and left when running dude :P
};
let RotatingAnimation = (player, time) => {
player.rotation.y = time;
};
export {
CompositeAnimation,
invokeAnimation,
WalkingAnimation,
RunningAnimation,
RotatingAnimation
};

View File

@ -593,4 +593,17 @@ class OrbitControls extends THREE.EventDispatcher {
} }
} }
export { OrbitControls }; function createOrbitControls(skinViewer) {
let control = new OrbitControls(skinViewer.camera, skinViewer.renderer.domElement);
// default configuration
control.enablePan = false;
control.target = new THREE.Vector3(0, -12, 0);
control.minDistance = 10;
control.maxDistance = 256;
control.update();
return control;
}
export { OrbitControls, createOrbitControls };

View File

@ -1,3 +1,10 @@
export { SkinObject, CapeObject, PlayerObject } from "./model"; export { SkinObject, CapeObject, PlayerObject } from "./model";
export { SkinViewer, SkinControl } from "./viewer"; export { SkinViewer } from "./viewer";
export { invokeAnimation, CompositeAnimation, WalkAnimation } from "./animation"; export { OrbitControls, createOrbitControls } from "./orbit_controls";
export {
invokeAnimation,
CompositeAnimation,
WalkingAnimation,
RunningAnimation,
RotatingAnimation
} from "./animation";

View File

@ -1,6 +1,5 @@
import * as THREE from "three"; import * as THREE from "three";
import { PlayerObject } from "./model"; import { PlayerObject } from "./model";
import { OrbitControls } from "./orbit_controls";
import { invokeAnimation } from "./animation"; import { invokeAnimation } from "./animation";
function copyImage(context, sX, sY, w, h, dX, dY, flipHorizontal) { function copyImage(context, sX, sY, w, h, dX, dY, flipHorizontal) {
@ -81,9 +80,10 @@ class SkinViewer {
// scene // scene
this.scene = new THREE.Scene(); this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75); // Use smaller fov to avoid distortion
this.camera = new THREE.PerspectiveCamera(40);
this.camera.position.y = -12; this.camera.position.y = -12;
this.camera.position.z = 30; this.camera.position.z = 60;
this.renderer = new THREE.WebGLRenderer({ angleRot: true, alpha: true, antialias: false }); this.renderer = new THREE.WebGLRenderer({ angleRot: true, alpha: true, antialias: false });
this.renderer.setSize(300, 300); // default size this.renderer.setSize(300, 300); // default size
@ -227,31 +227,4 @@ class SkinViewer {
} }
} }
class SkinControl { export { SkinViewer };
constructor(skinViewer) {
this.enableAnimationControl = true;
this.skinViewer = skinViewer;
this.orbitControls = new OrbitControls(skinViewer.camera, skinViewer.renderer.domElement);
this.orbitControls.enablePan = false;
this.orbitControls.target = new THREE.Vector3(0, -12, 0);
this.orbitControls.minDistance = 10;
this.orbitControls.maxDistance = 256;
this.orbitControls.update();
this.animationPauseListener = e => {
if (this.enableAnimationControl) {
e.preventDefault();
this.skinViewer.animationPaused = !this.skinViewer.animationPaused;
}
};
this.skinViewer.domElement.addEventListener("contextmenu", this.animationPauseListener, false);
}
dispose() {
this.skinViewer.domElement.removeEventListener("contextmenu", this.animationPauseListener, false);
this.orbitControls.dispose();
}
}
export { SkinViewer, SkinControl };

View File

@ -28,4 +28,6 @@ export class CompositeAnimation implements IAnimation {
public play(player: PlayerObject, time: number): void; public play(player: PlayerObject, time: number): void;
} }
export const WalkAnimation: AnimationFn; export const WalkingAnimation: AnimationFn;
export const RunningAnimation: AnimationFn;
export const RotatingAnimation: AnimationFn;

57
types/orbit_controls.d.ts vendored Normal file
View File

@ -0,0 +1,57 @@
import * as THREE from "three";
import { SkinViewer } from "./viewer";
export class OrbitControls {
public readonly object: THREE.Camera;
public readonly domElement: HTMLElement | HTMLDocument;
public enabled: boolean;
public target: THREE.Vector3;
public minDistance: number;
public maxDistance: number;
public minZoom: number;
public maxZoom: number;
public minPolarAngle: number;
public maxPolarAngle: number;
public minAzimuthAngle: number;
public maxAzimuthAngle: number;
public enableDamping: boolean;
public dampingFactor: number;
public enableZoom: boolean;
public zoomSpeed: number;
public enableRotate: boolean;
public rotateSpeed: number;
public enablePan: boolean;
public keyPanSpeed: number;
public autoRotate: boolean;
public autoRotateSpeed: number;
public enableKeys: boolean;
public keys: { LEFT: number, UP: number, RIGHT: number, BOTTOM: number };
public mouseButtons: { ORBIT: THREE.MOUSE, ZOOM: THREE.MOUSE, PAN: THREE.MOUSE };
constructor(object: THREE.Camera, domElement?: HTMLElement);
public getPolarAngle(): number;
public getAzimuthalAngle(): number;
public saveState(): void;
public reset(): void;
public update(): boolean;
public dispose(): void;
}
export function createOrbitControls(skinViewer: SkinViewer): OrbitControls;

View File

@ -1,3 +1,4 @@
export * from "./model"; export * from "./model";
export * from "./animation"; export * from "./animation";
export * from "./viewer"; export * from "./viewer";
export * from "./orbit_controls";

6
types/viewer.d.ts vendored
View File

@ -34,8 +34,10 @@ export class SkinViewer {
public dispose(): void; public dispose(): void;
} }
export class SkinControl { export class MouseControl {
public enableAnimationControl: boolean; public pan: boolean;
public zoom: boolean;
public rotation: boolean;
public readonly skinViewer: SkinViewer; public readonly skinViewer: SkinViewer;
constructor(skinViewer: SkinViewer); constructor(skinViewer: SkinViewer);