diff --git a/README.md b/README.md index c7dc389..43578dc 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ Three.js powered Minecraft skin viewer. // Change camera FOV skinViewer.fov = 70; + // Zoom out + skinViewer.zoom = 0.5; + // Control objects with your mouse! let control = skinview3d.createOrbitControls(skinViewer); control.enableRotate = true; diff --git a/examples/index.html b/examples/index.html index 56b15af..90efcae 100644 --- a/examples/index.html +++ b/examples/index.html @@ -118,6 +118,7 @@
+
@@ -367,6 +368,7 @@ document.getElementById("canvas_width").addEventListener("change", e => skinViewer.width = e.target.value); document.getElementById("canvas_height").addEventListener("change", e => skinViewer.height = e.target.value); document.getElementById("fov").addEventListener("change", e => skinViewer.fov = e.target.value); + document.getElementById("zoom").addEventListener("change", e => skinViewer.zoom = e.target.value); document.getElementById("global_animation_speed").addEventListener("change", e => skinViewer.animations.speed = e.target.value); document.getElementById("animation_pause_resume").addEventListener("click", () => skinViewer.animations.paused = !skinViewer.animations.paused); document.getElementById("rotate_animation").addEventListener("change", e => { @@ -466,6 +468,7 @@ skinViewer.width = document.getElementById("canvas_width").value; skinViewer.height = document.getElementById("canvas_height").value; skinViewer.fov = document.getElementById("fov").value; + skinViewer.zoom = document.getElementById("zoom").value; skinViewer.animations.speed = document.getElementById("global_animation_speed").value; if (document.getElementById("rotate_animation").checked) { rotateAnimation = skinViewer.animations.add(skinview3d.RotatingAnimation); diff --git a/src/viewer.ts b/src/viewer.ts index f2d3c5a..79a8f86 100644 --- a/src/viewer.ts +++ b/src/viewer.ts @@ -63,6 +63,13 @@ export interface SkinViewerOptions { * The distance between the object and the camera is automatically computed. */ fov?: number; + + /** + * Zoom ratio of the player. Default is 0.9. + * This value affects the distance between the object and the camera. + * When set to 1.0, the top edge of the player's head coincides with the edge of the view. + */ + zoom?: number; } export class SkinViewer { @@ -82,6 +89,7 @@ export class SkinViewer { private _disposed: boolean = false; private _renderPaused: boolean = false; + private _zoom: number; private animationID: number | null; private onContextLost: (event: Event) => void; @@ -104,7 +112,6 @@ export class SkinViewer { this.scene = new Scene(); this.camera = new PerspectiveCamera(); - this.camera.position.z = 60; this.renderer = new WebGLRenderer({ canvas: this.canvas, @@ -140,6 +147,8 @@ export class SkinViewer { if (options.panorama !== undefined) { this.loadPanorama(options.panorama); } + this.camera.position.z = 1; + this._zoom = options.zoom === undefined ? 0.9 : options.zoom; this.fov = options.fov === undefined ? 50 : options.fov; if (options.renderPaused === true) { @@ -342,17 +351,35 @@ export class SkinViewer { } } + adjustCameraDistance(): void { + let distance = 4.5 + 16.5 / Math.tan(this.fov / 180 * Math.PI / 2) / this.zoom; + + // limit distance between 10 ~ 256 (default min / max distance of OrbitControls) + if (distance < 10) { + distance = 10; + } else if (distance > 256) { + distance = 256; + } + + this.camera.position.multiplyScalar(distance / this.camera.position.length()); + this.camera.updateProjectionMatrix(); + } + get fov(): number { return this.camera.fov; } set fov(value: number) { this.camera.fov = value; - let distance = 4 + 20 / Math.tan(value / 180 * Math.PI / 2); - if (distance < 10) { - distance = 10; - } - this.camera.position.multiplyScalar(distance / this.camera.position.length()); - this.camera.updateProjectionMatrix(); + this.adjustCameraDistance(); + } + + get zoom(): number { + return this._zoom; + } + + set zoom(value: number) { + this._zoom = value; + this.adjustCameraDistance(); } }