add 'fov' option

This commit is contained in:
Haowei Wen 2021-09-23 12:02:41 +08:00
parent 7114f93c7c
commit f273ee8b56
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4
4 changed files with 42 additions and 9 deletions

View File

@ -50,6 +50,9 @@ Three.js powered Minecraft skin viewer.
// Set the background to a panoramic image!
skinViewer.loadPanorama("img/panorama1.png");
// Change camera FOV
skinViewer.fov = 70;
// Control objects with your mouse!
let control = skinview3d.createOrbitControls(skinViewer);
control.enableRotate = true;

View File

@ -111,9 +111,14 @@
<button id="reset_all" type="button" class="control">Reset All</button>
<div class="control-section">
<h1>Canvas Size</h1>
<label class="control">Width: <input id="canvas_width" type="number" value="300" size="4"></label>
<label class="control">Height: <input id="canvas_height" type="number" value="300" size="4"></label>
<h1>Viewport</h1>
<div>
<label class="control">Width: <input id="canvas_width" type="number" value="300" size="4"></label>
<label class="control">Height: <input id="canvas_height" type="number" value="300" size="4"></label>
</div>
<div>
<label class="control">FOV: <input id="fov" type="number" value="50" step="1" min="1" max="179" size="2"></label>
</div>
</div>
<div class="control-section">
@ -358,6 +363,7 @@
function initializeControls() {
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("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 => {
@ -456,6 +462,7 @@
skinViewer.width = document.getElementById("canvas_width").value;
skinViewer.height = document.getElementById("canvas_height").value;
skinViewer.fov = document.getElementById("fov").value;
skinViewer.animations.speed = document.getElementById("global_animation_speed").value;
if (document.getElementById("rotate_animation").checked) {
rotateAnimation = skinViewer.animations.add(skinview3d.RotatingAnimation);

View File

@ -7,7 +7,7 @@ export function createOrbitControls(skinViewer: SkinViewer): OrbitControls {
// default configuration
control.enablePan = false;
control.target = new Vector3(0, -8, 0);
control.target = new Vector3(0, 0, 0);
control.minDistance = 10;
control.maxDistance = 256;
control.update();

View File

@ -1,5 +1,5 @@
import { inferModelType, isTextureSource, loadCapeToCanvas, loadImage, loadSkinToCanvas, ModelType, RemoteImage, TextureSource } from "skinview-utils";
import { Color, ColorRepresentation, EquirectangularReflectionMapping, NearestFilter, PerspectiveCamera, Scene, Texture, Vector2, WebGLRenderer } from "three";
import { Color, ColorRepresentation, EquirectangularReflectionMapping, Group, NearestFilter, PerspectiveCamera, Scene, Texture, Vector2, WebGLRenderer } from "three";
import { RootAnimation } from "./animation.js";
import { BackEquipment, PlayerObject } from "./model.js";
@ -57,6 +57,12 @@ export interface SkinViewerOptions {
* The panorama background to use. This option overrides 'background' option.
*/
panorama?: RemoteImage | TextureSource;
/**
* Camera vertical field of view, in degrees. Default is 50.
* The distance between the object and the camera is automatically computed.
*/
fov?: number;
}
export class SkinViewer {
@ -65,6 +71,7 @@ export class SkinViewer {
readonly camera: PerspectiveCamera;
readonly renderer: WebGLRenderer;
readonly playerObject: PlayerObject;
readonly playerWrapper: Group;
readonly animations: RootAnimation = new RootAnimation();
readonly skinCanvas: HTMLCanvasElement;
@ -96,9 +103,7 @@ export class SkinViewer {
this.scene = new Scene();
// Use smaller fov to avoid distortion
this.camera = new PerspectiveCamera(40);
this.camera.position.y = -8;
this.camera = new PerspectiveCamera();
this.camera.position.z = 60;
this.renderer = new WebGLRenderer({
@ -113,7 +118,10 @@ export class SkinViewer {
this.playerObject.name = "player";
this.playerObject.skin.visible = false;
this.playerObject.cape.visible = false;
this.scene.add(this.playerObject);
this.playerWrapper = new Group();
this.playerWrapper.add(this.playerObject);
this.playerWrapper.position.y = 8;
this.scene.add(this.playerWrapper);
if (options.skin !== undefined) {
this.loadSkin(options.skin, options.model);
@ -133,6 +141,7 @@ export class SkinViewer {
if (options.panorama !== undefined) {
this.loadPanorama(options.panorama);
}
this.fov = options.fov === undefined ? 50 : options.fov;
if (options.renderPaused === true) {
this._renderPaused = true;
@ -333,4 +342,18 @@ export class SkinViewer {
this.backgroundTexture = null;
}
}
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();
}
}