Favivon - Correção

This commit is contained in:
2026-05-30 19:59:39 -03:00
parent 76ddaa815d
commit d7dfd221f0
32859 changed files with 5459654 additions and 404 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2023 Poimandres
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+55
View File
@@ -0,0 +1,55 @@
# three-stdlib
[![Version](https://img.shields.io/npm/v/three-stdlib?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/three-stdlib)
[![Downloads](https://img.shields.io/npm/dt/three-stdlib.svg?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/three-stdlib)
[![Twitter](https://img.shields.io/twitter/follow/pmndrs?label=%40pmndrs&style=flat&colorA=000000&colorB=000000&logo=twitter&logoColor=000000)](https://twitter.com/pmndrs)
[![Discord](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=000000)](https://discord.gg/ZZjjNvJ)
[![release](https://github.com/pmndrs/three-stdlib/actions/workflows/main.yml/badge.svg?style=flat&colorA=000000&colorB=000000)](https://github.com/pmndrs/three-stdlib/actions/workflows/main.yml)
Stand-alone version of [threejs/examples/jsm](https://github.com/mrdoob/three.js/tree/dev/examples/jsm) written in Typescript & built for ESM & CJS.
## Basic usage
```bash
npm install three-stdlib
```
```ts
// Export collection
import * as STDLIB from 'three-stdlib'
// Flatbundle
import { OrbitControls, ... } from 'three-stdlib'
```
## Problem
`three/examples` are usually regarded as something that you copy/paste into your project and adapt to your needs. That's not how people use it, and this has caused numerous issues in the past.
## Solution
- A build system for ESM and CJS, compatible with browser, workers, and Node
- Class based, optimized for tree-shaking, no globals, exports instead of collections
- Typesafety with simple annotation-like types
- SemVer and NPM managed dependencies
But most importantly, allowing more people that use and rely on these primitives to hold a little stake, and to share the weight of maintaining it.
## How to Contribute
1. Fork and clone the repo
2. Run `yarn install` to install dependencies
3. Create a branch for your PR with `git checkout -b pr-type/issue-number-your-branch-name beta
4. Let's get cooking! 👨🏻‍🍳🥓
### Commit Guidelines
Be sure your commit messages follow this specification: https://conventionalcommits.org/en/v1.0.0-beta.4
## Publishing
We use `semantic-release-action` to deploy the package. Because of this only certain commits will trigger the action of creating a release:
- `chore` will not release a new version
- `fix:` will create a `0.0.x` version
- `feat:` will create a `0.x.0` version
- `BREAKING CHANGE:` will create a `x.0.0` version
+26
View File
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const CapsuleGeometry = /* @__PURE__ */ (() => {
class CapsuleGeometry2 extends THREE.LatheGeometry {
constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
const path = new THREE.Path();
path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0);
path.absarc(0, length / 2, radius, 0, Math.PI * 0.5);
super(path.getPoints(capSegments), radialSegments);
this.type = "CapsuleGeometry";
this.parameters = {
radius,
height: length,
capSegments,
radialSegments
};
}
static fromJSON(data) {
return new CapsuleGeometry2(data.radius, data.length, data.capSegments, data.radialSegments);
}
}
return CapsuleGeometry2;
})();
exports.CapsuleGeometry = CapsuleGeometry;
//# sourceMappingURL=CapsuleGeometry.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CapsuleGeometry.cjs","sources":["../../src/_polyfill/CapsuleGeometry.js"],"sourcesContent":["import { Path, LatheGeometry } from 'three'\n\nconst CapsuleGeometry = /* @__PURE__ */ (() => {\n class CapsuleGeometry extends LatheGeometry {\n constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {\n const path = new Path()\n path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0)\n path.absarc(0, length / 2, radius, 0, Math.PI * 0.5)\n\n super(path.getPoints(capSegments), radialSegments)\n\n this.type = 'CapsuleGeometry'\n\n this.parameters = {\n radius: radius,\n height: length,\n capSegments: capSegments,\n radialSegments: radialSegments,\n }\n }\n\n static fromJSON(data) {\n return new CapsuleGeometry(data.radius, data.length, data.capSegments, data.radialSegments)\n }\n }\n\n return CapsuleGeometry\n})()\n\nexport { CapsuleGeometry }\n"],"names":["CapsuleGeometry","LatheGeometry","Path"],"mappings":";;;AAEK,MAAC,kBAAmC,uBAAM;AAC7C,QAAMA,yBAAwBC,MAAAA,cAAc;AAAA,IAC1C,YAAY,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,iBAAiB,GAAG;AACvE,YAAM,OAAO,IAAIC,WAAM;AACvB,WAAK,OAAO,GAAG,CAAC,SAAS,GAAG,QAAQ,KAAK,KAAK,KAAK,CAAC;AACpD,WAAK,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG;AAEnD,YAAM,KAAK,UAAU,WAAW,GAAG,cAAc;AAEjD,WAAK,OAAO;AAEZ,WAAK,aAAa;AAAA,QAChB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,MACD;AAAA,IACF;AAAA,IAED,OAAO,SAAS,MAAM;AACpB,aAAO,IAAIF,iBAAgB,KAAK,QAAQ,KAAK,QAAQ,KAAK,aAAa,KAAK,cAAc;AAAA,IAC3F;AAAA,EACF;AAED,SAAOA;AACT,GAAC;;"}
+26
View File
@@ -0,0 +1,26 @@
import { LatheGeometry, Path } from "three";
const CapsuleGeometry = /* @__PURE__ */ (() => {
class CapsuleGeometry2 extends LatheGeometry {
constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
const path = new Path();
path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0);
path.absarc(0, length / 2, radius, 0, Math.PI * 0.5);
super(path.getPoints(capSegments), radialSegments);
this.type = "CapsuleGeometry";
this.parameters = {
radius,
height: length,
capSegments,
radialSegments
};
}
static fromJSON(data) {
return new CapsuleGeometry2(data.radius, data.length, data.capSegments, data.radialSegments);
}
}
return CapsuleGeometry2;
})();
export {
CapsuleGeometry
};
//# sourceMappingURL=CapsuleGeometry.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CapsuleGeometry.js","sources":["../../src/_polyfill/CapsuleGeometry.js"],"sourcesContent":["import { Path, LatheGeometry } from 'three'\n\nconst CapsuleGeometry = /* @__PURE__ */ (() => {\n class CapsuleGeometry extends LatheGeometry {\n constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {\n const path = new Path()\n path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0)\n path.absarc(0, length / 2, radius, 0, Math.PI * 0.5)\n\n super(path.getPoints(capSegments), radialSegments)\n\n this.type = 'CapsuleGeometry'\n\n this.parameters = {\n radius: radius,\n height: length,\n capSegments: capSegments,\n radialSegments: radialSegments,\n }\n }\n\n static fromJSON(data) {\n return new CapsuleGeometry(data.radius, data.length, data.capSegments, data.radialSegments)\n }\n }\n\n return CapsuleGeometry\n})()\n\nexport { CapsuleGeometry }\n"],"names":["CapsuleGeometry"],"mappings":";AAEK,MAAC,kBAAmC,uBAAM;AAC7C,QAAMA,yBAAwB,cAAc;AAAA,IAC1C,YAAY,SAAS,GAAG,SAAS,GAAG,cAAc,GAAG,iBAAiB,GAAG;AACvE,YAAM,OAAO,IAAI,KAAM;AACvB,WAAK,OAAO,GAAG,CAAC,SAAS,GAAG,QAAQ,KAAK,KAAK,KAAK,CAAC;AACpD,WAAK,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG;AAEnD,YAAM,KAAK,UAAU,WAAW,GAAG,cAAc;AAEjD,WAAK,OAAO;AAEZ,WAAK,aAAa;AAAA,QAChB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,MACD;AAAA,IACF;AAAA,IAED,OAAO,SAAS,MAAM;AACpB,aAAO,IAAIA,iBAAgB,KAAK,QAAQ,KAAK,QAAQ,KAAK,aAAa,KAAK,cAAc;AAAA,IAC3F;AAAA,EACF;AAED,SAAOA;AACT,GAAC;"}
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class CompressedArrayTexture extends THREE.CompressedTexture {
constructor(mipmaps, width, height, depth, format, type) {
super(mipmaps, width, height, format, type);
this.isCompressedArrayTexture = true;
this.image.depth = depth;
this.wrapR = THREE.ClampToEdgeWrapping;
}
}
exports.CompressedArrayTexture = CompressedArrayTexture;
//# sourceMappingURL=CompressedArrayTexture.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CompressedArrayTexture.cjs","sources":["../../src/_polyfill/CompressedArrayTexture.js"],"sourcesContent":["import { CompressedTexture, ClampToEdgeWrapping } from 'three'\n\nclass CompressedArrayTexture extends CompressedTexture {\n constructor(mipmaps, width, height, depth, format, type) {\n super(mipmaps, width, height, format, type)\n this.isCompressedArrayTexture = true\n this.image.depth = depth\n this.wrapR = ClampToEdgeWrapping\n }\n}\n\nexport { CompressedArrayTexture }\n"],"names":["CompressedTexture","ClampToEdgeWrapping"],"mappings":";;;AAEA,MAAM,+BAA+BA,MAAAA,kBAAkB;AAAA,EACrD,YAAY,SAAS,OAAO,QAAQ,OAAO,QAAQ,MAAM;AACvD,UAAM,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAC1C,SAAK,2BAA2B;AAChC,SAAK,MAAM,QAAQ;AACnB,SAAK,QAAQC,MAAmB;AAAA,EACjC;AACH;;"}
+13
View File
@@ -0,0 +1,13 @@
import { CompressedTexture, ClampToEdgeWrapping } from "three";
class CompressedArrayTexture extends CompressedTexture {
constructor(mipmaps, width, height, depth, format, type) {
super(mipmaps, width, height, format, type);
this.isCompressedArrayTexture = true;
this.image.depth = depth;
this.wrapR = ClampToEdgeWrapping;
}
}
export {
CompressedArrayTexture
};
//# sourceMappingURL=CompressedArrayTexture.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CompressedArrayTexture.js","sources":["../../src/_polyfill/CompressedArrayTexture.js"],"sourcesContent":["import { CompressedTexture, ClampToEdgeWrapping } from 'three'\n\nclass CompressedArrayTexture extends CompressedTexture {\n constructor(mipmaps, width, height, depth, format, type) {\n super(mipmaps, width, height, format, type)\n this.isCompressedArrayTexture = true\n this.image.depth = depth\n this.wrapR = ClampToEdgeWrapping\n }\n}\n\nexport { CompressedArrayTexture }\n"],"names":[],"mappings":";AAEA,MAAM,+BAA+B,kBAAkB;AAAA,EACrD,YAAY,SAAS,OAAO,QAAQ,OAAO,QAAQ,MAAM;AACvD,UAAM,SAAS,OAAO,QAAQ,QAAQ,IAAI;AAC1C,SAAK,2BAA2B;AAChC,SAAK,MAAM,QAAQ;AACnB,SAAK,QAAQ;AAAA,EACd;AACH;"}
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class CompressedCubeTexture extends THREE.CompressedTexture {
constructor(images, format, type) {
super(void 0, images[0].width, images[0].height, format, type, THREE.CubeReflectionMapping);
this.isCompressedCubeTexture = true;
this.isCubeTexture = true;
this.image = images;
}
}
exports.CompressedCubeTexture = CompressedCubeTexture;
//# sourceMappingURL=CompressedCubeTexture.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CompressedCubeTexture.cjs","sources":["../../src/_polyfill/CompressedCubeTexture.js"],"sourcesContent":["import { CompressedTexture, CubeReflectionMapping } from 'three'\n\nclass CompressedCubeTexture extends CompressedTexture {\n constructor(images, format, type) {\n super(undefined, images[0].width, images[0].height, format, type, CubeReflectionMapping)\n\n this.isCompressedCubeTexture = true\n this.isCubeTexture = true\n\n this.image = images\n }\n}\n\nexport { CompressedCubeTexture }\n"],"names":["CompressedTexture","CubeReflectionMapping"],"mappings":";;;AAEA,MAAM,8BAA8BA,MAAAA,kBAAkB;AAAA,EACpD,YAAY,QAAQ,QAAQ,MAAM;AAChC,UAAM,QAAW,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,QAAQ,QAAQ,MAAMC,MAAAA,qBAAqB;AAEvF,SAAK,0BAA0B;AAC/B,SAAK,gBAAgB;AAErB,SAAK,QAAQ;AAAA,EACd;AACH;;"}
+13
View File
@@ -0,0 +1,13 @@
import { CompressedTexture, CubeReflectionMapping } from "three";
class CompressedCubeTexture extends CompressedTexture {
constructor(images, format, type) {
super(void 0, images[0].width, images[0].height, format, type, CubeReflectionMapping);
this.isCompressedCubeTexture = true;
this.isCubeTexture = true;
this.image = images;
}
}
export {
CompressedCubeTexture
};
//# sourceMappingURL=CompressedCubeTexture.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"CompressedCubeTexture.js","sources":["../../src/_polyfill/CompressedCubeTexture.js"],"sourcesContent":["import { CompressedTexture, CubeReflectionMapping } from 'three'\n\nclass CompressedCubeTexture extends CompressedTexture {\n constructor(images, format, type) {\n super(undefined, images[0].width, images[0].height, format, type, CubeReflectionMapping)\n\n this.isCompressedCubeTexture = true\n this.isCubeTexture = true\n\n this.image = images\n }\n}\n\nexport { CompressedCubeTexture }\n"],"names":[],"mappings":";AAEA,MAAM,8BAA8B,kBAAkB;AAAA,EACpD,YAAY,QAAQ,QAAQ,MAAM;AAChC,UAAM,QAAW,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,QAAQ,QAAQ,MAAM,qBAAqB;AAEvF,SAAK,0BAA0B;AAC/B,SAAK,gBAAgB;AAErB,SAAK,QAAQ;AAAA,EACd;AACH;"}
+18
View File
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
class Data3DTexture extends THREE.Texture {
constructor(data = null, width = 1, height = 1, depth = 1) {
super(null);
this.isData3DTexture = true;
this.image = { data, width, height, depth };
this.magFilter = THREE.NearestFilter;
this.minFilter = THREE.NearestFilter;
this.wrapR = THREE.ClampToEdgeWrapping;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
}
}
exports.Data3DTexture = Data3DTexture;
//# sourceMappingURL=Data3DTexture.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Data3DTexture.cjs","sources":["../../src/_polyfill/Data3DTexture.js"],"sourcesContent":["import { Texture, ClampToEdgeWrapping, NearestFilter } from 'three'\n\nclass Data3DTexture extends Texture {\n constructor(data = null, width = 1, height = 1, depth = 1) {\n super(null)\n\n this.isData3DTexture = true\n\n this.image = { data, width, height, depth }\n\n this.magFilter = NearestFilter\n this.minFilter = NearestFilter\n\n this.wrapR = ClampToEdgeWrapping\n\n this.generateMipmaps = false\n this.flipY = false\n this.unpackAlignment = 1\n }\n}\n\nexport { Data3DTexture }\n"],"names":["Texture","NearestFilter","ClampToEdgeWrapping"],"mappings":";;;AAEA,MAAM,sBAAsBA,MAAAA,QAAQ;AAAA,EAClC,YAAY,OAAO,MAAM,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG;AACzD,UAAM,IAAI;AAEV,SAAK,kBAAkB;AAEvB,SAAK,QAAQ,EAAE,MAAM,OAAO,QAAQ,MAAO;AAE3C,SAAK,YAAYC,MAAa;AAC9B,SAAK,YAAYA,MAAa;AAE9B,SAAK,QAAQC,MAAmB;AAEhC,SAAK,kBAAkB;AACvB,SAAK,QAAQ;AACb,SAAK,kBAAkB;AAAA,EACxB;AACH;;"}
+18
View File
@@ -0,0 +1,18 @@
import { Texture, NearestFilter, ClampToEdgeWrapping } from "three";
class Data3DTexture extends Texture {
constructor(data = null, width = 1, height = 1, depth = 1) {
super(null);
this.isData3DTexture = true;
this.image = { data, width, height, depth };
this.magFilter = NearestFilter;
this.minFilter = NearestFilter;
this.wrapR = ClampToEdgeWrapping;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
}
}
export {
Data3DTexture
};
//# sourceMappingURL=Data3DTexture.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Data3DTexture.js","sources":["../../src/_polyfill/Data3DTexture.js"],"sourcesContent":["import { Texture, ClampToEdgeWrapping, NearestFilter } from 'three'\n\nclass Data3DTexture extends Texture {\n constructor(data = null, width = 1, height = 1, depth = 1) {\n super(null)\n\n this.isData3DTexture = true\n\n this.image = { data, width, height, depth }\n\n this.magFilter = NearestFilter\n this.minFilter = NearestFilter\n\n this.wrapR = ClampToEdgeWrapping\n\n this.generateMipmaps = false\n this.flipY = false\n this.unpackAlignment = 1\n }\n}\n\nexport { Data3DTexture }\n"],"names":[],"mappings":";AAEA,MAAM,sBAAsB,QAAQ;AAAA,EAClC,YAAY,OAAO,MAAM,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG;AACzD,UAAM,IAAI;AAEV,SAAK,kBAAkB;AAEvB,SAAK,QAAQ,EAAE,MAAM,OAAO,QAAQ,MAAO;AAE3C,SAAK,YAAY;AACjB,SAAK,YAAY;AAEjB,SAAK,QAAQ;AAEb,SAAK,kBAAkB;AACvB,SAAK,QAAQ;AACb,SAAK,kBAAkB;AAAA,EACxB;AACH;"}
+18
View File
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
function decodeText(array) {
if (typeof TextDecoder !== "undefined") {
return new TextDecoder().decode(array);
}
let s = "";
for (let i = 0, il = array.length; i < il; i++) {
s += String.fromCharCode(array[i]);
}
try {
return decodeURIComponent(escape(s));
} catch (e) {
return s;
}
}
exports.decodeText = decodeText;
//# sourceMappingURL=LoaderUtils.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"LoaderUtils.cjs","sources":["../../src/_polyfill/LoaderUtils.js"],"sourcesContent":["export function decodeText(array) {\n if (typeof TextDecoder !== 'undefined') {\n return new TextDecoder().decode(array)\n }\n\n // Avoid the String.fromCharCode.apply(null, array) shortcut, which\n // throws a \"maximum call stack size exceeded\" error for large arrays.\n\n let s = ''\n\n for (let i = 0, il = array.length; i < il; i++) {\n // Implicitly assumes little-endian.\n s += String.fromCharCode(array[i])\n }\n\n try {\n // merges multi-byte utf-8 characters.\n\n return decodeURIComponent(escape(s))\n } catch (e) {\n // see https://github.com/mrdoob/three.js/issues/16358\n\n return s\n }\n}\n"],"names":[],"mappings":";;AAAO,SAAS,WAAW,OAAO;AAChC,MAAI,OAAO,gBAAgB,aAAa;AACtC,WAAO,IAAI,YAAW,EAAG,OAAO,KAAK;AAAA,EACtC;AAKD,MAAI,IAAI;AAER,WAAS,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAE9C,SAAK,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,EAClC;AAED,MAAI;AAGF,WAAO,mBAAmB,OAAO,CAAC,CAAC;AAAA,EACpC,SAAQ,GAAP;AAGA,WAAO;AAAA,EACR;AACH;;"}
+18
View File
@@ -0,0 +1,18 @@
function decodeText(array) {
if (typeof TextDecoder !== "undefined") {
return new TextDecoder().decode(array);
}
let s = "";
for (let i = 0, il = array.length; i < il; i++) {
s += String.fromCharCode(array[i]);
}
try {
return decodeURIComponent(escape(s));
} catch (e) {
return s;
}
}
export {
decodeText
};
//# sourceMappingURL=LoaderUtils.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"LoaderUtils.js","sources":["../../src/_polyfill/LoaderUtils.js"],"sourcesContent":["export function decodeText(array) {\n if (typeof TextDecoder !== 'undefined') {\n return new TextDecoder().decode(array)\n }\n\n // Avoid the String.fromCharCode.apply(null, array) shortcut, which\n // throws a \"maximum call stack size exceeded\" error for large arrays.\n\n let s = ''\n\n for (let i = 0, il = array.length; i < il; i++) {\n // Implicitly assumes little-endian.\n s += String.fromCharCode(array[i])\n }\n\n try {\n // merges multi-byte utf-8 characters.\n\n return decodeURIComponent(escape(s))\n } catch (e) {\n // see https://github.com/mrdoob/three.js/issues/16358\n\n return s\n }\n}\n"],"names":[],"mappings":"AAAO,SAAS,WAAW,OAAO;AAChC,MAAI,OAAO,gBAAgB,aAAa;AACtC,WAAO,IAAI,YAAW,EAAG,OAAO,KAAK;AAAA,EACtC;AAKD,MAAI,IAAI;AAER,WAAS,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAE9C,SAAK,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,EAClC;AAED,MAAI;AAGF,WAAO,mBAAmB,OAAO,CAAC,CAAC;AAAA,EACpC,SAAQ,GAAP;AAGA,WAAO;AAAA,EACR;AACH;"}
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const version = /* @__PURE__ */ (() => parseInt(THREE.REVISION.replace(/\D+/g, "")))();
exports.version = version;
//# sourceMappingURL=constants.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.cjs","sources":["../../src/_polyfill/constants.ts"],"sourcesContent":["import { REVISION } from 'three'\n\nexport const version = /* @__PURE__ */ (() => parseInt(REVISION.replace(/\\D+/g, '')))()\n"],"names":["REVISION"],"mappings":";;;AAEa,MAAA,iCAAiC,SAASA,MAAAA,SAAS,QAAQ,QAAQ,EAAE,CAAC,GAAG;;"}
+1
View File
@@ -0,0 +1 @@
export declare const version: number;
+6
View File
@@ -0,0 +1,6 @@
import { REVISION } from "three";
const version = /* @__PURE__ */ (() => parseInt(REVISION.replace(/\D+/g, "")))();
export {
version
};
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../src/_polyfill/constants.ts"],"sourcesContent":["import { REVISION } from 'three'\n\nexport const version = /* @__PURE__ */ (() => parseInt(REVISION.replace(/\\D+/g, '')))()\n"],"names":[],"mappings":";AAEa,MAAA,iCAAiC,SAAS,SAAS,QAAQ,QAAQ,EAAE,CAAC,GAAG;"}
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const constants = require("./constants.cjs");
const UV1 = constants.version >= 125 ? "uv1" : "uv2";
exports.UV1 = UV1;
//# sourceMappingURL=uv1.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"uv1.cjs","sources":["../../src/_polyfill/uv1.ts"],"sourcesContent":["import { version } from \"./constants\";\n\n/** uv2 renamed to uv1 in r125\n * \n * https://github.com/mrdoob/three.js/pull/25943\n*/\nexport const UV1 = version >= 125 ? 'uv1' : 'uv2'"],"names":["version"],"mappings":";;;AAMa,MAAA,MAAMA,UAAAA,WAAW,MAAM,QAAQ;;"}
+5
View File
@@ -0,0 +1,5 @@
/** uv2 renamed to uv1 in r125
*
* https://github.com/mrdoob/three.js/pull/25943
*/
export declare const UV1: string;
+6
View File
@@ -0,0 +1,6 @@
import { version } from "./constants.js";
const UV1 = version >= 125 ? "uv1" : "uv2";
export {
UV1
};
//# sourceMappingURL=uv1.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"uv1.js","sources":["../../src/_polyfill/uv1.ts"],"sourcesContent":["import { version } from \"./constants\";\n\n/** uv2 renamed to uv1 in r125\n * \n * https://github.com/mrdoob/three.js/pull/25943\n*/\nexport const UV1 = version >= 125 ? 'uv1' : 'uv2'"],"names":[],"mappings":";AAMa,MAAA,MAAM,WAAW,MAAM,QAAQ;"}
+57
View File
@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const AnimationClipCreator = {
CreateRotationAnimation(period, axis = "x") {
const times = [0, period], values = [0, 360];
const trackName = ".rotation[" + axis + "]";
const track = new THREE.NumberKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, period, [track]);
},
CreateScaleAxisAnimation(period, axis = "x") {
const times = [0, period], values = [0, 1];
const trackName = ".scale[" + axis + "]";
const track = new THREE.NumberKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, period, [track]);
},
CreateShakeAnimation(duration, shakeScale) {
const times = [], values = [], tmp = new THREE.Vector3();
for (let i = 0; i < duration * 10; i++) {
times.push(i / 10);
tmp.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1).multiply(shakeScale).toArray(values, values.length);
}
const trackName = ".position";
const track = new THREE.VectorKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, duration, [track]);
},
CreatePulsationAnimation(duration, pulseScale) {
const times = [], values = [], tmp = new THREE.Vector3();
for (let i = 0; i < duration * 10; i++) {
times.push(i / 10);
const scaleFactor = Math.random() * pulseScale;
tmp.set(scaleFactor, scaleFactor, scaleFactor).toArray(values, values.length);
}
const trackName = ".scale";
const track = new THREE.VectorKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, duration, [track]);
},
CreateVisibilityAnimation(duration) {
const times = [0, duration / 2, duration], values = [true, false, true];
const trackName = ".visible";
const track = new THREE.BooleanKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, duration, [track]);
},
CreateMaterialColorAnimation(duration, colors) {
const times = [], values = [], timeStep = duration / colors.length;
for (let i = 0; i < colors.length; i++) {
times.push(i * timeStep);
const color = colors[i];
values.push(color.r, color.g, color.b);
}
const trackName = ".material.color";
const track = new THREE.ColorKeyframeTrack(trackName, times, values);
return new THREE.AnimationClip(null, duration, [track]);
}
};
exports.AnimationClipCreator = AnimationClipCreator;
//# sourceMappingURL=AnimationClipCreator.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AnimationClipCreator.cjs","sources":["../../src/animation/AnimationClipCreator.js"],"sourcesContent":["import {\n AnimationClip,\n BooleanKeyframeTrack,\n ColorKeyframeTrack,\n NumberKeyframeTrack,\n Vector3,\n VectorKeyframeTrack,\n} from 'three'\n\nconst AnimationClipCreator = {\n CreateRotationAnimation(period, axis = 'x') {\n const times = [0, period],\n values = [0, 360]\n\n const trackName = '.rotation[' + axis + ']'\n\n const track = new NumberKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, period, [track])\n },\n\n CreateScaleAxisAnimation(period, axis = 'x') {\n const times = [0, period],\n values = [0, 1]\n\n const trackName = '.scale[' + axis + ']'\n\n const track = new NumberKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, period, [track])\n },\n\n CreateShakeAnimation(duration, shakeScale) {\n const times = [],\n values = [],\n tmp = new Vector3()\n\n for (let i = 0; i < duration * 10; i++) {\n times.push(i / 10)\n\n tmp\n .set(Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0)\n .multiply(shakeScale)\n .toArray(values, values.length)\n }\n\n const trackName = '.position'\n\n const track = new VectorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreatePulsationAnimation(duration, pulseScale) {\n const times = [],\n values = [],\n tmp = new Vector3()\n\n for (let i = 0; i < duration * 10; i++) {\n times.push(i / 10)\n\n const scaleFactor = Math.random() * pulseScale\n tmp.set(scaleFactor, scaleFactor, scaleFactor).toArray(values, values.length)\n }\n\n const trackName = '.scale'\n\n const track = new VectorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreateVisibilityAnimation(duration) {\n const times = [0, duration / 2, duration],\n values = [true, false, true]\n\n const trackName = '.visible'\n\n const track = new BooleanKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreateMaterialColorAnimation(duration, colors) {\n const times = [],\n values = [],\n timeStep = duration / colors.length\n\n for (let i = 0; i < colors.length; i++) {\n times.push(i * timeStep)\n\n const color = colors[i]\n values.push(color.r, color.g, color.b)\n }\n\n const trackName = '.material.color'\n\n const track = new ColorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n}\n\nexport { AnimationClipCreator }\n"],"names":["NumberKeyframeTrack","AnimationClip","Vector3","VectorKeyframeTrack","BooleanKeyframeTrack","ColorKeyframeTrack"],"mappings":";;;AASK,MAAC,uBAAuB;AAAA,EAC3B,wBAAwB,QAAQ,OAAO,KAAK;AAC1C,UAAM,QAAQ,CAAC,GAAG,MAAM,GACtB,SAAS,CAAC,GAAG,GAAG;AAElB,UAAM,YAAY,eAAe,OAAO;AAExC,UAAM,QAAQ,IAAIA,MAAAA,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAIC,MAAAA,cAAc,MAAM,QAAQ,CAAC,KAAK,CAAC;AAAA,EAC/C;AAAA,EAED,yBAAyB,QAAQ,OAAO,KAAK;AAC3C,UAAM,QAAQ,CAAC,GAAG,MAAM,GACtB,SAAS,CAAC,GAAG,CAAC;AAEhB,UAAM,YAAY,YAAY,OAAO;AAErC,UAAM,QAAQ,IAAID,MAAAA,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAIC,MAAAA,cAAc,MAAM,QAAQ,CAAC,KAAK,CAAC;AAAA,EAC/C;AAAA,EAED,qBAAqB,UAAU,YAAY;AACzC,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,MAAM,IAAIC,MAAAA,QAAS;AAErB,aAAS,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AACtC,YAAM,KAAK,IAAI,EAAE;AAEjB,UACG,IAAI,KAAK,OAAM,IAAK,IAAM,GAAK,KAAK,OAAQ,IAAG,IAAM,GAAK,KAAK,OAAM,IAAK,IAAM,CAAG,EACnF,SAAS,UAAU,EACnB,QAAQ,QAAQ,OAAO,MAAM;AAAA,IACjC;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAIC,MAAAA,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAIF,MAAAA,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,yBAAyB,UAAU,YAAY;AAC7C,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,MAAM,IAAIC,MAAAA,QAAS;AAErB,aAAS,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AACtC,YAAM,KAAK,IAAI,EAAE;AAEjB,YAAM,cAAc,KAAK,OAAM,IAAK;AACpC,UAAI,IAAI,aAAa,aAAa,WAAW,EAAE,QAAQ,QAAQ,OAAO,MAAM;AAAA,IAC7E;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAIC,MAAAA,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAIF,MAAAA,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,0BAA0B,UAAU;AAClC,UAAM,QAAQ,CAAC,GAAG,WAAW,GAAG,QAAQ,GACtC,SAAS,CAAC,MAAM,OAAO,IAAI;AAE7B,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAIG,MAAAA,qBAAqB,WAAW,OAAO,MAAM;AAE/D,WAAO,IAAIH,MAAAA,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,6BAA6B,UAAU,QAAQ;AAC7C,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,WAAW,WAAW,OAAO;AAE/B,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,KAAK,IAAI,QAAQ;AAEvB,YAAM,QAAQ,OAAO,CAAC;AACtB,aAAO,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAAA,IACtC;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAII,MAAAA,mBAAmB,WAAW,OAAO,MAAM;AAE7D,WAAO,IAAIJ,MAAAA,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AACH;;"}
+12
View File
@@ -0,0 +1,12 @@
import { AnimationClip, Vector3 } from 'three'
export interface AnimationClipCreator {
CreateRotationAnimation(period: number, axis: string): AnimationClip
CreateScaleAxisAnimation(period: number, axis: string): AnimationClip
CreateShakeAnimation(duration: number, shakeScale: Vector3): AnimationClip
CreatePulsationAnimation(duration: number, pulseScale: number): AnimationClip
CreateVisibilityAnimation(duration: number): AnimationClip
CreateMaterialColorAnimation(duration: number, colors: number[]): AnimationClip
}
export const AnimationClipCreator: AnimationClipCreator
+57
View File
@@ -0,0 +1,57 @@
import { NumberKeyframeTrack, AnimationClip, Vector3, VectorKeyframeTrack, BooleanKeyframeTrack, ColorKeyframeTrack } from "three";
const AnimationClipCreator = {
CreateRotationAnimation(period, axis = "x") {
const times = [0, period], values = [0, 360];
const trackName = ".rotation[" + axis + "]";
const track = new NumberKeyframeTrack(trackName, times, values);
return new AnimationClip(null, period, [track]);
},
CreateScaleAxisAnimation(period, axis = "x") {
const times = [0, period], values = [0, 1];
const trackName = ".scale[" + axis + "]";
const track = new NumberKeyframeTrack(trackName, times, values);
return new AnimationClip(null, period, [track]);
},
CreateShakeAnimation(duration, shakeScale) {
const times = [], values = [], tmp = new Vector3();
for (let i = 0; i < duration * 10; i++) {
times.push(i / 10);
tmp.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1).multiply(shakeScale).toArray(values, values.length);
}
const trackName = ".position";
const track = new VectorKeyframeTrack(trackName, times, values);
return new AnimationClip(null, duration, [track]);
},
CreatePulsationAnimation(duration, pulseScale) {
const times = [], values = [], tmp = new Vector3();
for (let i = 0; i < duration * 10; i++) {
times.push(i / 10);
const scaleFactor = Math.random() * pulseScale;
tmp.set(scaleFactor, scaleFactor, scaleFactor).toArray(values, values.length);
}
const trackName = ".scale";
const track = new VectorKeyframeTrack(trackName, times, values);
return new AnimationClip(null, duration, [track]);
},
CreateVisibilityAnimation(duration) {
const times = [0, duration / 2, duration], values = [true, false, true];
const trackName = ".visible";
const track = new BooleanKeyframeTrack(trackName, times, values);
return new AnimationClip(null, duration, [track]);
},
CreateMaterialColorAnimation(duration, colors) {
const times = [], values = [], timeStep = duration / colors.length;
for (let i = 0; i < colors.length; i++) {
times.push(i * timeStep);
const color = colors[i];
values.push(color.r, color.g, color.b);
}
const trackName = ".material.color";
const track = new ColorKeyframeTrack(trackName, times, values);
return new AnimationClip(null, duration, [track]);
}
};
export {
AnimationClipCreator
};
//# sourceMappingURL=AnimationClipCreator.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AnimationClipCreator.js","sources":["../../src/animation/AnimationClipCreator.js"],"sourcesContent":["import {\n AnimationClip,\n BooleanKeyframeTrack,\n ColorKeyframeTrack,\n NumberKeyframeTrack,\n Vector3,\n VectorKeyframeTrack,\n} from 'three'\n\nconst AnimationClipCreator = {\n CreateRotationAnimation(period, axis = 'x') {\n const times = [0, period],\n values = [0, 360]\n\n const trackName = '.rotation[' + axis + ']'\n\n const track = new NumberKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, period, [track])\n },\n\n CreateScaleAxisAnimation(period, axis = 'x') {\n const times = [0, period],\n values = [0, 1]\n\n const trackName = '.scale[' + axis + ']'\n\n const track = new NumberKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, period, [track])\n },\n\n CreateShakeAnimation(duration, shakeScale) {\n const times = [],\n values = [],\n tmp = new Vector3()\n\n for (let i = 0; i < duration * 10; i++) {\n times.push(i / 10)\n\n tmp\n .set(Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0)\n .multiply(shakeScale)\n .toArray(values, values.length)\n }\n\n const trackName = '.position'\n\n const track = new VectorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreatePulsationAnimation(duration, pulseScale) {\n const times = [],\n values = [],\n tmp = new Vector3()\n\n for (let i = 0; i < duration * 10; i++) {\n times.push(i / 10)\n\n const scaleFactor = Math.random() * pulseScale\n tmp.set(scaleFactor, scaleFactor, scaleFactor).toArray(values, values.length)\n }\n\n const trackName = '.scale'\n\n const track = new VectorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreateVisibilityAnimation(duration) {\n const times = [0, duration / 2, duration],\n values = [true, false, true]\n\n const trackName = '.visible'\n\n const track = new BooleanKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n\n CreateMaterialColorAnimation(duration, colors) {\n const times = [],\n values = [],\n timeStep = duration / colors.length\n\n for (let i = 0; i < colors.length; i++) {\n times.push(i * timeStep)\n\n const color = colors[i]\n values.push(color.r, color.g, color.b)\n }\n\n const trackName = '.material.color'\n\n const track = new ColorKeyframeTrack(trackName, times, values)\n\n return new AnimationClip(null, duration, [track])\n },\n}\n\nexport { AnimationClipCreator }\n"],"names":[],"mappings":";AASK,MAAC,uBAAuB;AAAA,EAC3B,wBAAwB,QAAQ,OAAO,KAAK;AAC1C,UAAM,QAAQ,CAAC,GAAG,MAAM,GACtB,SAAS,CAAC,GAAG,GAAG;AAElB,UAAM,YAAY,eAAe,OAAO;AAExC,UAAM,QAAQ,IAAI,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAI,cAAc,MAAM,QAAQ,CAAC,KAAK,CAAC;AAAA,EAC/C;AAAA,EAED,yBAAyB,QAAQ,OAAO,KAAK;AAC3C,UAAM,QAAQ,CAAC,GAAG,MAAM,GACtB,SAAS,CAAC,GAAG,CAAC;AAEhB,UAAM,YAAY,YAAY,OAAO;AAErC,UAAM,QAAQ,IAAI,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAI,cAAc,MAAM,QAAQ,CAAC,KAAK,CAAC;AAAA,EAC/C;AAAA,EAED,qBAAqB,UAAU,YAAY;AACzC,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,MAAM,IAAI,QAAS;AAErB,aAAS,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AACtC,YAAM,KAAK,IAAI,EAAE;AAEjB,UACG,IAAI,KAAK,OAAM,IAAK,IAAM,GAAK,KAAK,OAAQ,IAAG,IAAM,GAAK,KAAK,OAAM,IAAK,IAAM,CAAG,EACnF,SAAS,UAAU,EACnB,QAAQ,QAAQ,OAAO,MAAM;AAAA,IACjC;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAI,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAI,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,yBAAyB,UAAU,YAAY;AAC7C,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,MAAM,IAAI,QAAS;AAErB,aAAS,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AACtC,YAAM,KAAK,IAAI,EAAE;AAEjB,YAAM,cAAc,KAAK,OAAM,IAAK;AACpC,UAAI,IAAI,aAAa,aAAa,WAAW,EAAE,QAAQ,QAAQ,OAAO,MAAM;AAAA,IAC7E;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAI,oBAAoB,WAAW,OAAO,MAAM;AAE9D,WAAO,IAAI,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,0BAA0B,UAAU;AAClC,UAAM,QAAQ,CAAC,GAAG,WAAW,GAAG,QAAQ,GACtC,SAAS,CAAC,MAAM,OAAO,IAAI;AAE7B,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAI,qBAAqB,WAAW,OAAO,MAAM;AAE/D,WAAO,IAAI,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AAAA,EAED,6BAA6B,UAAU,QAAQ;AAC7C,UAAM,QAAQ,CAAE,GACd,SAAS,CAAE,GACX,WAAW,WAAW,OAAO;AAE/B,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,KAAK,IAAI,QAAQ;AAEvB,YAAM,QAAQ,OAAO,CAAC;AACtB,aAAO,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAAA,IACtC;AAED,UAAM,YAAY;AAElB,UAAM,QAAQ,IAAI,mBAAmB,WAAW,OAAO,MAAM;AAE7D,WAAO,IAAI,cAAc,MAAM,UAAU,CAAC,KAAK,CAAC;AAAA,EACjD;AACH;"}
+270
View File
@@ -0,0 +1,270 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const _q = /* @__PURE__ */ new THREE.Quaternion();
const _targetPos = /* @__PURE__ */ new THREE.Vector3();
const _targetVec = /* @__PURE__ */ new THREE.Vector3();
const _effectorPos = /* @__PURE__ */ new THREE.Vector3();
const _effectorVec = /* @__PURE__ */ new THREE.Vector3();
const _linkPos = /* @__PURE__ */ new THREE.Vector3();
const _invLinkQ = /* @__PURE__ */ new THREE.Quaternion();
const _linkScale = /* @__PURE__ */ new THREE.Vector3();
const _axis = /* @__PURE__ */ new THREE.Vector3();
const _vector = /* @__PURE__ */ new THREE.Vector3();
const _matrix = /* @__PURE__ */ new THREE.Matrix4();
class CCDIKSolver {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Array<Object>} iks
*/
constructor(mesh, iks = []) {
this.mesh = mesh;
this.iks = iks;
this._valid();
}
/**
* Update all IK bones.
*
* @return {CCDIKSolver}
*/
update() {
const iks = this.iks;
for (let i = 0, il = iks.length; i < il; i++) {
this.updateOne(iks[i]);
}
return this;
}
/**
* Update one IK bone
*
* @param {Object} ik parameter
* @return {CCDIKSolver}
*/
updateOne(ik) {
const bones = this.mesh.skeleton.bones;
const math = Math;
const effector = bones[ik.effector];
const target = bones[ik.target];
_targetPos.setFromMatrixPosition(target.matrixWorld);
const links = ik.links;
const iteration = ik.iteration !== void 0 ? ik.iteration : 1;
for (let i = 0; i < iteration; i++) {
let rotated = false;
for (let j = 0, jl = links.length; j < jl; j++) {
const link = bones[links[j].index];
if (links[j].enabled === false)
break;
const limitation = links[j].limitation;
const rotationMin = links[j].rotationMin;
const rotationMax = links[j].rotationMax;
link.matrixWorld.decompose(_linkPos, _invLinkQ, _linkScale);
_invLinkQ.invert();
_effectorPos.setFromMatrixPosition(effector.matrixWorld);
_effectorVec.subVectors(_effectorPos, _linkPos);
_effectorVec.applyQuaternion(_invLinkQ);
_effectorVec.normalize();
_targetVec.subVectors(_targetPos, _linkPos);
_targetVec.applyQuaternion(_invLinkQ);
_targetVec.normalize();
let angle = _targetVec.dot(_effectorVec);
if (angle > 1) {
angle = 1;
} else if (angle < -1) {
angle = -1;
}
angle = math.acos(angle);
if (angle < 1e-5)
continue;
if (ik.minAngle !== void 0 && angle < ik.minAngle) {
angle = ik.minAngle;
}
if (ik.maxAngle !== void 0 && angle > ik.maxAngle) {
angle = ik.maxAngle;
}
_axis.crossVectors(_effectorVec, _targetVec);
_axis.normalize();
_q.setFromAxisAngle(_axis, angle);
link.quaternion.multiply(_q);
if (limitation !== void 0) {
let c = link.quaternion.w;
if (c > 1)
c = 1;
const c2 = math.sqrt(1 - c * c);
link.quaternion.set(limitation.x * c2, limitation.y * c2, limitation.z * c2, c);
}
if (rotationMin !== void 0) {
link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).max(rotationMin));
}
if (rotationMax !== void 0) {
link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).min(rotationMax));
}
link.updateMatrixWorld(true);
rotated = true;
}
if (!rotated)
break;
}
return this;
}
/**
* Creates Helper
*
* @return {CCDIKHelper}
*/
createHelper() {
return new CCDIKHelper(this.mesh, this.iks);
}
// private methods
_valid() {
const iks = this.iks;
const bones = this.mesh.skeleton.bones;
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const effector = bones[ik.effector];
const links = ik.links;
let link0, link1;
link0 = effector;
for (let j = 0, jl = links.length; j < jl; j++) {
link1 = bones[links[j].index];
if (link0.parent !== link1) {
console.warn("THREE.CCDIKSolver: bone " + link0.name + " is not the child of bone " + link1.name);
}
link0 = link1;
}
}
}
}
function getPosition(bone, matrixWorldInv) {
return _vector.setFromMatrixPosition(bone.matrixWorld).applyMatrix4(matrixWorldInv);
}
function setPositionOfBoneToAttributeArray(array, index, bone, matrixWorldInv) {
const v = getPosition(bone, matrixWorldInv);
array[index * 3 + 0] = v.x;
array[index * 3 + 1] = v.y;
array[index * 3 + 2] = v.z;
}
class CCDIKHelper extends THREE.Object3D {
constructor(mesh, iks = [], sphereSize = 0.25) {
super();
this.root = mesh;
this.iks = iks;
this.matrix.copy(mesh.matrixWorld);
this.matrixAutoUpdate = false;
this.sphereGeometry = new THREE.SphereGeometry(sphereSize, 16, 8);
this.targetSphereMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color(16746632),
depthTest: false,
depthWrite: false,
transparent: true
});
this.effectorSphereMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color(8978312),
depthTest: false,
depthWrite: false,
transparent: true
});
this.linkSphereMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color(8947967),
depthTest: false,
depthWrite: false,
transparent: true
});
this.lineMaterial = new THREE.LineBasicMaterial({
color: new THREE.Color(16711680),
depthTest: false,
depthWrite: false,
transparent: true
});
this._init();
}
/**
* Updates IK bones visualization.
*/
updateMatrixWorld(force) {
const mesh = this.root;
if (this.visible) {
let offset = 0;
const iks = this.iks;
const bones = mesh.skeleton.bones;
_matrix.copy(mesh.matrixWorld).invert();
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const targetBone = bones[ik.target];
const effectorBone = bones[ik.effector];
const targetMesh = this.children[offset++];
const effectorMesh = this.children[offset++];
targetMesh.position.copy(getPosition(targetBone, _matrix));
effectorMesh.position.copy(getPosition(effectorBone, _matrix));
for (let j = 0, jl = ik.links.length; j < jl; j++) {
const link = ik.links[j];
const linkBone = bones[link.index];
const linkMesh = this.children[offset++];
linkMesh.position.copy(getPosition(linkBone, _matrix));
}
const line = this.children[offset++];
const array = line.geometry.attributes.position.array;
setPositionOfBoneToAttributeArray(array, 0, targetBone, _matrix);
setPositionOfBoneToAttributeArray(array, 1, effectorBone, _matrix);
for (let j = 0, jl = ik.links.length; j < jl; j++) {
const link = ik.links[j];
const linkBone = bones[link.index];
setPositionOfBoneToAttributeArray(array, j + 2, linkBone, _matrix);
}
line.geometry.attributes.position.needsUpdate = true;
}
}
this.matrix.copy(mesh.matrixWorld);
super.updateMatrixWorld(force);
}
/**
* Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.
*/
dispose() {
this.sphereGeometry.dispose();
this.targetSphereMaterial.dispose();
this.effectorSphereMaterial.dispose();
this.linkSphereMaterial.dispose();
this.lineMaterial.dispose();
const children = this.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.isLine)
child.geometry.dispose();
}
}
// private method
_init() {
const scope = this;
const iks = this.iks;
function createLineGeometry(ik) {
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array((2 + ik.links.length) * 3);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
return geometry;
}
function createTargetMesh() {
return new THREE.Mesh(scope.sphereGeometry, scope.targetSphereMaterial);
}
function createEffectorMesh() {
return new THREE.Mesh(scope.sphereGeometry, scope.effectorSphereMaterial);
}
function createLinkMesh() {
return new THREE.Mesh(scope.sphereGeometry, scope.linkSphereMaterial);
}
function createLine(ik) {
return new THREE.Line(createLineGeometry(ik), scope.lineMaterial);
}
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
this.add(createTargetMesh());
this.add(createEffectorMesh());
for (let j = 0, jl = ik.links.length; j < jl; j++) {
this.add(createLinkMesh());
}
this.add(createLine(ik));
}
}
}
exports.CCDIKHelper = CCDIKHelper;
exports.CCDIKSolver = CCDIKSolver;
//# sourceMappingURL=CCDIKSolver.cjs.map
File diff suppressed because one or more lines are too long
+30
View File
@@ -0,0 +1,30 @@
import { Object3D, SkinnedMesh, Vector3 } from 'three'
// tslint:disable-next-line:interface-name
export interface IKS {
effector: number
iteration: number
links: Array<{
enabled: boolean
index: number
limitation?: Vector3
rotationMin?: Vector3
rotationMax?: Vector3
}>
minAngle: number
maxAngle: number
target: number
}
export class CCDIKSolver {
constructor(mesh: SkinnedMesh, iks: IKS[])
update(): this
updateOne(iks: IKS): this
createHelper(): CCDIKHelper
}
export class CCDIKHelper extends Object3D {
constructor(mesh: SkinnedMesh, iks?: IKS[], sphereSize?: number)
dispose(): void
}
+270
View File
@@ -0,0 +1,270 @@
import { Object3D, SphereGeometry, MeshBasicMaterial, Color, LineBasicMaterial, Quaternion, Vector3, Matrix4, Mesh, Line, BufferGeometry, BufferAttribute } from "three";
const _q = /* @__PURE__ */ new Quaternion();
const _targetPos = /* @__PURE__ */ new Vector3();
const _targetVec = /* @__PURE__ */ new Vector3();
const _effectorPos = /* @__PURE__ */ new Vector3();
const _effectorVec = /* @__PURE__ */ new Vector3();
const _linkPos = /* @__PURE__ */ new Vector3();
const _invLinkQ = /* @__PURE__ */ new Quaternion();
const _linkScale = /* @__PURE__ */ new Vector3();
const _axis = /* @__PURE__ */ new Vector3();
const _vector = /* @__PURE__ */ new Vector3();
const _matrix = /* @__PURE__ */ new Matrix4();
class CCDIKSolver {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Array<Object>} iks
*/
constructor(mesh, iks = []) {
this.mesh = mesh;
this.iks = iks;
this._valid();
}
/**
* Update all IK bones.
*
* @return {CCDIKSolver}
*/
update() {
const iks = this.iks;
for (let i = 0, il = iks.length; i < il; i++) {
this.updateOne(iks[i]);
}
return this;
}
/**
* Update one IK bone
*
* @param {Object} ik parameter
* @return {CCDIKSolver}
*/
updateOne(ik) {
const bones = this.mesh.skeleton.bones;
const math = Math;
const effector = bones[ik.effector];
const target = bones[ik.target];
_targetPos.setFromMatrixPosition(target.matrixWorld);
const links = ik.links;
const iteration = ik.iteration !== void 0 ? ik.iteration : 1;
for (let i = 0; i < iteration; i++) {
let rotated = false;
for (let j = 0, jl = links.length; j < jl; j++) {
const link = bones[links[j].index];
if (links[j].enabled === false)
break;
const limitation = links[j].limitation;
const rotationMin = links[j].rotationMin;
const rotationMax = links[j].rotationMax;
link.matrixWorld.decompose(_linkPos, _invLinkQ, _linkScale);
_invLinkQ.invert();
_effectorPos.setFromMatrixPosition(effector.matrixWorld);
_effectorVec.subVectors(_effectorPos, _linkPos);
_effectorVec.applyQuaternion(_invLinkQ);
_effectorVec.normalize();
_targetVec.subVectors(_targetPos, _linkPos);
_targetVec.applyQuaternion(_invLinkQ);
_targetVec.normalize();
let angle = _targetVec.dot(_effectorVec);
if (angle > 1) {
angle = 1;
} else if (angle < -1) {
angle = -1;
}
angle = math.acos(angle);
if (angle < 1e-5)
continue;
if (ik.minAngle !== void 0 && angle < ik.minAngle) {
angle = ik.minAngle;
}
if (ik.maxAngle !== void 0 && angle > ik.maxAngle) {
angle = ik.maxAngle;
}
_axis.crossVectors(_effectorVec, _targetVec);
_axis.normalize();
_q.setFromAxisAngle(_axis, angle);
link.quaternion.multiply(_q);
if (limitation !== void 0) {
let c = link.quaternion.w;
if (c > 1)
c = 1;
const c2 = math.sqrt(1 - c * c);
link.quaternion.set(limitation.x * c2, limitation.y * c2, limitation.z * c2, c);
}
if (rotationMin !== void 0) {
link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).max(rotationMin));
}
if (rotationMax !== void 0) {
link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).min(rotationMax));
}
link.updateMatrixWorld(true);
rotated = true;
}
if (!rotated)
break;
}
return this;
}
/**
* Creates Helper
*
* @return {CCDIKHelper}
*/
createHelper() {
return new CCDIKHelper(this.mesh, this.iks);
}
// private methods
_valid() {
const iks = this.iks;
const bones = this.mesh.skeleton.bones;
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const effector = bones[ik.effector];
const links = ik.links;
let link0, link1;
link0 = effector;
for (let j = 0, jl = links.length; j < jl; j++) {
link1 = bones[links[j].index];
if (link0.parent !== link1) {
console.warn("THREE.CCDIKSolver: bone " + link0.name + " is not the child of bone " + link1.name);
}
link0 = link1;
}
}
}
}
function getPosition(bone, matrixWorldInv) {
return _vector.setFromMatrixPosition(bone.matrixWorld).applyMatrix4(matrixWorldInv);
}
function setPositionOfBoneToAttributeArray(array, index, bone, matrixWorldInv) {
const v = getPosition(bone, matrixWorldInv);
array[index * 3 + 0] = v.x;
array[index * 3 + 1] = v.y;
array[index * 3 + 2] = v.z;
}
class CCDIKHelper extends Object3D {
constructor(mesh, iks = [], sphereSize = 0.25) {
super();
this.root = mesh;
this.iks = iks;
this.matrix.copy(mesh.matrixWorld);
this.matrixAutoUpdate = false;
this.sphereGeometry = new SphereGeometry(sphereSize, 16, 8);
this.targetSphereMaterial = new MeshBasicMaterial({
color: new Color(16746632),
depthTest: false,
depthWrite: false,
transparent: true
});
this.effectorSphereMaterial = new MeshBasicMaterial({
color: new Color(8978312),
depthTest: false,
depthWrite: false,
transparent: true
});
this.linkSphereMaterial = new MeshBasicMaterial({
color: new Color(8947967),
depthTest: false,
depthWrite: false,
transparent: true
});
this.lineMaterial = new LineBasicMaterial({
color: new Color(16711680),
depthTest: false,
depthWrite: false,
transparent: true
});
this._init();
}
/**
* Updates IK bones visualization.
*/
updateMatrixWorld(force) {
const mesh = this.root;
if (this.visible) {
let offset = 0;
const iks = this.iks;
const bones = mesh.skeleton.bones;
_matrix.copy(mesh.matrixWorld).invert();
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const targetBone = bones[ik.target];
const effectorBone = bones[ik.effector];
const targetMesh = this.children[offset++];
const effectorMesh = this.children[offset++];
targetMesh.position.copy(getPosition(targetBone, _matrix));
effectorMesh.position.copy(getPosition(effectorBone, _matrix));
for (let j = 0, jl = ik.links.length; j < jl; j++) {
const link = ik.links[j];
const linkBone = bones[link.index];
const linkMesh = this.children[offset++];
linkMesh.position.copy(getPosition(linkBone, _matrix));
}
const line = this.children[offset++];
const array = line.geometry.attributes.position.array;
setPositionOfBoneToAttributeArray(array, 0, targetBone, _matrix);
setPositionOfBoneToAttributeArray(array, 1, effectorBone, _matrix);
for (let j = 0, jl = ik.links.length; j < jl; j++) {
const link = ik.links[j];
const linkBone = bones[link.index];
setPositionOfBoneToAttributeArray(array, j + 2, linkBone, _matrix);
}
line.geometry.attributes.position.needsUpdate = true;
}
}
this.matrix.copy(mesh.matrixWorld);
super.updateMatrixWorld(force);
}
/**
* Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.
*/
dispose() {
this.sphereGeometry.dispose();
this.targetSphereMaterial.dispose();
this.effectorSphereMaterial.dispose();
this.linkSphereMaterial.dispose();
this.lineMaterial.dispose();
const children = this.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.isLine)
child.geometry.dispose();
}
}
// private method
_init() {
const scope = this;
const iks = this.iks;
function createLineGeometry(ik) {
const geometry = new BufferGeometry();
const vertices = new Float32Array((2 + ik.links.length) * 3);
geometry.setAttribute("position", new BufferAttribute(vertices, 3));
return geometry;
}
function createTargetMesh() {
return new Mesh(scope.sphereGeometry, scope.targetSphereMaterial);
}
function createEffectorMesh() {
return new Mesh(scope.sphereGeometry, scope.effectorSphereMaterial);
}
function createLinkMesh() {
return new Mesh(scope.sphereGeometry, scope.linkSphereMaterial);
}
function createLine(ik) {
return new Line(createLineGeometry(ik), scope.lineMaterial);
}
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
this.add(createTargetMesh());
this.add(createEffectorMesh());
for (let j = 0, jl = ik.links.length; j < jl; j++) {
this.add(createLinkMesh());
}
this.add(createLine(ik));
}
}
}
export {
CCDIKHelper,
CCDIKSolver
};
//# sourceMappingURL=CCDIKSolver.js.map
File diff suppressed because one or more lines are too long
+689
View File
@@ -0,0 +1,689 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const CCDIKSolver = require("./CCDIKSolver.cjs");
const MMDPhysics = require("./MMDPhysics.cjs");
class MMDAnimationHelper {
/**
* @param {Object} params - (optional)
* @param {boolean} params.sync - Whether animation durations of added objects are synched. Default is true.
* @param {Number} params.afterglow - Default is 0.0.
* @param {boolean} params.resetPhysicsOnLoop - Default is true.
*/
constructor(params = {}) {
this.meshes = [];
this.camera = null;
this.cameraTarget = new THREE.Object3D();
this.cameraTarget.name = "target";
this.audio = null;
this.audioManager = null;
this.objects = /* @__PURE__ */ new WeakMap();
this.configuration = {
sync: params.sync !== void 0 ? params.sync : true,
afterglow: params.afterglow !== void 0 ? params.afterglow : 0,
resetPhysicsOnLoop: params.resetPhysicsOnLoop !== void 0 ? params.resetPhysicsOnLoop : true,
pmxAnimation: params.pmxAnimation !== void 0 ? params.pmxAnimation : false
};
this.enabled = {
animation: true,
ik: true,
grant: true,
physics: true,
cameraAnimation: true
};
this.onBeforePhysics = function() {
};
this.sharedPhysics = false;
this.masterPhysics = null;
}
/**
* Adds an Three.js Object to helper and setups animation.
* The anmation durations of added objects are synched
* if this.configuration.sync is true.
*
* @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
* @param {Object} params - (optional)
* @param {THREE.AnimationClip|Array<THREE.AnimationClip>} params.animation - Only for THREE.SkinnedMesh and THREE.Camera. Default is undefined.
* @param {boolean} params.physics - Only for THREE.SkinnedMesh. Default is true.
* @param {Integer} params.warmup - Only for THREE.SkinnedMesh and physics is true. Default is 60.
* @param {Number} params.unitStep - Only for THREE.SkinnedMesh and physics is true. Default is 1 / 65.
* @param {Integer} params.maxStepNum - Only for THREE.SkinnedMesh and physics is true. Default is 3.
* @param {Vector3} params.gravity - Only for THREE.SkinnedMesh and physics is true. Default ( 0, - 9.8 * 10, 0 ).
* @param {Number} params.delayTime - Only for THREE.Audio. Default is 0.0.
* @return {MMDAnimationHelper}
*/
add(object, params = {}) {
if (object.isSkinnedMesh) {
this._addMesh(object, params);
} else if (object.isCamera) {
this._setupCamera(object, params);
} else if (object.type === "Audio") {
this._setupAudio(object, params);
} else {
throw new Error(
"THREE.MMDAnimationHelper.add: accepts only THREE.SkinnedMesh or THREE.Camera or THREE.Audio instance."
);
}
if (this.configuration.sync)
this._syncDuration();
return this;
}
/**
* Removes an Three.js Object from helper.
*
* @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
* @return {MMDAnimationHelper}
*/
remove(object) {
if (object.isSkinnedMesh) {
this._removeMesh(object);
} else if (object.isCamera) {
this._clearCamera(object);
} else if (object.type === "Audio") {
this._clearAudio(object);
} else {
throw new Error(
"THREE.MMDAnimationHelper.remove: accepts only THREE.SkinnedMesh or THREE.Camera or THREE.Audio instance."
);
}
if (this.configuration.sync)
this._syncDuration();
return this;
}
/**
* Updates the animation.
*
* @param {Number} delta
* @return {MMDAnimationHelper}
*/
update(delta) {
if (this.audioManager !== null)
this.audioManager.control(delta);
for (let i = 0; i < this.meshes.length; i++) {
this._animateMesh(this.meshes[i], delta);
}
if (this.sharedPhysics)
this._updateSharedPhysics(delta);
if (this.camera !== null)
this._animateCamera(this.camera, delta);
return this;
}
/**
* Changes the pose of SkinnedMesh as VPD specifies.
*
* @param {THREE.SkinnedMesh} mesh
* @param {Object} vpd - VPD content parsed MMDParser
* @param {Object} params - (optional)
* @param {boolean} params.resetPose - Default is true.
* @param {boolean} params.ik - Default is true.
* @param {boolean} params.grant - Default is true.
* @return {MMDAnimationHelper}
*/
pose(mesh, vpd, params = {}) {
if (params.resetPose !== false)
mesh.pose();
const bones = mesh.skeleton.bones;
const boneParams = vpd.bones;
const boneNameDictionary = {};
for (let i = 0, il = bones.length; i < il; i++) {
boneNameDictionary[bones[i].name] = i;
}
const vector = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
for (let i = 0, il = boneParams.length; i < il; i++) {
const boneParam = boneParams[i];
const boneIndex = boneNameDictionary[boneParam.name];
if (boneIndex === void 0)
continue;
const bone = bones[boneIndex];
bone.position.add(vector.fromArray(boneParam.translation));
bone.quaternion.multiply(quaternion.fromArray(boneParam.quaternion));
}
mesh.updateMatrixWorld(true);
if (this.configuration.pmxAnimation && mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === "pmx") {
const sortedBonesData = this._sortBoneDataArray(mesh.geometry.userData.MMD.bones.slice());
const ikSolver = params.ik !== false ? this._createCCDIKSolver(mesh) : null;
const grantSolver = params.grant !== false ? this.createGrantSolver(mesh) : null;
this._animatePMXMesh(mesh, sortedBonesData, ikSolver, grantSolver);
} else {
if (params.ik !== false) {
this._createCCDIKSolver(mesh).update();
}
if (params.grant !== false) {
this.createGrantSolver(mesh).update();
}
}
return this;
}
/**
* Enabes/Disables an animation feature.
*
* @param {string} key
* @param {boolean} enabled
* @return {MMDAnimationHelper}
*/
enable(key, enabled) {
if (this.enabled[key] === void 0) {
throw new Error("THREE.MMDAnimationHelper.enable: unknown key " + key);
}
this.enabled[key] = enabled;
if (key === "physics") {
for (let i = 0, il = this.meshes.length; i < il; i++) {
this._optimizeIK(this.meshes[i], enabled);
}
}
return this;
}
/**
* Creates an GrantSolver instance.
*
* @param {THREE.SkinnedMesh} mesh
* @return {GrantSolver}
*/
createGrantSolver(mesh) {
return new GrantSolver(mesh, mesh.geometry.userData.MMD.grants);
}
// private methods
_addMesh(mesh, params) {
if (this.meshes.indexOf(mesh) >= 0) {
throw new Error("THREE.MMDAnimationHelper._addMesh: SkinnedMesh '" + mesh.name + "' has already been added.");
}
this.meshes.push(mesh);
this.objects.set(mesh, { looped: false });
this._setupMeshAnimation(mesh, params.animation);
if (params.physics !== false) {
this._setupMeshPhysics(mesh, params);
}
return this;
}
_setupCamera(camera, params) {
if (this.camera === camera) {
throw new Error("THREE.MMDAnimationHelper._setupCamera: Camera '" + camera.name + "' has already been set.");
}
if (this.camera)
this.clearCamera(this.camera);
this.camera = camera;
camera.add(this.cameraTarget);
this.objects.set(camera, {});
if (params.animation !== void 0) {
this._setupCameraAnimation(camera, params.animation);
}
return this;
}
_setupAudio(audio, params) {
if (this.audio === audio) {
throw new Error("THREE.MMDAnimationHelper._setupAudio: Audio '" + audio.name + "' has already been set.");
}
if (this.audio)
this.clearAudio(this.audio);
this.audio = audio;
this.audioManager = new AudioManager(audio, params);
this.objects.set(this.audioManager, {
duration: this.audioManager.duration
});
return this;
}
_removeMesh(mesh) {
let found = false;
let writeIndex = 0;
for (let i = 0, il = this.meshes.length; i < il; i++) {
if (this.meshes[i] === mesh) {
this.objects.delete(mesh);
found = true;
continue;
}
this.meshes[writeIndex++] = this.meshes[i];
}
if (!found) {
throw new Error(
"THREE.MMDAnimationHelper._removeMesh: SkinnedMesh '" + mesh.name + "' has not been added yet."
);
}
this.meshes.length = writeIndex;
return this;
}
_clearCamera(camera) {
if (camera !== this.camera) {
throw new Error("THREE.MMDAnimationHelper._clearCamera: Camera '" + camera.name + "' has not been set yet.");
}
this.camera.remove(this.cameraTarget);
this.objects.delete(this.camera);
this.camera = null;
return this;
}
_clearAudio(audio) {
if (audio !== this.audio) {
throw new Error("THREE.MMDAnimationHelper._clearAudio: Audio '" + audio.name + "' has not been set yet.");
}
this.objects.delete(this.audioManager);
this.audio = null;
this.audioManager = null;
return this;
}
_setupMeshAnimation(mesh, animation) {
const objects = this.objects.get(mesh);
if (animation !== void 0) {
const animations = Array.isArray(animation) ? animation : [animation];
objects.mixer = new THREE.AnimationMixer(mesh);
for (let i = 0, il = animations.length; i < il; i++) {
objects.mixer.clipAction(animations[i]).play();
}
objects.mixer.addEventListener("loop", function(event) {
const tracks = event.action._clip.tracks;
if (tracks.length > 0 && tracks[0].name.slice(0, 6) !== ".bones")
return;
objects.looped = true;
});
}
objects.ikSolver = this._createCCDIKSolver(mesh);
objects.grantSolver = this.createGrantSolver(mesh);
return this;
}
_setupCameraAnimation(camera, animation) {
const animations = Array.isArray(animation) ? animation : [animation];
const objects = this.objects.get(camera);
objects.mixer = new THREE.AnimationMixer(camera);
for (let i = 0, il = animations.length; i < il; i++) {
objects.mixer.clipAction(animations[i]).play();
}
}
_setupMeshPhysics(mesh, params) {
const objects = this.objects.get(mesh);
if (params.world === void 0 && this.sharedPhysics) {
const masterPhysics = this._getMasterPhysics();
if (masterPhysics !== null)
world = masterPhysics.world;
}
objects.physics = this._createMMDPhysics(mesh, params);
if (objects.mixer && params.animationWarmup !== false) {
this._animateMesh(mesh, 0);
objects.physics.reset();
}
objects.physics.warmup(params.warmup !== void 0 ? params.warmup : 60);
this._optimizeIK(mesh, true);
}
_animateMesh(mesh, delta) {
const objects = this.objects.get(mesh);
const mixer = objects.mixer;
const ikSolver = objects.ikSolver;
const grantSolver = objects.grantSolver;
const physics = objects.physics;
const looped = objects.looped;
if (mixer && this.enabled.animation) {
this._restoreBones(mesh);
mixer.update(delta);
this._saveBones(mesh);
if (this.configuration.pmxAnimation && mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === "pmx") {
if (!objects.sortedBonesData)
objects.sortedBonesData = this._sortBoneDataArray(mesh.geometry.userData.MMD.bones.slice());
this._animatePMXMesh(
mesh,
objects.sortedBonesData,
ikSolver && this.enabled.ik ? ikSolver : null,
grantSolver && this.enabled.grant ? grantSolver : null
);
} else {
if (ikSolver && this.enabled.ik) {
mesh.updateMatrixWorld(true);
ikSolver.update();
}
if (grantSolver && this.enabled.grant) {
grantSolver.update();
}
}
}
if (looped === true && this.enabled.physics) {
if (physics && this.configuration.resetPhysicsOnLoop)
physics.reset();
objects.looped = false;
}
if (physics && this.enabled.physics && !this.sharedPhysics) {
this.onBeforePhysics(mesh);
physics.update(delta);
}
}
// Sort bones in order by 1. transformationClass and 2. bone index.
// In PMX animation system, bone transformations should be processed
// in this order.
_sortBoneDataArray(boneDataArray) {
return boneDataArray.sort(function(a, b) {
if (a.transformationClass !== b.transformationClass) {
return a.transformationClass - b.transformationClass;
} else {
return a.index - b.index;
}
});
}
// PMX Animation system is a bit too complex and doesn't great match to
// Three.js Animation system. This method attempts to simulate it as much as
// possible but doesn't perfectly simulate.
// This method is more costly than the regular one so
// you are recommended to set constructor parameter "pmxAnimation: true"
// only if your PMX model animation doesn't work well.
// If you need better method you would be required to write your own.
_animatePMXMesh(mesh, sortedBonesData, ikSolver, grantSolver) {
_quaternionIndex = 0;
_grantResultMap.clear();
for (let i = 0, il = sortedBonesData.length; i < il; i++) {
updateOne(mesh, sortedBonesData[i].index, ikSolver, grantSolver);
}
mesh.updateMatrixWorld(true);
return this;
}
_animateCamera(camera, delta) {
const mixer = this.objects.get(camera).mixer;
if (mixer && this.enabled.cameraAnimation) {
mixer.update(delta);
camera.updateProjectionMatrix();
camera.up.set(0, 1, 0);
camera.up.applyQuaternion(camera.quaternion);
camera.lookAt(this.cameraTarget.position);
}
}
_optimizeIK(mesh, physicsEnabled) {
const iks = mesh.geometry.userData.MMD.iks;
const bones = mesh.geometry.userData.MMD.bones;
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const links = ik.links;
for (let j = 0, jl = links.length; j < jl; j++) {
const link = links[j];
if (physicsEnabled === true) {
link.enabled = bones[link.index].rigidBodyType > 0 ? false : true;
} else {
link.enabled = true;
}
}
}
}
_createCCDIKSolver(mesh) {
if (CCDIKSolver.CCDIKSolver === void 0) {
throw new Error("THREE.MMDAnimationHelper: Import CCDIKSolver.");
}
return new CCDIKSolver.CCDIKSolver(mesh, mesh.geometry.userData.MMD.iks);
}
_createMMDPhysics(mesh, params) {
if (MMDPhysics.MMDPhysics === void 0) {
throw new Error("THREE.MMDPhysics: Import MMDPhysics.");
}
return new MMDPhysics.MMDPhysics(mesh, mesh.geometry.userData.MMD.rigidBodies, mesh.geometry.userData.MMD.constraints, params);
}
/*
* Detects the longest duration and then sets it to them to sync.
* TODO: Not to access private properties ( ._actions and ._clip )
*/
_syncDuration() {
let max = 0;
const objects = this.objects;
const meshes = this.meshes;
const camera = this.camera;
const audioManager = this.audioManager;
for (let i = 0, il = meshes.length; i < il; i++) {
const mixer = this.objects.get(meshes[i]).mixer;
if (mixer === void 0)
continue;
for (let j = 0; j < mixer._actions.length; j++) {
const clip = mixer._actions[j]._clip;
if (!objects.has(clip)) {
objects.set(clip, {
duration: clip.duration
});
}
max = Math.max(max, objects.get(clip).duration);
}
}
if (camera !== null) {
const mixer = this.objects.get(camera).mixer;
if (mixer !== void 0) {
for (let i = 0, il = mixer._actions.length; i < il; i++) {
const clip = mixer._actions[i]._clip;
if (!objects.has(clip)) {
objects.set(clip, {
duration: clip.duration
});
}
max = Math.max(max, objects.get(clip).duration);
}
}
}
if (audioManager !== null) {
max = Math.max(max, objects.get(audioManager).duration);
}
max += this.configuration.afterglow;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const mixer = this.objects.get(this.meshes[i]).mixer;
if (mixer === void 0)
continue;
for (let j = 0, jl = mixer._actions.length; j < jl; j++) {
mixer._actions[j]._clip.duration = max;
}
}
if (camera !== null) {
const mixer = this.objects.get(camera).mixer;
if (mixer !== void 0) {
for (let i = 0, il = mixer._actions.length; i < il; i++) {
mixer._actions[i]._clip.duration = max;
}
}
}
if (audioManager !== null) {
audioManager.duration = max;
}
}
// workaround
_updatePropertyMixersBuffer(mesh) {
const mixer = this.objects.get(mesh).mixer;
const propertyMixers = mixer._bindings;
const accuIndex = mixer._accuIndex;
for (let i = 0, il = propertyMixers.length; i < il; i++) {
const propertyMixer = propertyMixers[i];
const buffer = propertyMixer.buffer;
const stride = propertyMixer.valueSize;
const offset = (accuIndex + 1) * stride;
propertyMixer.binding.getValue(buffer, offset);
}
}
/*
* Avoiding these two issues by restore/save bones before/after mixer animation.
*
* 1. PropertyMixer used by AnimationMixer holds cache value in .buffer.
* Calculating IK, Grant, and Physics after mixer animation can break
* the cache coherency.
*
* 2. Applying Grant two or more times without reset the posing breaks model.
*/
_saveBones(mesh) {
const objects = this.objects.get(mesh);
const bones = mesh.skeleton.bones;
let backupBones = objects.backupBones;
if (backupBones === void 0) {
backupBones = new Float32Array(bones.length * 7);
objects.backupBones = backupBones;
}
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
bone.position.toArray(backupBones, i * 7);
bone.quaternion.toArray(backupBones, i * 7 + 3);
}
}
_restoreBones(mesh) {
const objects = this.objects.get(mesh);
const backupBones = objects.backupBones;
if (backupBones === void 0)
return;
const bones = mesh.skeleton.bones;
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
bone.position.fromArray(backupBones, i * 7);
bone.quaternion.fromArray(backupBones, i * 7 + 3);
}
}
// experimental
_getMasterPhysics() {
if (this.masterPhysics !== null)
return this.masterPhysics;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const physics = this.meshes[i].physics;
if (physics !== void 0 && physics !== null) {
this.masterPhysics = physics;
return this.masterPhysics;
}
}
return null;
}
_updateSharedPhysics(delta) {
if (this.meshes.length === 0 || !this.enabled.physics || !this.sharedPhysics)
return;
const physics = this._getMasterPhysics();
if (physics === null)
return;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const p = this.meshes[i].physics;
if (p !== null && p !== void 0) {
p.updateRigidBodies();
}
}
physics.stepSimulation(delta);
for (let i = 0, il = this.meshes.length; i < il; i++) {
const p = this.meshes[i].physics;
if (p !== null && p !== void 0) {
p.updateBones();
}
}
}
}
const _quaternions = [];
let _quaternionIndex = 0;
function getQuaternion() {
if (_quaternionIndex >= _quaternions.length) {
_quaternions.push(new THREE.Quaternion());
}
return _quaternions[_quaternionIndex++];
}
const _grantResultMap = /* @__PURE__ */ new Map();
function updateOne(mesh, boneIndex, ikSolver, grantSolver) {
const bones = mesh.skeleton.bones;
const bonesData = mesh.geometry.userData.MMD.bones;
const boneData = bonesData[boneIndex];
const bone = bones[boneIndex];
if (_grantResultMap.has(boneIndex))
return;
const quaternion = getQuaternion();
_grantResultMap.set(boneIndex, quaternion.copy(bone.quaternion));
if (grantSolver && boneData.grant && !boneData.grant.isLocal && boneData.grant.affectRotation) {
const parentIndex = boneData.grant.parentIndex;
const ratio = boneData.grant.ratio;
if (!_grantResultMap.has(parentIndex)) {
updateOne(mesh, parentIndex, ikSolver, grantSolver);
}
grantSolver.addGrantRotation(bone, _grantResultMap.get(parentIndex), ratio);
}
if (ikSolver && boneData.ik) {
mesh.updateMatrixWorld(true);
ikSolver.updateOne(boneData.ik);
const links = boneData.ik.links;
for (let i = 0, il = links.length; i < il; i++) {
const link = links[i];
if (link.enabled === false)
continue;
const linkIndex = link.index;
if (_grantResultMap.has(linkIndex)) {
_grantResultMap.set(linkIndex, _grantResultMap.get(linkIndex).copy(bones[linkIndex].quaternion));
}
}
}
quaternion.copy(bone.quaternion);
}
class AudioManager {
/**
* @param {THREE.Audio} audio
* @param {Object} params - (optional)
* @param {Nuumber} params.delayTime
*/
constructor(audio, params = {}) {
this.audio = audio;
this.elapsedTime = 0;
this.currentTime = 0;
this.delayTime = params.delayTime !== void 0 ? params.delayTime : 0;
this.audioDuration = this.audio.buffer.duration;
this.duration = this.audioDuration + this.delayTime;
}
/**
* @param {Number} delta
* @return {AudioManager}
*/
control(delta) {
this.elapsed += delta;
this.currentTime += delta;
if (this._shouldStopAudio())
this.audio.stop();
if (this._shouldStartAudio())
this.audio.play();
return this;
}
// private methods
_shouldStartAudio() {
if (this.audio.isPlaying)
return false;
while (this.currentTime >= this.duration) {
this.currentTime -= this.duration;
}
if (this.currentTime < this.delayTime)
return false;
if (this.currentTime - this.delayTime > this.audioDuration)
return false;
return true;
}
_shouldStopAudio() {
return this.audio.isPlaying && this.currentTime >= this.duration;
}
}
const _q = /* @__PURE__ */ new THREE.Quaternion();
class GrantSolver {
constructor(mesh, grants = []) {
this.mesh = mesh;
this.grants = grants;
}
/**
* Solve all the grant bones
* @return {GrantSolver}
*/
update() {
const grants = this.grants;
for (let i = 0, il = grants.length; i < il; i++) {
this.updateOne(grants[i]);
}
return this;
}
/**
* Solve a grant bone
* @param {Object} grant - grant parameter
* @return {GrantSolver}
*/
updateOne(grant) {
const bones = this.mesh.skeleton.bones;
const bone = bones[grant.index];
const parentBone = bones[grant.parentIndex];
if (grant.isLocal) {
if (grant.affectPosition)
;
if (grant.affectRotation)
;
} else {
if (grant.affectPosition)
;
if (grant.affectRotation) {
this.addGrantRotation(bone, parentBone.quaternion, grant.ratio);
}
}
return this;
}
addGrantRotation(bone, q, ratio) {
_q.set(0, 0, 0, 1);
_q.slerp(q, ratio);
bone.quaternion.multiply(_q);
return this;
}
}
exports.MMDAnimationHelper = MMDAnimationHelper;
//# sourceMappingURL=MMDAnimationHelper.cjs.map
File diff suppressed because one or more lines are too long
+93
View File
@@ -0,0 +1,93 @@
import { AnimationClip, Audio, Camera, Object3D, Quaternion, SkinnedMesh, Bone, AnimationMixer } from 'three'
import { CCDIKSolver } from './CCDIKSolver'
import { MMDPhysics } from './MMDPhysics'
export interface MMDAnimationHelperParameter {
sync?: boolean | undefined
afterglow?: number | undefined
resetPhysicsOnLoop?: boolean | undefined
}
export interface MMDAnimationHelperAddParameter {
animation?: AnimationClip | AnimationClip[] | undefined
physics?: boolean | undefined
warmup?: number | undefined
unitStep?: number | undefined
maxStepNum?: number | undefined
gravity?: number | undefined
delayTime?: number | undefined
}
export interface MMDAnimationHelperPoseParameter {
resetPose?: boolean | undefined
ik?: boolean | undefined
grant?: boolean | undefined
}
export interface MMDAnimationHelperMixer {
looped: boolean
mixer?: AnimationMixer | undefined
ikSolver: CCDIKSolver
grantSolver: GrantSolver
physics?: MMDPhysics | undefined
duration?: number | undefined
}
export class MMDAnimationHelper {
constructor(params?: MMDAnimationHelperParameter)
meshes: SkinnedMesh[]
camera: Camera | null
cameraTarget: Object3D
audio: Audio
audioManager: AudioManager
configuration: {
sync: boolean
afterglow: number
resetPhysicsOnLoop: boolean
}
enabled: {
animation: boolean
ik: boolean
grant: boolean
physics: boolean
cameraAnimation: boolean
}
objects: WeakMap<SkinnedMesh | Camera | AudioManager, MMDAnimationHelperMixer>
onBeforePhysics: (mesh: SkinnedMesh) => void
sharedPhysics: boolean
masterPhysics: null
add(object: SkinnedMesh | Camera | Audio, params?: MMDAnimationHelperAddParameter): this
remove(object: SkinnedMesh | Camera | Audio): this
update(delta: number): this
pose(mesh: SkinnedMesh, vpd: object, params?: MMDAnimationHelperPoseParameter): this
enable(key: string, enabled: boolean): this
createGrantSolver(mesh: SkinnedMesh): GrantSolver
}
export interface AudioManagerParameter {
delayTime?: number | undefined
}
export class AudioManager {
constructor(audio: Audio, params?: AudioManagerParameter)
audio: Audio
elapsedTime: number
currentTime: number
delayTime: number
audioDuration: number
duration: number
control(delta: number): this
}
export class GrantSolver {
constructor(mesh: SkinnedMesh, grants: object[])
mesh: SkinnedMesh
grants: object[]
update(): this
updateOne(gran: object[]): this
addGrantRotation(bone: Bone, q: Quaternion, ratio: number): this
}
+689
View File
@@ -0,0 +1,689 @@
import { Object3D, Vector3, Quaternion, AnimationMixer } from "three";
import { CCDIKSolver } from "./CCDIKSolver.js";
import { MMDPhysics } from "./MMDPhysics.js";
class MMDAnimationHelper {
/**
* @param {Object} params - (optional)
* @param {boolean} params.sync - Whether animation durations of added objects are synched. Default is true.
* @param {Number} params.afterglow - Default is 0.0.
* @param {boolean} params.resetPhysicsOnLoop - Default is true.
*/
constructor(params = {}) {
this.meshes = [];
this.camera = null;
this.cameraTarget = new Object3D();
this.cameraTarget.name = "target";
this.audio = null;
this.audioManager = null;
this.objects = /* @__PURE__ */ new WeakMap();
this.configuration = {
sync: params.sync !== void 0 ? params.sync : true,
afterglow: params.afterglow !== void 0 ? params.afterglow : 0,
resetPhysicsOnLoop: params.resetPhysicsOnLoop !== void 0 ? params.resetPhysicsOnLoop : true,
pmxAnimation: params.pmxAnimation !== void 0 ? params.pmxAnimation : false
};
this.enabled = {
animation: true,
ik: true,
grant: true,
physics: true,
cameraAnimation: true
};
this.onBeforePhysics = function() {
};
this.sharedPhysics = false;
this.masterPhysics = null;
}
/**
* Adds an Three.js Object to helper and setups animation.
* The anmation durations of added objects are synched
* if this.configuration.sync is true.
*
* @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
* @param {Object} params - (optional)
* @param {THREE.AnimationClip|Array<THREE.AnimationClip>} params.animation - Only for THREE.SkinnedMesh and THREE.Camera. Default is undefined.
* @param {boolean} params.physics - Only for THREE.SkinnedMesh. Default is true.
* @param {Integer} params.warmup - Only for THREE.SkinnedMesh and physics is true. Default is 60.
* @param {Number} params.unitStep - Only for THREE.SkinnedMesh and physics is true. Default is 1 / 65.
* @param {Integer} params.maxStepNum - Only for THREE.SkinnedMesh and physics is true. Default is 3.
* @param {Vector3} params.gravity - Only for THREE.SkinnedMesh and physics is true. Default ( 0, - 9.8 * 10, 0 ).
* @param {Number} params.delayTime - Only for THREE.Audio. Default is 0.0.
* @return {MMDAnimationHelper}
*/
add(object, params = {}) {
if (object.isSkinnedMesh) {
this._addMesh(object, params);
} else if (object.isCamera) {
this._setupCamera(object, params);
} else if (object.type === "Audio") {
this._setupAudio(object, params);
} else {
throw new Error(
"THREE.MMDAnimationHelper.add: accepts only THREE.SkinnedMesh or THREE.Camera or THREE.Audio instance."
);
}
if (this.configuration.sync)
this._syncDuration();
return this;
}
/**
* Removes an Three.js Object from helper.
*
* @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object
* @return {MMDAnimationHelper}
*/
remove(object) {
if (object.isSkinnedMesh) {
this._removeMesh(object);
} else if (object.isCamera) {
this._clearCamera(object);
} else if (object.type === "Audio") {
this._clearAudio(object);
} else {
throw new Error(
"THREE.MMDAnimationHelper.remove: accepts only THREE.SkinnedMesh or THREE.Camera or THREE.Audio instance."
);
}
if (this.configuration.sync)
this._syncDuration();
return this;
}
/**
* Updates the animation.
*
* @param {Number} delta
* @return {MMDAnimationHelper}
*/
update(delta) {
if (this.audioManager !== null)
this.audioManager.control(delta);
for (let i = 0; i < this.meshes.length; i++) {
this._animateMesh(this.meshes[i], delta);
}
if (this.sharedPhysics)
this._updateSharedPhysics(delta);
if (this.camera !== null)
this._animateCamera(this.camera, delta);
return this;
}
/**
* Changes the pose of SkinnedMesh as VPD specifies.
*
* @param {THREE.SkinnedMesh} mesh
* @param {Object} vpd - VPD content parsed MMDParser
* @param {Object} params - (optional)
* @param {boolean} params.resetPose - Default is true.
* @param {boolean} params.ik - Default is true.
* @param {boolean} params.grant - Default is true.
* @return {MMDAnimationHelper}
*/
pose(mesh, vpd, params = {}) {
if (params.resetPose !== false)
mesh.pose();
const bones = mesh.skeleton.bones;
const boneParams = vpd.bones;
const boneNameDictionary = {};
for (let i = 0, il = bones.length; i < il; i++) {
boneNameDictionary[bones[i].name] = i;
}
const vector = new Vector3();
const quaternion = new Quaternion();
for (let i = 0, il = boneParams.length; i < il; i++) {
const boneParam = boneParams[i];
const boneIndex = boneNameDictionary[boneParam.name];
if (boneIndex === void 0)
continue;
const bone = bones[boneIndex];
bone.position.add(vector.fromArray(boneParam.translation));
bone.quaternion.multiply(quaternion.fromArray(boneParam.quaternion));
}
mesh.updateMatrixWorld(true);
if (this.configuration.pmxAnimation && mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === "pmx") {
const sortedBonesData = this._sortBoneDataArray(mesh.geometry.userData.MMD.bones.slice());
const ikSolver = params.ik !== false ? this._createCCDIKSolver(mesh) : null;
const grantSolver = params.grant !== false ? this.createGrantSolver(mesh) : null;
this._animatePMXMesh(mesh, sortedBonesData, ikSolver, grantSolver);
} else {
if (params.ik !== false) {
this._createCCDIKSolver(mesh).update();
}
if (params.grant !== false) {
this.createGrantSolver(mesh).update();
}
}
return this;
}
/**
* Enabes/Disables an animation feature.
*
* @param {string} key
* @param {boolean} enabled
* @return {MMDAnimationHelper}
*/
enable(key, enabled) {
if (this.enabled[key] === void 0) {
throw new Error("THREE.MMDAnimationHelper.enable: unknown key " + key);
}
this.enabled[key] = enabled;
if (key === "physics") {
for (let i = 0, il = this.meshes.length; i < il; i++) {
this._optimizeIK(this.meshes[i], enabled);
}
}
return this;
}
/**
* Creates an GrantSolver instance.
*
* @param {THREE.SkinnedMesh} mesh
* @return {GrantSolver}
*/
createGrantSolver(mesh) {
return new GrantSolver(mesh, mesh.geometry.userData.MMD.grants);
}
// private methods
_addMesh(mesh, params) {
if (this.meshes.indexOf(mesh) >= 0) {
throw new Error("THREE.MMDAnimationHelper._addMesh: SkinnedMesh '" + mesh.name + "' has already been added.");
}
this.meshes.push(mesh);
this.objects.set(mesh, { looped: false });
this._setupMeshAnimation(mesh, params.animation);
if (params.physics !== false) {
this._setupMeshPhysics(mesh, params);
}
return this;
}
_setupCamera(camera, params) {
if (this.camera === camera) {
throw new Error("THREE.MMDAnimationHelper._setupCamera: Camera '" + camera.name + "' has already been set.");
}
if (this.camera)
this.clearCamera(this.camera);
this.camera = camera;
camera.add(this.cameraTarget);
this.objects.set(camera, {});
if (params.animation !== void 0) {
this._setupCameraAnimation(camera, params.animation);
}
return this;
}
_setupAudio(audio, params) {
if (this.audio === audio) {
throw new Error("THREE.MMDAnimationHelper._setupAudio: Audio '" + audio.name + "' has already been set.");
}
if (this.audio)
this.clearAudio(this.audio);
this.audio = audio;
this.audioManager = new AudioManager(audio, params);
this.objects.set(this.audioManager, {
duration: this.audioManager.duration
});
return this;
}
_removeMesh(mesh) {
let found = false;
let writeIndex = 0;
for (let i = 0, il = this.meshes.length; i < il; i++) {
if (this.meshes[i] === mesh) {
this.objects.delete(mesh);
found = true;
continue;
}
this.meshes[writeIndex++] = this.meshes[i];
}
if (!found) {
throw new Error(
"THREE.MMDAnimationHelper._removeMesh: SkinnedMesh '" + mesh.name + "' has not been added yet."
);
}
this.meshes.length = writeIndex;
return this;
}
_clearCamera(camera) {
if (camera !== this.camera) {
throw new Error("THREE.MMDAnimationHelper._clearCamera: Camera '" + camera.name + "' has not been set yet.");
}
this.camera.remove(this.cameraTarget);
this.objects.delete(this.camera);
this.camera = null;
return this;
}
_clearAudio(audio) {
if (audio !== this.audio) {
throw new Error("THREE.MMDAnimationHelper._clearAudio: Audio '" + audio.name + "' has not been set yet.");
}
this.objects.delete(this.audioManager);
this.audio = null;
this.audioManager = null;
return this;
}
_setupMeshAnimation(mesh, animation) {
const objects = this.objects.get(mesh);
if (animation !== void 0) {
const animations = Array.isArray(animation) ? animation : [animation];
objects.mixer = new AnimationMixer(mesh);
for (let i = 0, il = animations.length; i < il; i++) {
objects.mixer.clipAction(animations[i]).play();
}
objects.mixer.addEventListener("loop", function(event) {
const tracks = event.action._clip.tracks;
if (tracks.length > 0 && tracks[0].name.slice(0, 6) !== ".bones")
return;
objects.looped = true;
});
}
objects.ikSolver = this._createCCDIKSolver(mesh);
objects.grantSolver = this.createGrantSolver(mesh);
return this;
}
_setupCameraAnimation(camera, animation) {
const animations = Array.isArray(animation) ? animation : [animation];
const objects = this.objects.get(camera);
objects.mixer = new AnimationMixer(camera);
for (let i = 0, il = animations.length; i < il; i++) {
objects.mixer.clipAction(animations[i]).play();
}
}
_setupMeshPhysics(mesh, params) {
const objects = this.objects.get(mesh);
if (params.world === void 0 && this.sharedPhysics) {
const masterPhysics = this._getMasterPhysics();
if (masterPhysics !== null)
world = masterPhysics.world;
}
objects.physics = this._createMMDPhysics(mesh, params);
if (objects.mixer && params.animationWarmup !== false) {
this._animateMesh(mesh, 0);
objects.physics.reset();
}
objects.physics.warmup(params.warmup !== void 0 ? params.warmup : 60);
this._optimizeIK(mesh, true);
}
_animateMesh(mesh, delta) {
const objects = this.objects.get(mesh);
const mixer = objects.mixer;
const ikSolver = objects.ikSolver;
const grantSolver = objects.grantSolver;
const physics = objects.physics;
const looped = objects.looped;
if (mixer && this.enabled.animation) {
this._restoreBones(mesh);
mixer.update(delta);
this._saveBones(mesh);
if (this.configuration.pmxAnimation && mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === "pmx") {
if (!objects.sortedBonesData)
objects.sortedBonesData = this._sortBoneDataArray(mesh.geometry.userData.MMD.bones.slice());
this._animatePMXMesh(
mesh,
objects.sortedBonesData,
ikSolver && this.enabled.ik ? ikSolver : null,
grantSolver && this.enabled.grant ? grantSolver : null
);
} else {
if (ikSolver && this.enabled.ik) {
mesh.updateMatrixWorld(true);
ikSolver.update();
}
if (grantSolver && this.enabled.grant) {
grantSolver.update();
}
}
}
if (looped === true && this.enabled.physics) {
if (physics && this.configuration.resetPhysicsOnLoop)
physics.reset();
objects.looped = false;
}
if (physics && this.enabled.physics && !this.sharedPhysics) {
this.onBeforePhysics(mesh);
physics.update(delta);
}
}
// Sort bones in order by 1. transformationClass and 2. bone index.
// In PMX animation system, bone transformations should be processed
// in this order.
_sortBoneDataArray(boneDataArray) {
return boneDataArray.sort(function(a, b) {
if (a.transformationClass !== b.transformationClass) {
return a.transformationClass - b.transformationClass;
} else {
return a.index - b.index;
}
});
}
// PMX Animation system is a bit too complex and doesn't great match to
// Three.js Animation system. This method attempts to simulate it as much as
// possible but doesn't perfectly simulate.
// This method is more costly than the regular one so
// you are recommended to set constructor parameter "pmxAnimation: true"
// only if your PMX model animation doesn't work well.
// If you need better method you would be required to write your own.
_animatePMXMesh(mesh, sortedBonesData, ikSolver, grantSolver) {
_quaternionIndex = 0;
_grantResultMap.clear();
for (let i = 0, il = sortedBonesData.length; i < il; i++) {
updateOne(mesh, sortedBonesData[i].index, ikSolver, grantSolver);
}
mesh.updateMatrixWorld(true);
return this;
}
_animateCamera(camera, delta) {
const mixer = this.objects.get(camera).mixer;
if (mixer && this.enabled.cameraAnimation) {
mixer.update(delta);
camera.updateProjectionMatrix();
camera.up.set(0, 1, 0);
camera.up.applyQuaternion(camera.quaternion);
camera.lookAt(this.cameraTarget.position);
}
}
_optimizeIK(mesh, physicsEnabled) {
const iks = mesh.geometry.userData.MMD.iks;
const bones = mesh.geometry.userData.MMD.bones;
for (let i = 0, il = iks.length; i < il; i++) {
const ik = iks[i];
const links = ik.links;
for (let j = 0, jl = links.length; j < jl; j++) {
const link = links[j];
if (physicsEnabled === true) {
link.enabled = bones[link.index].rigidBodyType > 0 ? false : true;
} else {
link.enabled = true;
}
}
}
}
_createCCDIKSolver(mesh) {
if (CCDIKSolver === void 0) {
throw new Error("THREE.MMDAnimationHelper: Import CCDIKSolver.");
}
return new CCDIKSolver(mesh, mesh.geometry.userData.MMD.iks);
}
_createMMDPhysics(mesh, params) {
if (MMDPhysics === void 0) {
throw new Error("THREE.MMDPhysics: Import MMDPhysics.");
}
return new MMDPhysics(mesh, mesh.geometry.userData.MMD.rigidBodies, mesh.geometry.userData.MMD.constraints, params);
}
/*
* Detects the longest duration and then sets it to them to sync.
* TODO: Not to access private properties ( ._actions and ._clip )
*/
_syncDuration() {
let max = 0;
const objects = this.objects;
const meshes = this.meshes;
const camera = this.camera;
const audioManager = this.audioManager;
for (let i = 0, il = meshes.length; i < il; i++) {
const mixer = this.objects.get(meshes[i]).mixer;
if (mixer === void 0)
continue;
for (let j = 0; j < mixer._actions.length; j++) {
const clip = mixer._actions[j]._clip;
if (!objects.has(clip)) {
objects.set(clip, {
duration: clip.duration
});
}
max = Math.max(max, objects.get(clip).duration);
}
}
if (camera !== null) {
const mixer = this.objects.get(camera).mixer;
if (mixer !== void 0) {
for (let i = 0, il = mixer._actions.length; i < il; i++) {
const clip = mixer._actions[i]._clip;
if (!objects.has(clip)) {
objects.set(clip, {
duration: clip.duration
});
}
max = Math.max(max, objects.get(clip).duration);
}
}
}
if (audioManager !== null) {
max = Math.max(max, objects.get(audioManager).duration);
}
max += this.configuration.afterglow;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const mixer = this.objects.get(this.meshes[i]).mixer;
if (mixer === void 0)
continue;
for (let j = 0, jl = mixer._actions.length; j < jl; j++) {
mixer._actions[j]._clip.duration = max;
}
}
if (camera !== null) {
const mixer = this.objects.get(camera).mixer;
if (mixer !== void 0) {
for (let i = 0, il = mixer._actions.length; i < il; i++) {
mixer._actions[i]._clip.duration = max;
}
}
}
if (audioManager !== null) {
audioManager.duration = max;
}
}
// workaround
_updatePropertyMixersBuffer(mesh) {
const mixer = this.objects.get(mesh).mixer;
const propertyMixers = mixer._bindings;
const accuIndex = mixer._accuIndex;
for (let i = 0, il = propertyMixers.length; i < il; i++) {
const propertyMixer = propertyMixers[i];
const buffer = propertyMixer.buffer;
const stride = propertyMixer.valueSize;
const offset = (accuIndex + 1) * stride;
propertyMixer.binding.getValue(buffer, offset);
}
}
/*
* Avoiding these two issues by restore/save bones before/after mixer animation.
*
* 1. PropertyMixer used by AnimationMixer holds cache value in .buffer.
* Calculating IK, Grant, and Physics after mixer animation can break
* the cache coherency.
*
* 2. Applying Grant two or more times without reset the posing breaks model.
*/
_saveBones(mesh) {
const objects = this.objects.get(mesh);
const bones = mesh.skeleton.bones;
let backupBones = objects.backupBones;
if (backupBones === void 0) {
backupBones = new Float32Array(bones.length * 7);
objects.backupBones = backupBones;
}
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
bone.position.toArray(backupBones, i * 7);
bone.quaternion.toArray(backupBones, i * 7 + 3);
}
}
_restoreBones(mesh) {
const objects = this.objects.get(mesh);
const backupBones = objects.backupBones;
if (backupBones === void 0)
return;
const bones = mesh.skeleton.bones;
for (let i = 0, il = bones.length; i < il; i++) {
const bone = bones[i];
bone.position.fromArray(backupBones, i * 7);
bone.quaternion.fromArray(backupBones, i * 7 + 3);
}
}
// experimental
_getMasterPhysics() {
if (this.masterPhysics !== null)
return this.masterPhysics;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const physics = this.meshes[i].physics;
if (physics !== void 0 && physics !== null) {
this.masterPhysics = physics;
return this.masterPhysics;
}
}
return null;
}
_updateSharedPhysics(delta) {
if (this.meshes.length === 0 || !this.enabled.physics || !this.sharedPhysics)
return;
const physics = this._getMasterPhysics();
if (physics === null)
return;
for (let i = 0, il = this.meshes.length; i < il; i++) {
const p = this.meshes[i].physics;
if (p !== null && p !== void 0) {
p.updateRigidBodies();
}
}
physics.stepSimulation(delta);
for (let i = 0, il = this.meshes.length; i < il; i++) {
const p = this.meshes[i].physics;
if (p !== null && p !== void 0) {
p.updateBones();
}
}
}
}
const _quaternions = [];
let _quaternionIndex = 0;
function getQuaternion() {
if (_quaternionIndex >= _quaternions.length) {
_quaternions.push(new Quaternion());
}
return _quaternions[_quaternionIndex++];
}
const _grantResultMap = /* @__PURE__ */ new Map();
function updateOne(mesh, boneIndex, ikSolver, grantSolver) {
const bones = mesh.skeleton.bones;
const bonesData = mesh.geometry.userData.MMD.bones;
const boneData = bonesData[boneIndex];
const bone = bones[boneIndex];
if (_grantResultMap.has(boneIndex))
return;
const quaternion = getQuaternion();
_grantResultMap.set(boneIndex, quaternion.copy(bone.quaternion));
if (grantSolver && boneData.grant && !boneData.grant.isLocal && boneData.grant.affectRotation) {
const parentIndex = boneData.grant.parentIndex;
const ratio = boneData.grant.ratio;
if (!_grantResultMap.has(parentIndex)) {
updateOne(mesh, parentIndex, ikSolver, grantSolver);
}
grantSolver.addGrantRotation(bone, _grantResultMap.get(parentIndex), ratio);
}
if (ikSolver && boneData.ik) {
mesh.updateMatrixWorld(true);
ikSolver.updateOne(boneData.ik);
const links = boneData.ik.links;
for (let i = 0, il = links.length; i < il; i++) {
const link = links[i];
if (link.enabled === false)
continue;
const linkIndex = link.index;
if (_grantResultMap.has(linkIndex)) {
_grantResultMap.set(linkIndex, _grantResultMap.get(linkIndex).copy(bones[linkIndex].quaternion));
}
}
}
quaternion.copy(bone.quaternion);
}
class AudioManager {
/**
* @param {THREE.Audio} audio
* @param {Object} params - (optional)
* @param {Nuumber} params.delayTime
*/
constructor(audio, params = {}) {
this.audio = audio;
this.elapsedTime = 0;
this.currentTime = 0;
this.delayTime = params.delayTime !== void 0 ? params.delayTime : 0;
this.audioDuration = this.audio.buffer.duration;
this.duration = this.audioDuration + this.delayTime;
}
/**
* @param {Number} delta
* @return {AudioManager}
*/
control(delta) {
this.elapsed += delta;
this.currentTime += delta;
if (this._shouldStopAudio())
this.audio.stop();
if (this._shouldStartAudio())
this.audio.play();
return this;
}
// private methods
_shouldStartAudio() {
if (this.audio.isPlaying)
return false;
while (this.currentTime >= this.duration) {
this.currentTime -= this.duration;
}
if (this.currentTime < this.delayTime)
return false;
if (this.currentTime - this.delayTime > this.audioDuration)
return false;
return true;
}
_shouldStopAudio() {
return this.audio.isPlaying && this.currentTime >= this.duration;
}
}
const _q = /* @__PURE__ */ new Quaternion();
class GrantSolver {
constructor(mesh, grants = []) {
this.mesh = mesh;
this.grants = grants;
}
/**
* Solve all the grant bones
* @return {GrantSolver}
*/
update() {
const grants = this.grants;
for (let i = 0, il = grants.length; i < il; i++) {
this.updateOne(grants[i]);
}
return this;
}
/**
* Solve a grant bone
* @param {Object} grant - grant parameter
* @return {GrantSolver}
*/
updateOne(grant) {
const bones = this.mesh.skeleton.bones;
const bone = bones[grant.index];
const parentBone = bones[grant.parentIndex];
if (grant.isLocal) {
if (grant.affectPosition)
;
if (grant.affectRotation)
;
} else {
if (grant.affectPosition)
;
if (grant.affectRotation) {
this.addGrantRotation(bone, parentBone.quaternion, grant.ratio);
}
}
return this;
}
addGrantRotation(bone, q, ratio) {
_q.set(0, 0, 0, 1);
_q.slerp(q, ratio);
bone.quaternion.multiply(_q);
return this;
}
}
export {
MMDAnimationHelper
};
//# sourceMappingURL=MMDAnimationHelper.js.map
File diff suppressed because one or more lines are too long
+831
View File
@@ -0,0 +1,831 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const CapsuleGeometry = require("../_polyfill/CapsuleGeometry.cjs");
class MMDPhysics {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Array<Object>} rigidBodyParams
* @param {Array<Object>} (optional) constraintParams
* @param {Object} params - (optional)
* @param {Number} params.unitStep - Default is 1 / 65.
* @param {Integer} params.maxStepNum - Default is 3.
* @param {Vector3} params.gravity - Default is ( 0, - 9.8 * 10, 0 )
*/
constructor(mesh, rigidBodyParams, constraintParams = [], params = {}) {
if (typeof Ammo === "undefined") {
throw new Error("THREE.MMDPhysics: Import ammo.js https://github.com/kripken/ammo.js");
}
this.manager = new ResourceManager();
this.mesh = mesh;
this.unitStep = params.unitStep !== void 0 ? params.unitStep : 1 / 65;
this.maxStepNum = params.maxStepNum !== void 0 ? params.maxStepNum : 3;
this.gravity = new THREE.Vector3(0, -9.8 * 10, 0);
if (params.gravity !== void 0)
this.gravity.copy(params.gravity);
this.world = params.world !== void 0 ? params.world : null;
this.bodies = [];
this.constraints = [];
this._init(mesh, rigidBodyParams, constraintParams);
}
/**
* Advances Physics calculation and updates bones.
*
* @param {Number} delta - time in second
* @return {MMDPhysics}
*/
update(delta) {
const manager = this.manager;
const mesh = this.mesh;
let isNonDefaultScale = false;
const position = manager.allocThreeVector3();
const quaternion = manager.allocThreeQuaternion();
const scale = manager.allocThreeVector3();
mesh.matrixWorld.decompose(position, quaternion, scale);
if (scale.x !== 1 || scale.y !== 1 || scale.z !== 1) {
isNonDefaultScale = true;
}
let parent;
if (isNonDefaultScale) {
parent = mesh.parent;
if (parent !== null)
mesh.parent = null;
scale.copy(this.mesh.scale);
mesh.scale.set(1, 1, 1);
mesh.updateMatrixWorld(true);
}
this._updateRigidBodies();
this._stepSimulation(delta);
this._updateBones();
if (isNonDefaultScale) {
if (parent !== null)
mesh.parent = parent;
mesh.scale.copy(scale);
}
manager.freeThreeVector3(scale);
manager.freeThreeQuaternion(quaternion);
manager.freeThreeVector3(position);
return this;
}
/**
* Resets rigid bodies transorm to current bone's.
*
* @return {MMDPhysics}
*/
reset() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].reset();
}
return this;
}
/**
* Warm ups Rigid bodies. Calculates cycles steps.
*
* @param {Integer} cycles
* @return {MMDPhysics}
*/
warmup(cycles) {
for (let i = 0; i < cycles; i++) {
this.update(1 / 60);
}
return this;
}
/**
* Sets gravity.
*
* @param {Vector3} gravity
* @return {MMDPhysicsHelper}
*/
setGravity(gravity) {
this.world.setGravity(new Ammo.btVector3(gravity.x, gravity.y, gravity.z));
this.gravity.copy(gravity);
return this;
}
/**
* Creates MMDPhysicsHelper
*
* @return {MMDPhysicsHelper}
*/
createHelper() {
return new MMDPhysicsHelper(this.mesh, this);
}
// private methods
_init(mesh, rigidBodyParams, constraintParams) {
const manager = this.manager;
const parent = mesh.parent;
if (parent !== null)
mesh.parent = null;
const currentPosition = manager.allocThreeVector3();
const currentQuaternion = manager.allocThreeQuaternion();
const currentScale = manager.allocThreeVector3();
currentPosition.copy(mesh.position);
currentQuaternion.copy(mesh.quaternion);
currentScale.copy(mesh.scale);
mesh.position.set(0, 0, 0);
mesh.quaternion.set(0, 0, 0, 1);
mesh.scale.set(1, 1, 1);
mesh.updateMatrixWorld(true);
if (this.world === null) {
this.world = this._createWorld();
this.setGravity(this.gravity);
}
this._initRigidBodies(rigidBodyParams);
this._initConstraints(constraintParams);
if (parent !== null)
mesh.parent = parent;
mesh.position.copy(currentPosition);
mesh.quaternion.copy(currentQuaternion);
mesh.scale.copy(currentScale);
mesh.updateMatrixWorld(true);
this.reset();
manager.freeThreeVector3(currentPosition);
manager.freeThreeQuaternion(currentQuaternion);
manager.freeThreeVector3(currentScale);
}
_createWorld() {
const config = new Ammo.btDefaultCollisionConfiguration();
const dispatcher = new Ammo.btCollisionDispatcher(config);
const cache = new Ammo.btDbvtBroadphase();
const solver = new Ammo.btSequentialImpulseConstraintSolver();
const world = new Ammo.btDiscreteDynamicsWorld(dispatcher, cache, solver, config);
return world;
}
_initRigidBodies(rigidBodies) {
for (let i = 0, il = rigidBodies.length; i < il; i++) {
this.bodies.push(new RigidBody(this.mesh, this.world, rigidBodies[i], this.manager));
}
}
_initConstraints(constraints) {
for (let i = 0, il = constraints.length; i < il; i++) {
const params = constraints[i];
const bodyA = this.bodies[params.rigidBodyIndex1];
const bodyB = this.bodies[params.rigidBodyIndex2];
this.constraints.push(new Constraint(this.mesh, this.world, bodyA, bodyB, params, this.manager));
}
}
_stepSimulation(delta) {
const unitStep = this.unitStep;
let stepTime = delta;
let maxStepNum = (delta / unitStep | 0) + 1;
if (stepTime < unitStep) {
stepTime = unitStep;
maxStepNum = 1;
}
if (maxStepNum > this.maxStepNum) {
maxStepNum = this.maxStepNum;
}
this.world.stepSimulation(stepTime, maxStepNum, unitStep);
}
_updateRigidBodies() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].updateFromBone();
}
}
_updateBones() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].updateBone();
}
}
}
class ResourceManager {
constructor() {
this.threeVector3s = [];
this.threeMatrix4s = [];
this.threeQuaternions = [];
this.threeEulers = [];
this.transforms = [];
this.quaternions = [];
this.vector3s = [];
}
allocThreeVector3() {
return this.threeVector3s.length > 0 ? this.threeVector3s.pop() : new THREE.Vector3();
}
freeThreeVector3(v) {
this.threeVector3s.push(v);
}
allocThreeMatrix4() {
return this.threeMatrix4s.length > 0 ? this.threeMatrix4s.pop() : new THREE.Matrix4();
}
freeThreeMatrix4(m) {
this.threeMatrix4s.push(m);
}
allocThreeQuaternion() {
return this.threeQuaternions.length > 0 ? this.threeQuaternions.pop() : new THREE.Quaternion();
}
freeThreeQuaternion(q) {
this.threeQuaternions.push(q);
}
allocThreeEuler() {
return this.threeEulers.length > 0 ? this.threeEulers.pop() : new THREE.Euler();
}
freeThreeEuler(e) {
this.threeEulers.push(e);
}
allocTransform() {
return this.transforms.length > 0 ? this.transforms.pop() : new Ammo.btTransform();
}
freeTransform(t) {
this.transforms.push(t);
}
allocQuaternion() {
return this.quaternions.length > 0 ? this.quaternions.pop() : new Ammo.btQuaternion();
}
freeQuaternion(q) {
this.quaternions.push(q);
}
allocVector3() {
return this.vector3s.length > 0 ? this.vector3s.pop() : new Ammo.btVector3();
}
freeVector3(v) {
this.vector3s.push(v);
}
setIdentity(t) {
t.setIdentity();
}
getBasis(t) {
var q = this.allocQuaternion();
t.getBasis().getRotation(q);
return q;
}
getBasisAsMatrix3(t) {
var q = this.getBasis(t);
var m = this.quaternionToMatrix3(q);
this.freeQuaternion(q);
return m;
}
getOrigin(t) {
return t.getOrigin();
}
setOrigin(t, v) {
t.getOrigin().setValue(v.x(), v.y(), v.z());
}
copyOrigin(t1, t2) {
var o = t2.getOrigin();
this.setOrigin(t1, o);
}
setBasis(t, q) {
t.setRotation(q);
}
setBasisFromMatrix3(t, m) {
var q = this.matrix3ToQuaternion(m);
this.setBasis(t, q);
this.freeQuaternion(q);
}
setOriginFromArray3(t, a) {
t.getOrigin().setValue(a[0], a[1], a[2]);
}
setOriginFromThreeVector3(t, v) {
t.getOrigin().setValue(v.x, v.y, v.z);
}
setBasisFromArray3(t, a) {
var thQ = this.allocThreeQuaternion();
var thE = this.allocThreeEuler();
thE.set(a[0], a[1], a[2]);
this.setBasisFromThreeQuaternion(t, thQ.setFromEuler(thE));
this.freeThreeEuler(thE);
this.freeThreeQuaternion(thQ);
}
setBasisFromThreeQuaternion(t, a) {
var q = this.allocQuaternion();
q.setX(a.x);
q.setY(a.y);
q.setZ(a.z);
q.setW(a.w);
this.setBasis(t, q);
this.freeQuaternion(q);
}
multiplyTransforms(t1, t2) {
var t = this.allocTransform();
this.setIdentity(t);
var m1 = this.getBasisAsMatrix3(t1);
var m2 = this.getBasisAsMatrix3(t2);
var o1 = this.getOrigin(t1);
var o2 = this.getOrigin(t2);
var v1 = this.multiplyMatrix3ByVector3(m1, o2);
var v2 = this.addVector3(v1, o1);
this.setOrigin(t, v2);
var m3 = this.multiplyMatrices3(m1, m2);
this.setBasisFromMatrix3(t, m3);
this.freeVector3(v1);
this.freeVector3(v2);
return t;
}
inverseTransform(t) {
var t2 = this.allocTransform();
var m1 = this.getBasisAsMatrix3(t);
var o = this.getOrigin(t);
var m2 = this.transposeMatrix3(m1);
var v1 = this.negativeVector3(o);
var v2 = this.multiplyMatrix3ByVector3(m2, v1);
this.setOrigin(t2, v2);
this.setBasisFromMatrix3(t2, m2);
this.freeVector3(v1);
this.freeVector3(v2);
return t2;
}
multiplyMatrices3(m1, m2) {
var m3 = [];
var v10 = this.rowOfMatrix3(m1, 0);
var v11 = this.rowOfMatrix3(m1, 1);
var v12 = this.rowOfMatrix3(m1, 2);
var v20 = this.columnOfMatrix3(m2, 0);
var v21 = this.columnOfMatrix3(m2, 1);
var v22 = this.columnOfMatrix3(m2, 2);
m3[0] = this.dotVectors3(v10, v20);
m3[1] = this.dotVectors3(v10, v21);
m3[2] = this.dotVectors3(v10, v22);
m3[3] = this.dotVectors3(v11, v20);
m3[4] = this.dotVectors3(v11, v21);
m3[5] = this.dotVectors3(v11, v22);
m3[6] = this.dotVectors3(v12, v20);
m3[7] = this.dotVectors3(v12, v21);
m3[8] = this.dotVectors3(v12, v22);
this.freeVector3(v10);
this.freeVector3(v11);
this.freeVector3(v12);
this.freeVector3(v20);
this.freeVector3(v21);
this.freeVector3(v22);
return m3;
}
addVector3(v1, v2) {
var v = this.allocVector3();
v.setValue(v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z());
return v;
}
dotVectors3(v1, v2) {
return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
}
rowOfMatrix3(m, i) {
var v = this.allocVector3();
v.setValue(m[i * 3 + 0], m[i * 3 + 1], m[i * 3 + 2]);
return v;
}
columnOfMatrix3(m, i) {
var v = this.allocVector3();
v.setValue(m[i + 0], m[i + 3], m[i + 6]);
return v;
}
negativeVector3(v) {
var v2 = this.allocVector3();
v2.setValue(-v.x(), -v.y(), -v.z());
return v2;
}
multiplyMatrix3ByVector3(m, v) {
var v4 = this.allocVector3();
var v0 = this.rowOfMatrix3(m, 0);
var v1 = this.rowOfMatrix3(m, 1);
var v2 = this.rowOfMatrix3(m, 2);
var x = this.dotVectors3(v0, v);
var y = this.dotVectors3(v1, v);
var z = this.dotVectors3(v2, v);
v4.setValue(x, y, z);
this.freeVector3(v0);
this.freeVector3(v1);
this.freeVector3(v2);
return v4;
}
transposeMatrix3(m) {
var m2 = [];
m2[0] = m[0];
m2[1] = m[3];
m2[2] = m[6];
m2[3] = m[1];
m2[4] = m[4];
m2[5] = m[7];
m2[6] = m[2];
m2[7] = m[5];
m2[8] = m[8];
return m2;
}
quaternionToMatrix3(q) {
var m = [];
var x = q.x();
var y = q.y();
var z = q.z();
var w = q.w();
var xx = x * x;
var yy = y * y;
var zz = z * z;
var xy = x * y;
var yz = y * z;
var zx = z * x;
var xw = x * w;
var yw = y * w;
var zw = z * w;
m[0] = 1 - 2 * (yy + zz);
m[1] = 2 * (xy - zw);
m[2] = 2 * (zx + yw);
m[3] = 2 * (xy + zw);
m[4] = 1 - 2 * (zz + xx);
m[5] = 2 * (yz - xw);
m[6] = 2 * (zx - yw);
m[7] = 2 * (yz + xw);
m[8] = 1 - 2 * (xx + yy);
return m;
}
matrix3ToQuaternion(m) {
var t = m[0] + m[4] + m[8];
var s, x, y, z, w;
if (t > 0) {
s = Math.sqrt(t + 1) * 2;
w = 0.25 * s;
x = (m[7] - m[5]) / s;
y = (m[2] - m[6]) / s;
z = (m[3] - m[1]) / s;
} else if (m[0] > m[4] && m[0] > m[8]) {
s = Math.sqrt(1 + m[0] - m[4] - m[8]) * 2;
w = (m[7] - m[5]) / s;
x = 0.25 * s;
y = (m[1] + m[3]) / s;
z = (m[2] + m[6]) / s;
} else if (m[4] > m[8]) {
s = Math.sqrt(1 + m[4] - m[0] - m[8]) * 2;
w = (m[2] - m[6]) / s;
x = (m[1] + m[3]) / s;
y = 0.25 * s;
z = (m[5] + m[7]) / s;
} else {
s = Math.sqrt(1 + m[8] - m[0] - m[4]) * 2;
w = (m[3] - m[1]) / s;
x = (m[2] + m[6]) / s;
y = (m[5] + m[7]) / s;
z = 0.25 * s;
}
var q = this.allocQuaternion();
q.setX(x);
q.setY(y);
q.setZ(z);
q.setW(w);
return q;
}
}
class RigidBody {
constructor(mesh, world, params, manager) {
this.mesh = mesh;
this.world = world;
this.params = params;
this.manager = manager;
this.body = null;
this.bone = null;
this.boneOffsetForm = null;
this.boneOffsetFormInverse = null;
this._init();
}
/**
* Resets rigid body transform to the current bone's.
*
* @return {RigidBody}
*/
reset() {
this._setTransformFromBone();
return this;
}
/**
* Updates rigid body's transform from the current bone.
*
* @return {RidigBody}
*/
updateFromBone() {
if (this.params.boneIndex !== -1 && this.params.type === 0) {
this._setTransformFromBone();
}
return this;
}
/**
* Updates bone from the current ridid body's transform.
*
* @return {RidigBody}
*/
updateBone() {
if (this.params.type === 0 || this.params.boneIndex === -1) {
return this;
}
this._updateBoneRotation();
if (this.params.type === 1) {
this._updateBonePosition();
}
this.bone.updateMatrixWorld(true);
if (this.params.type === 2) {
this._setPositionFromBone();
}
return this;
}
// private methods
_init() {
function generateShape(p) {
switch (p.shapeType) {
case 0:
return new Ammo.btSphereShape(p.width);
case 1:
return new Ammo.btBoxShape(new Ammo.btVector3(p.width, p.height, p.depth));
case 2:
return new Ammo.btCapsuleShape(p.width, p.height);
default:
throw new Error("unknown shape type " + p.shapeType);
}
}
const manager = this.manager;
const params = this.params;
const bones = this.mesh.skeleton.bones;
const bone = params.boneIndex === -1 ? new THREE.Bone() : bones[params.boneIndex];
const shape = generateShape(params);
const weight = params.type === 0 ? 0 : params.weight;
const localInertia = manager.allocVector3();
localInertia.setValue(0, 0, 0);
if (weight !== 0) {
shape.calculateLocalInertia(weight, localInertia);
}
const boneOffsetForm = manager.allocTransform();
manager.setIdentity(boneOffsetForm);
manager.setOriginFromArray3(boneOffsetForm, params.position);
manager.setBasisFromArray3(boneOffsetForm, params.rotation);
const vector = manager.allocThreeVector3();
const boneForm = manager.allocTransform();
manager.setIdentity(boneForm);
manager.setOriginFromThreeVector3(boneForm, bone.getWorldPosition(vector));
const form = manager.multiplyTransforms(boneForm, boneOffsetForm);
const state = new Ammo.btDefaultMotionState(form);
const info = new Ammo.btRigidBodyConstructionInfo(weight, state, shape, localInertia);
info.set_m_friction(params.friction);
info.set_m_restitution(params.restitution);
const body = new Ammo.btRigidBody(info);
if (params.type === 0) {
body.setCollisionFlags(body.getCollisionFlags() | 2);
body.setActivationState(4);
}
body.setDamping(params.positionDamping, params.rotationDamping);
body.setSleepingThresholds(0, 0);
this.world.addRigidBody(body, 1 << params.groupIndex, params.groupTarget);
this.body = body;
this.bone = bone;
this.boneOffsetForm = boneOffsetForm;
this.boneOffsetFormInverse = manager.inverseTransform(boneOffsetForm);
manager.freeVector3(localInertia);
manager.freeTransform(form);
manager.freeTransform(boneForm);
manager.freeThreeVector3(vector);
}
_getBoneTransform() {
const manager = this.manager;
const p = manager.allocThreeVector3();
const q = manager.allocThreeQuaternion();
const s = manager.allocThreeVector3();
this.bone.matrixWorld.decompose(p, q, s);
const tr = manager.allocTransform();
manager.setOriginFromThreeVector3(tr, p);
manager.setBasisFromThreeQuaternion(tr, q);
const form = manager.multiplyTransforms(tr, this.boneOffsetForm);
manager.freeTransform(tr);
manager.freeThreeVector3(s);
manager.freeThreeQuaternion(q);
manager.freeThreeVector3(p);
return form;
}
_getWorldTransformForBone() {
const manager = this.manager;
const tr = this.body.getCenterOfMassTransform();
return manager.multiplyTransforms(tr, this.boneOffsetFormInverse);
}
_setTransformFromBone() {
const manager = this.manager;
const form = this._getBoneTransform();
this.body.setCenterOfMassTransform(form);
this.body.getMotionState().setWorldTransform(form);
manager.freeTransform(form);
}
_setPositionFromBone() {
const manager = this.manager;
const form = this._getBoneTransform();
const tr = manager.allocTransform();
this.body.getMotionState().getWorldTransform(tr);
manager.copyOrigin(tr, form);
this.body.setCenterOfMassTransform(tr);
this.body.getMotionState().setWorldTransform(tr);
manager.freeTransform(tr);
manager.freeTransform(form);
}
_updateBoneRotation() {
const manager = this.manager;
const tr = this._getWorldTransformForBone();
const q = manager.getBasis(tr);
const thQ = manager.allocThreeQuaternion();
const thQ2 = manager.allocThreeQuaternion();
const thQ3 = manager.allocThreeQuaternion();
thQ.set(q.x(), q.y(), q.z(), q.w());
thQ2.setFromRotationMatrix(this.bone.matrixWorld);
thQ2.conjugate();
thQ2.multiply(thQ);
thQ3.setFromRotationMatrix(this.bone.matrix);
this.bone.quaternion.copy(thQ2.multiply(thQ3).normalize());
manager.freeThreeQuaternion(thQ);
manager.freeThreeQuaternion(thQ2);
manager.freeThreeQuaternion(thQ3);
manager.freeQuaternion(q);
manager.freeTransform(tr);
}
_updateBonePosition() {
const manager = this.manager;
const tr = this._getWorldTransformForBone();
const thV = manager.allocThreeVector3();
const o = manager.getOrigin(tr);
thV.set(o.x(), o.y(), o.z());
if (this.bone.parent) {
this.bone.parent.worldToLocal(thV);
}
this.bone.position.copy(thV);
manager.freeThreeVector3(thV);
manager.freeTransform(tr);
}
}
class Constraint {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Ammo.btDiscreteDynamicsWorld} world
* @param {RigidBody} bodyA
* @param {RigidBody} bodyB
* @param {Object} params
* @param {ResourceManager} manager
*/
constructor(mesh, world, bodyA, bodyB, params, manager) {
this.mesh = mesh;
this.world = world;
this.bodyA = bodyA;
this.bodyB = bodyB;
this.params = params;
this.manager = manager;
this.constraint = null;
this._init();
}
// private method
_init() {
const manager = this.manager;
const params = this.params;
const bodyA = this.bodyA;
const bodyB = this.bodyB;
const form = manager.allocTransform();
manager.setIdentity(form);
manager.setOriginFromArray3(form, params.position);
manager.setBasisFromArray3(form, params.rotation);
const formA = manager.allocTransform();
const formB = manager.allocTransform();
bodyA.body.getMotionState().getWorldTransform(formA);
bodyB.body.getMotionState().getWorldTransform(formB);
const formInverseA = manager.inverseTransform(formA);
const formInverseB = manager.inverseTransform(formB);
const formA2 = manager.multiplyTransforms(formInverseA, form);
const formB2 = manager.multiplyTransforms(formInverseB, form);
const constraint = new Ammo.btGeneric6DofSpringConstraint(bodyA.body, bodyB.body, formA2, formB2, true);
const lll = manager.allocVector3();
const lul = manager.allocVector3();
const all = manager.allocVector3();
const aul = manager.allocVector3();
lll.setValue(params.translationLimitation1[0], params.translationLimitation1[1], params.translationLimitation1[2]);
lul.setValue(params.translationLimitation2[0], params.translationLimitation2[1], params.translationLimitation2[2]);
all.setValue(params.rotationLimitation1[0], params.rotationLimitation1[1], params.rotationLimitation1[2]);
aul.setValue(params.rotationLimitation2[0], params.rotationLimitation2[1], params.rotationLimitation2[2]);
constraint.setLinearLowerLimit(lll);
constraint.setLinearUpperLimit(lul);
constraint.setAngularLowerLimit(all);
constraint.setAngularUpperLimit(aul);
for (let i = 0; i < 3; i++) {
if (params.springPosition[i] !== 0) {
constraint.enableSpring(i, true);
constraint.setStiffness(i, params.springPosition[i]);
}
}
for (let i = 0; i < 3; i++) {
if (params.springRotation[i] !== 0) {
constraint.enableSpring(i + 3, true);
constraint.setStiffness(i + 3, params.springRotation[i]);
}
}
if (constraint.setParam !== void 0) {
for (let i = 0; i < 6; i++) {
constraint.setParam(2, 0.475, i);
}
}
this.world.addConstraint(constraint, true);
this.constraint = constraint;
manager.freeTransform(form);
manager.freeTransform(formA);
manager.freeTransform(formB);
manager.freeTransform(formInverseA);
manager.freeTransform(formInverseB);
manager.freeTransform(formA2);
manager.freeTransform(formB2);
manager.freeVector3(lll);
manager.freeVector3(lul);
manager.freeVector3(all);
manager.freeVector3(aul);
}
}
const _position = /* @__PURE__ */ new THREE.Vector3();
const _quaternion = /* @__PURE__ */ new THREE.Quaternion();
const _scale = /* @__PURE__ */ new THREE.Vector3();
const _matrixWorldInv = /* @__PURE__ */ new THREE.Matrix4();
class MMDPhysicsHelper extends THREE.Object3D {
/**
* Visualize Rigid bodies
*
* @param {THREE.SkinnedMesh} mesh
* @param {Physics} physics
*/
constructor(mesh, physics) {
super();
this.root = mesh;
this.physics = physics;
this.matrix.copy(mesh.matrixWorld);
this.matrixAutoUpdate = false;
this.materials = [];
this.materials.push(
new THREE.MeshBasicMaterial({
color: new THREE.Color(16746632),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this.materials.push(
new THREE.MeshBasicMaterial({
color: new THREE.Color(8978312),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this.materials.push(
new THREE.MeshBasicMaterial({
color: new THREE.Color(8947967),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this._init();
}
/**
* Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.
*/
dispose() {
const materials = this.materials;
const children = this.children;
for (let i = 0; i < materials.length; i++) {
materials[i].dispose();
}
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.isMesh)
child.geometry.dispose();
}
}
/**
* Updates Rigid Bodies visualization.
*/
updateMatrixWorld(force) {
var mesh = this.root;
if (this.visible) {
var bodies = this.physics.bodies;
_matrixWorldInv.copy(mesh.matrixWorld).decompose(_position, _quaternion, _scale).compose(_position, _quaternion, _scale.set(1, 1, 1)).invert();
for (var i = 0, il = bodies.length; i < il; i++) {
var body = bodies[i].body;
var child = this.children[i];
var tr = body.getCenterOfMassTransform();
var origin = tr.getOrigin();
var rotation = tr.getRotation();
child.position.set(origin.x(), origin.y(), origin.z()).applyMatrix4(_matrixWorldInv);
child.quaternion.setFromRotationMatrix(_matrixWorldInv).multiply(_quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w()));
}
}
this.matrix.copy(mesh.matrixWorld).decompose(_position, _quaternion, _scale).compose(_position, _quaternion, _scale.set(1, 1, 1));
super.updateMatrixWorld(force);
}
// private method
_init() {
var bodies = this.physics.bodies;
function createGeometry(param2) {
switch (param2.shapeType) {
case 0:
return new THREE.SphereGeometry(param2.width, 16, 8);
case 1:
return new THREE.BoxGeometry(param2.width * 2, param2.height * 2, param2.depth * 2, 8, 8, 8);
case 2:
return new CapsuleGeometry.CapsuleGeometry(param2.width, param2.height, 8, 16);
default:
return null;
}
}
for (var i = 0, il = bodies.length; i < il; i++) {
var param = bodies[i].params;
this.add(new THREE.Mesh(createGeometry(param), this.materials[param.type]));
}
}
}
exports.MMDPhysics = MMDPhysics;
//# sourceMappingURL=MMDPhysics.cjs.map
File diff suppressed because one or more lines are too long
+119
View File
@@ -0,0 +1,119 @@
import { Bone, Euler, Matrix4, MeshBasicMaterial, Object3D, Quaternion, SkinnedMesh, Vector3 } from 'three'
export interface MMDPhysicsParameter {
unitStep?: number | undefined
maxStepNum?: number | undefined
gravity?: Vector3 | undefined
}
export class MMDPhysics {
constructor(mesh: SkinnedMesh, rigidBodyParams: object[], constraintParams?: object[], params?: MMDPhysicsParameter)
manager: ResourceManager
mesh: SkinnedMesh
unitStep: number
maxStepNum: number
gravity: Vector3
world: null
bodies: RigidBody[]
constraints: Constraint[]
update(delta: number): this
reset(): this
warmup(cycles: number): this
setGravity(gravity: Vector3): this
createHelper(): MMDPhysicsHelper
}
export class ResourceManager {
constructor()
threeVector3s: Vector3[]
threeMatrix4s: Matrix4[]
threeQuaternions: Quaternion[]
threeEulers: Euler[]
transforms: object[]
quaternions: object[]
vector3s: object[]
allocThreeVector3(): void
freeThreeVector3(v: Vector3): void
allocThreeMatrix4(): void
freeThreeMatrix4(m: Matrix4): void
allocThreeQuaternion(): void
freeThreeQuaternion(q: Quaternion): void
allocThreeEuler(): void
freeThreeEuler(e: Euler): void
allocTransform(): void
freeTransform(t: object): void
allocQuaternion(): void
freeQuaternion(q: object): void
allocVector3(): void
freeVector3(v: object): void
setIdentity(): void
getBasis(t: object): object
getBasisAsMatrix3(t: object): object
getOrigin(t: object): object
setOrigin(t: object, v: object): void
copyOrigin(t1: object, t2: object): void
setBasis(t: object, q: object): void
setBasisFromMatrix3(t: object, m: object): void
setOriginFromArray3(t: object, a: number[]): void
setOriginFromThreeVector3(t: object, v: Vector3): void
setBasisFromArray3(t: object, a: number[]): void
setBasisFromThreeQuaternion(t: object, a: Quaternion): void
multiplyTransforms(t1: object, t2: object): object
inverseTransform(t: object): object
multiplyMatrices3(m1: object, m2: object): object
addVector3(v1: object, v2: object): object
dotVectors3(v1: object, v2: object): number
rowOfMatrix3(m: object, i: number): object
columnOfMatrix3(m: object, i: number): object
negativeVector3(v: object): object
multiplyMatrix3ByVector3(m: object, v: object): object
transposeMatrix3(m: object): object
quaternionToMatrix3(q: object): object
matrix3ToQuaternion(m: object): object
}
export class RigidBody {
constructor(mesh: SkinnedMesh, world: object, params: object, manager: ResourceManager)
mesh: SkinnedMesh
world: object
params: object
manager: ResourceManager
body: object
bone: Bone
boneOffsetForm: object
boneOffsetFormInverse: object
reset(): this
updateFromBone(): this
updateBone(): this
}
export class Constraint {
constructor(
mesh: SkinnedMesh,
world: object,
bodyA: RigidBody,
bodyB: RigidBody,
params: object,
manager: ResourceManager,
)
mesh: SkinnedMesh
world: object
bodyA: RigidBody
bodyB: RigidBody
params: object
manager: ResourceManager
}
export class MMDPhysicsHelper extends Object3D {
mesh: SkinnedMesh
physics: MMDPhysics
materials: [MeshBasicMaterial, MeshBasicMaterial, MeshBasicMaterial]
constructor(mesh: SkinnedMesh, physics: MMDPhysics)
dispose(): void
}
+831
View File
@@ -0,0 +1,831 @@
import { Vector3, Matrix4, Quaternion, Euler, Bone, Object3D, MeshBasicMaterial, Color, Mesh, BoxGeometry, SphereGeometry } from "three";
import { CapsuleGeometry } from "../_polyfill/CapsuleGeometry.js";
class MMDPhysics {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Array<Object>} rigidBodyParams
* @param {Array<Object>} (optional) constraintParams
* @param {Object} params - (optional)
* @param {Number} params.unitStep - Default is 1 / 65.
* @param {Integer} params.maxStepNum - Default is 3.
* @param {Vector3} params.gravity - Default is ( 0, - 9.8 * 10, 0 )
*/
constructor(mesh, rigidBodyParams, constraintParams = [], params = {}) {
if (typeof Ammo === "undefined") {
throw new Error("THREE.MMDPhysics: Import ammo.js https://github.com/kripken/ammo.js");
}
this.manager = new ResourceManager();
this.mesh = mesh;
this.unitStep = params.unitStep !== void 0 ? params.unitStep : 1 / 65;
this.maxStepNum = params.maxStepNum !== void 0 ? params.maxStepNum : 3;
this.gravity = new Vector3(0, -9.8 * 10, 0);
if (params.gravity !== void 0)
this.gravity.copy(params.gravity);
this.world = params.world !== void 0 ? params.world : null;
this.bodies = [];
this.constraints = [];
this._init(mesh, rigidBodyParams, constraintParams);
}
/**
* Advances Physics calculation and updates bones.
*
* @param {Number} delta - time in second
* @return {MMDPhysics}
*/
update(delta) {
const manager = this.manager;
const mesh = this.mesh;
let isNonDefaultScale = false;
const position = manager.allocThreeVector3();
const quaternion = manager.allocThreeQuaternion();
const scale = manager.allocThreeVector3();
mesh.matrixWorld.decompose(position, quaternion, scale);
if (scale.x !== 1 || scale.y !== 1 || scale.z !== 1) {
isNonDefaultScale = true;
}
let parent;
if (isNonDefaultScale) {
parent = mesh.parent;
if (parent !== null)
mesh.parent = null;
scale.copy(this.mesh.scale);
mesh.scale.set(1, 1, 1);
mesh.updateMatrixWorld(true);
}
this._updateRigidBodies();
this._stepSimulation(delta);
this._updateBones();
if (isNonDefaultScale) {
if (parent !== null)
mesh.parent = parent;
mesh.scale.copy(scale);
}
manager.freeThreeVector3(scale);
manager.freeThreeQuaternion(quaternion);
manager.freeThreeVector3(position);
return this;
}
/**
* Resets rigid bodies transorm to current bone's.
*
* @return {MMDPhysics}
*/
reset() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].reset();
}
return this;
}
/**
* Warm ups Rigid bodies. Calculates cycles steps.
*
* @param {Integer} cycles
* @return {MMDPhysics}
*/
warmup(cycles) {
for (let i = 0; i < cycles; i++) {
this.update(1 / 60);
}
return this;
}
/**
* Sets gravity.
*
* @param {Vector3} gravity
* @return {MMDPhysicsHelper}
*/
setGravity(gravity) {
this.world.setGravity(new Ammo.btVector3(gravity.x, gravity.y, gravity.z));
this.gravity.copy(gravity);
return this;
}
/**
* Creates MMDPhysicsHelper
*
* @return {MMDPhysicsHelper}
*/
createHelper() {
return new MMDPhysicsHelper(this.mesh, this);
}
// private methods
_init(mesh, rigidBodyParams, constraintParams) {
const manager = this.manager;
const parent = mesh.parent;
if (parent !== null)
mesh.parent = null;
const currentPosition = manager.allocThreeVector3();
const currentQuaternion = manager.allocThreeQuaternion();
const currentScale = manager.allocThreeVector3();
currentPosition.copy(mesh.position);
currentQuaternion.copy(mesh.quaternion);
currentScale.copy(mesh.scale);
mesh.position.set(0, 0, 0);
mesh.quaternion.set(0, 0, 0, 1);
mesh.scale.set(1, 1, 1);
mesh.updateMatrixWorld(true);
if (this.world === null) {
this.world = this._createWorld();
this.setGravity(this.gravity);
}
this._initRigidBodies(rigidBodyParams);
this._initConstraints(constraintParams);
if (parent !== null)
mesh.parent = parent;
mesh.position.copy(currentPosition);
mesh.quaternion.copy(currentQuaternion);
mesh.scale.copy(currentScale);
mesh.updateMatrixWorld(true);
this.reset();
manager.freeThreeVector3(currentPosition);
manager.freeThreeQuaternion(currentQuaternion);
manager.freeThreeVector3(currentScale);
}
_createWorld() {
const config = new Ammo.btDefaultCollisionConfiguration();
const dispatcher = new Ammo.btCollisionDispatcher(config);
const cache = new Ammo.btDbvtBroadphase();
const solver = new Ammo.btSequentialImpulseConstraintSolver();
const world = new Ammo.btDiscreteDynamicsWorld(dispatcher, cache, solver, config);
return world;
}
_initRigidBodies(rigidBodies) {
for (let i = 0, il = rigidBodies.length; i < il; i++) {
this.bodies.push(new RigidBody(this.mesh, this.world, rigidBodies[i], this.manager));
}
}
_initConstraints(constraints) {
for (let i = 0, il = constraints.length; i < il; i++) {
const params = constraints[i];
const bodyA = this.bodies[params.rigidBodyIndex1];
const bodyB = this.bodies[params.rigidBodyIndex2];
this.constraints.push(new Constraint(this.mesh, this.world, bodyA, bodyB, params, this.manager));
}
}
_stepSimulation(delta) {
const unitStep = this.unitStep;
let stepTime = delta;
let maxStepNum = (delta / unitStep | 0) + 1;
if (stepTime < unitStep) {
stepTime = unitStep;
maxStepNum = 1;
}
if (maxStepNum > this.maxStepNum) {
maxStepNum = this.maxStepNum;
}
this.world.stepSimulation(stepTime, maxStepNum, unitStep);
}
_updateRigidBodies() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].updateFromBone();
}
}
_updateBones() {
for (let i = 0, il = this.bodies.length; i < il; i++) {
this.bodies[i].updateBone();
}
}
}
class ResourceManager {
constructor() {
this.threeVector3s = [];
this.threeMatrix4s = [];
this.threeQuaternions = [];
this.threeEulers = [];
this.transforms = [];
this.quaternions = [];
this.vector3s = [];
}
allocThreeVector3() {
return this.threeVector3s.length > 0 ? this.threeVector3s.pop() : new Vector3();
}
freeThreeVector3(v) {
this.threeVector3s.push(v);
}
allocThreeMatrix4() {
return this.threeMatrix4s.length > 0 ? this.threeMatrix4s.pop() : new Matrix4();
}
freeThreeMatrix4(m) {
this.threeMatrix4s.push(m);
}
allocThreeQuaternion() {
return this.threeQuaternions.length > 0 ? this.threeQuaternions.pop() : new Quaternion();
}
freeThreeQuaternion(q) {
this.threeQuaternions.push(q);
}
allocThreeEuler() {
return this.threeEulers.length > 0 ? this.threeEulers.pop() : new Euler();
}
freeThreeEuler(e) {
this.threeEulers.push(e);
}
allocTransform() {
return this.transforms.length > 0 ? this.transforms.pop() : new Ammo.btTransform();
}
freeTransform(t) {
this.transforms.push(t);
}
allocQuaternion() {
return this.quaternions.length > 0 ? this.quaternions.pop() : new Ammo.btQuaternion();
}
freeQuaternion(q) {
this.quaternions.push(q);
}
allocVector3() {
return this.vector3s.length > 0 ? this.vector3s.pop() : new Ammo.btVector3();
}
freeVector3(v) {
this.vector3s.push(v);
}
setIdentity(t) {
t.setIdentity();
}
getBasis(t) {
var q = this.allocQuaternion();
t.getBasis().getRotation(q);
return q;
}
getBasisAsMatrix3(t) {
var q = this.getBasis(t);
var m = this.quaternionToMatrix3(q);
this.freeQuaternion(q);
return m;
}
getOrigin(t) {
return t.getOrigin();
}
setOrigin(t, v) {
t.getOrigin().setValue(v.x(), v.y(), v.z());
}
copyOrigin(t1, t2) {
var o = t2.getOrigin();
this.setOrigin(t1, o);
}
setBasis(t, q) {
t.setRotation(q);
}
setBasisFromMatrix3(t, m) {
var q = this.matrix3ToQuaternion(m);
this.setBasis(t, q);
this.freeQuaternion(q);
}
setOriginFromArray3(t, a) {
t.getOrigin().setValue(a[0], a[1], a[2]);
}
setOriginFromThreeVector3(t, v) {
t.getOrigin().setValue(v.x, v.y, v.z);
}
setBasisFromArray3(t, a) {
var thQ = this.allocThreeQuaternion();
var thE = this.allocThreeEuler();
thE.set(a[0], a[1], a[2]);
this.setBasisFromThreeQuaternion(t, thQ.setFromEuler(thE));
this.freeThreeEuler(thE);
this.freeThreeQuaternion(thQ);
}
setBasisFromThreeQuaternion(t, a) {
var q = this.allocQuaternion();
q.setX(a.x);
q.setY(a.y);
q.setZ(a.z);
q.setW(a.w);
this.setBasis(t, q);
this.freeQuaternion(q);
}
multiplyTransforms(t1, t2) {
var t = this.allocTransform();
this.setIdentity(t);
var m1 = this.getBasisAsMatrix3(t1);
var m2 = this.getBasisAsMatrix3(t2);
var o1 = this.getOrigin(t1);
var o2 = this.getOrigin(t2);
var v1 = this.multiplyMatrix3ByVector3(m1, o2);
var v2 = this.addVector3(v1, o1);
this.setOrigin(t, v2);
var m3 = this.multiplyMatrices3(m1, m2);
this.setBasisFromMatrix3(t, m3);
this.freeVector3(v1);
this.freeVector3(v2);
return t;
}
inverseTransform(t) {
var t2 = this.allocTransform();
var m1 = this.getBasisAsMatrix3(t);
var o = this.getOrigin(t);
var m2 = this.transposeMatrix3(m1);
var v1 = this.negativeVector3(o);
var v2 = this.multiplyMatrix3ByVector3(m2, v1);
this.setOrigin(t2, v2);
this.setBasisFromMatrix3(t2, m2);
this.freeVector3(v1);
this.freeVector3(v2);
return t2;
}
multiplyMatrices3(m1, m2) {
var m3 = [];
var v10 = this.rowOfMatrix3(m1, 0);
var v11 = this.rowOfMatrix3(m1, 1);
var v12 = this.rowOfMatrix3(m1, 2);
var v20 = this.columnOfMatrix3(m2, 0);
var v21 = this.columnOfMatrix3(m2, 1);
var v22 = this.columnOfMatrix3(m2, 2);
m3[0] = this.dotVectors3(v10, v20);
m3[1] = this.dotVectors3(v10, v21);
m3[2] = this.dotVectors3(v10, v22);
m3[3] = this.dotVectors3(v11, v20);
m3[4] = this.dotVectors3(v11, v21);
m3[5] = this.dotVectors3(v11, v22);
m3[6] = this.dotVectors3(v12, v20);
m3[7] = this.dotVectors3(v12, v21);
m3[8] = this.dotVectors3(v12, v22);
this.freeVector3(v10);
this.freeVector3(v11);
this.freeVector3(v12);
this.freeVector3(v20);
this.freeVector3(v21);
this.freeVector3(v22);
return m3;
}
addVector3(v1, v2) {
var v = this.allocVector3();
v.setValue(v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z());
return v;
}
dotVectors3(v1, v2) {
return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
}
rowOfMatrix3(m, i) {
var v = this.allocVector3();
v.setValue(m[i * 3 + 0], m[i * 3 + 1], m[i * 3 + 2]);
return v;
}
columnOfMatrix3(m, i) {
var v = this.allocVector3();
v.setValue(m[i + 0], m[i + 3], m[i + 6]);
return v;
}
negativeVector3(v) {
var v2 = this.allocVector3();
v2.setValue(-v.x(), -v.y(), -v.z());
return v2;
}
multiplyMatrix3ByVector3(m, v) {
var v4 = this.allocVector3();
var v0 = this.rowOfMatrix3(m, 0);
var v1 = this.rowOfMatrix3(m, 1);
var v2 = this.rowOfMatrix3(m, 2);
var x = this.dotVectors3(v0, v);
var y = this.dotVectors3(v1, v);
var z = this.dotVectors3(v2, v);
v4.setValue(x, y, z);
this.freeVector3(v0);
this.freeVector3(v1);
this.freeVector3(v2);
return v4;
}
transposeMatrix3(m) {
var m2 = [];
m2[0] = m[0];
m2[1] = m[3];
m2[2] = m[6];
m2[3] = m[1];
m2[4] = m[4];
m2[5] = m[7];
m2[6] = m[2];
m2[7] = m[5];
m2[8] = m[8];
return m2;
}
quaternionToMatrix3(q) {
var m = [];
var x = q.x();
var y = q.y();
var z = q.z();
var w = q.w();
var xx = x * x;
var yy = y * y;
var zz = z * z;
var xy = x * y;
var yz = y * z;
var zx = z * x;
var xw = x * w;
var yw = y * w;
var zw = z * w;
m[0] = 1 - 2 * (yy + zz);
m[1] = 2 * (xy - zw);
m[2] = 2 * (zx + yw);
m[3] = 2 * (xy + zw);
m[4] = 1 - 2 * (zz + xx);
m[5] = 2 * (yz - xw);
m[6] = 2 * (zx - yw);
m[7] = 2 * (yz + xw);
m[8] = 1 - 2 * (xx + yy);
return m;
}
matrix3ToQuaternion(m) {
var t = m[0] + m[4] + m[8];
var s, x, y, z, w;
if (t > 0) {
s = Math.sqrt(t + 1) * 2;
w = 0.25 * s;
x = (m[7] - m[5]) / s;
y = (m[2] - m[6]) / s;
z = (m[3] - m[1]) / s;
} else if (m[0] > m[4] && m[0] > m[8]) {
s = Math.sqrt(1 + m[0] - m[4] - m[8]) * 2;
w = (m[7] - m[5]) / s;
x = 0.25 * s;
y = (m[1] + m[3]) / s;
z = (m[2] + m[6]) / s;
} else if (m[4] > m[8]) {
s = Math.sqrt(1 + m[4] - m[0] - m[8]) * 2;
w = (m[2] - m[6]) / s;
x = (m[1] + m[3]) / s;
y = 0.25 * s;
z = (m[5] + m[7]) / s;
} else {
s = Math.sqrt(1 + m[8] - m[0] - m[4]) * 2;
w = (m[3] - m[1]) / s;
x = (m[2] + m[6]) / s;
y = (m[5] + m[7]) / s;
z = 0.25 * s;
}
var q = this.allocQuaternion();
q.setX(x);
q.setY(y);
q.setZ(z);
q.setW(w);
return q;
}
}
class RigidBody {
constructor(mesh, world, params, manager) {
this.mesh = mesh;
this.world = world;
this.params = params;
this.manager = manager;
this.body = null;
this.bone = null;
this.boneOffsetForm = null;
this.boneOffsetFormInverse = null;
this._init();
}
/**
* Resets rigid body transform to the current bone's.
*
* @return {RigidBody}
*/
reset() {
this._setTransformFromBone();
return this;
}
/**
* Updates rigid body's transform from the current bone.
*
* @return {RidigBody}
*/
updateFromBone() {
if (this.params.boneIndex !== -1 && this.params.type === 0) {
this._setTransformFromBone();
}
return this;
}
/**
* Updates bone from the current ridid body's transform.
*
* @return {RidigBody}
*/
updateBone() {
if (this.params.type === 0 || this.params.boneIndex === -1) {
return this;
}
this._updateBoneRotation();
if (this.params.type === 1) {
this._updateBonePosition();
}
this.bone.updateMatrixWorld(true);
if (this.params.type === 2) {
this._setPositionFromBone();
}
return this;
}
// private methods
_init() {
function generateShape(p) {
switch (p.shapeType) {
case 0:
return new Ammo.btSphereShape(p.width);
case 1:
return new Ammo.btBoxShape(new Ammo.btVector3(p.width, p.height, p.depth));
case 2:
return new Ammo.btCapsuleShape(p.width, p.height);
default:
throw new Error("unknown shape type " + p.shapeType);
}
}
const manager = this.manager;
const params = this.params;
const bones = this.mesh.skeleton.bones;
const bone = params.boneIndex === -1 ? new Bone() : bones[params.boneIndex];
const shape = generateShape(params);
const weight = params.type === 0 ? 0 : params.weight;
const localInertia = manager.allocVector3();
localInertia.setValue(0, 0, 0);
if (weight !== 0) {
shape.calculateLocalInertia(weight, localInertia);
}
const boneOffsetForm = manager.allocTransform();
manager.setIdentity(boneOffsetForm);
manager.setOriginFromArray3(boneOffsetForm, params.position);
manager.setBasisFromArray3(boneOffsetForm, params.rotation);
const vector = manager.allocThreeVector3();
const boneForm = manager.allocTransform();
manager.setIdentity(boneForm);
manager.setOriginFromThreeVector3(boneForm, bone.getWorldPosition(vector));
const form = manager.multiplyTransforms(boneForm, boneOffsetForm);
const state = new Ammo.btDefaultMotionState(form);
const info = new Ammo.btRigidBodyConstructionInfo(weight, state, shape, localInertia);
info.set_m_friction(params.friction);
info.set_m_restitution(params.restitution);
const body = new Ammo.btRigidBody(info);
if (params.type === 0) {
body.setCollisionFlags(body.getCollisionFlags() | 2);
body.setActivationState(4);
}
body.setDamping(params.positionDamping, params.rotationDamping);
body.setSleepingThresholds(0, 0);
this.world.addRigidBody(body, 1 << params.groupIndex, params.groupTarget);
this.body = body;
this.bone = bone;
this.boneOffsetForm = boneOffsetForm;
this.boneOffsetFormInverse = manager.inverseTransform(boneOffsetForm);
manager.freeVector3(localInertia);
manager.freeTransform(form);
manager.freeTransform(boneForm);
manager.freeThreeVector3(vector);
}
_getBoneTransform() {
const manager = this.manager;
const p = manager.allocThreeVector3();
const q = manager.allocThreeQuaternion();
const s = manager.allocThreeVector3();
this.bone.matrixWorld.decompose(p, q, s);
const tr = manager.allocTransform();
manager.setOriginFromThreeVector3(tr, p);
manager.setBasisFromThreeQuaternion(tr, q);
const form = manager.multiplyTransforms(tr, this.boneOffsetForm);
manager.freeTransform(tr);
manager.freeThreeVector3(s);
manager.freeThreeQuaternion(q);
manager.freeThreeVector3(p);
return form;
}
_getWorldTransformForBone() {
const manager = this.manager;
const tr = this.body.getCenterOfMassTransform();
return manager.multiplyTransforms(tr, this.boneOffsetFormInverse);
}
_setTransformFromBone() {
const manager = this.manager;
const form = this._getBoneTransform();
this.body.setCenterOfMassTransform(form);
this.body.getMotionState().setWorldTransform(form);
manager.freeTransform(form);
}
_setPositionFromBone() {
const manager = this.manager;
const form = this._getBoneTransform();
const tr = manager.allocTransform();
this.body.getMotionState().getWorldTransform(tr);
manager.copyOrigin(tr, form);
this.body.setCenterOfMassTransform(tr);
this.body.getMotionState().setWorldTransform(tr);
manager.freeTransform(tr);
manager.freeTransform(form);
}
_updateBoneRotation() {
const manager = this.manager;
const tr = this._getWorldTransformForBone();
const q = manager.getBasis(tr);
const thQ = manager.allocThreeQuaternion();
const thQ2 = manager.allocThreeQuaternion();
const thQ3 = manager.allocThreeQuaternion();
thQ.set(q.x(), q.y(), q.z(), q.w());
thQ2.setFromRotationMatrix(this.bone.matrixWorld);
thQ2.conjugate();
thQ2.multiply(thQ);
thQ3.setFromRotationMatrix(this.bone.matrix);
this.bone.quaternion.copy(thQ2.multiply(thQ3).normalize());
manager.freeThreeQuaternion(thQ);
manager.freeThreeQuaternion(thQ2);
manager.freeThreeQuaternion(thQ3);
manager.freeQuaternion(q);
manager.freeTransform(tr);
}
_updateBonePosition() {
const manager = this.manager;
const tr = this._getWorldTransformForBone();
const thV = manager.allocThreeVector3();
const o = manager.getOrigin(tr);
thV.set(o.x(), o.y(), o.z());
if (this.bone.parent) {
this.bone.parent.worldToLocal(thV);
}
this.bone.position.copy(thV);
manager.freeThreeVector3(thV);
manager.freeTransform(tr);
}
}
class Constraint {
/**
* @param {THREE.SkinnedMesh} mesh
* @param {Ammo.btDiscreteDynamicsWorld} world
* @param {RigidBody} bodyA
* @param {RigidBody} bodyB
* @param {Object} params
* @param {ResourceManager} manager
*/
constructor(mesh, world, bodyA, bodyB, params, manager) {
this.mesh = mesh;
this.world = world;
this.bodyA = bodyA;
this.bodyB = bodyB;
this.params = params;
this.manager = manager;
this.constraint = null;
this._init();
}
// private method
_init() {
const manager = this.manager;
const params = this.params;
const bodyA = this.bodyA;
const bodyB = this.bodyB;
const form = manager.allocTransform();
manager.setIdentity(form);
manager.setOriginFromArray3(form, params.position);
manager.setBasisFromArray3(form, params.rotation);
const formA = manager.allocTransform();
const formB = manager.allocTransform();
bodyA.body.getMotionState().getWorldTransform(formA);
bodyB.body.getMotionState().getWorldTransform(formB);
const formInverseA = manager.inverseTransform(formA);
const formInverseB = manager.inverseTransform(formB);
const formA2 = manager.multiplyTransforms(formInverseA, form);
const formB2 = manager.multiplyTransforms(formInverseB, form);
const constraint = new Ammo.btGeneric6DofSpringConstraint(bodyA.body, bodyB.body, formA2, formB2, true);
const lll = manager.allocVector3();
const lul = manager.allocVector3();
const all = manager.allocVector3();
const aul = manager.allocVector3();
lll.setValue(params.translationLimitation1[0], params.translationLimitation1[1], params.translationLimitation1[2]);
lul.setValue(params.translationLimitation2[0], params.translationLimitation2[1], params.translationLimitation2[2]);
all.setValue(params.rotationLimitation1[0], params.rotationLimitation1[1], params.rotationLimitation1[2]);
aul.setValue(params.rotationLimitation2[0], params.rotationLimitation2[1], params.rotationLimitation2[2]);
constraint.setLinearLowerLimit(lll);
constraint.setLinearUpperLimit(lul);
constraint.setAngularLowerLimit(all);
constraint.setAngularUpperLimit(aul);
for (let i = 0; i < 3; i++) {
if (params.springPosition[i] !== 0) {
constraint.enableSpring(i, true);
constraint.setStiffness(i, params.springPosition[i]);
}
}
for (let i = 0; i < 3; i++) {
if (params.springRotation[i] !== 0) {
constraint.enableSpring(i + 3, true);
constraint.setStiffness(i + 3, params.springRotation[i]);
}
}
if (constraint.setParam !== void 0) {
for (let i = 0; i < 6; i++) {
constraint.setParam(2, 0.475, i);
}
}
this.world.addConstraint(constraint, true);
this.constraint = constraint;
manager.freeTransform(form);
manager.freeTransform(formA);
manager.freeTransform(formB);
manager.freeTransform(formInverseA);
manager.freeTransform(formInverseB);
manager.freeTransform(formA2);
manager.freeTransform(formB2);
manager.freeVector3(lll);
manager.freeVector3(lul);
manager.freeVector3(all);
manager.freeVector3(aul);
}
}
const _position = /* @__PURE__ */ new Vector3();
const _quaternion = /* @__PURE__ */ new Quaternion();
const _scale = /* @__PURE__ */ new Vector3();
const _matrixWorldInv = /* @__PURE__ */ new Matrix4();
class MMDPhysicsHelper extends Object3D {
/**
* Visualize Rigid bodies
*
* @param {THREE.SkinnedMesh} mesh
* @param {Physics} physics
*/
constructor(mesh, physics) {
super();
this.root = mesh;
this.physics = physics;
this.matrix.copy(mesh.matrixWorld);
this.matrixAutoUpdate = false;
this.materials = [];
this.materials.push(
new MeshBasicMaterial({
color: new Color(16746632),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this.materials.push(
new MeshBasicMaterial({
color: new Color(8978312),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this.materials.push(
new MeshBasicMaterial({
color: new Color(8947967),
wireframe: true,
depthTest: false,
depthWrite: false,
opacity: 0.25,
transparent: true
})
);
this._init();
}
/**
* Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.
*/
dispose() {
const materials = this.materials;
const children = this.children;
for (let i = 0; i < materials.length; i++) {
materials[i].dispose();
}
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.isMesh)
child.geometry.dispose();
}
}
/**
* Updates Rigid Bodies visualization.
*/
updateMatrixWorld(force) {
var mesh = this.root;
if (this.visible) {
var bodies = this.physics.bodies;
_matrixWorldInv.copy(mesh.matrixWorld).decompose(_position, _quaternion, _scale).compose(_position, _quaternion, _scale.set(1, 1, 1)).invert();
for (var i = 0, il = bodies.length; i < il; i++) {
var body = bodies[i].body;
var child = this.children[i];
var tr = body.getCenterOfMassTransform();
var origin = tr.getOrigin();
var rotation = tr.getRotation();
child.position.set(origin.x(), origin.y(), origin.z()).applyMatrix4(_matrixWorldInv);
child.quaternion.setFromRotationMatrix(_matrixWorldInv).multiply(_quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w()));
}
}
this.matrix.copy(mesh.matrixWorld).decompose(_position, _quaternion, _scale).compose(_position, _quaternion, _scale.set(1, 1, 1));
super.updateMatrixWorld(force);
}
// private method
_init() {
var bodies = this.physics.bodies;
function createGeometry(param2) {
switch (param2.shapeType) {
case 0:
return new SphereGeometry(param2.width, 16, 8);
case 1:
return new BoxGeometry(param2.width * 2, param2.height * 2, param2.depth * 2, 8, 8, 8);
case 2:
return new CapsuleGeometry(param2.width, param2.height, 8, 16);
default:
return null;
}
}
for (var i = 0, il = bodies.length; i < il; i++) {
var param = bodies[i].params;
this.add(new Mesh(createGeometry(param), this.materials[param.type]));
}
}
}
export {
MMDPhysics
};
//# sourceMappingURL=MMDPhysics.js.map
File diff suppressed because one or more lines are too long
+132
View File
@@ -0,0 +1,132 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const BokehShader2 = require("../shaders/BokehShader2.cjs");
class CinematicCamera extends THREE.PerspectiveCamera {
constructor(fov, aspect, near, far) {
super(fov, aspect, near, far);
this.type = "CinematicCamera";
this.postprocessing = { enabled: true };
this.shaderSettings = {
rings: 3,
samples: 4
};
const depthShader = BokehShader2.BokehDepthShader;
this.materialDepth = new THREE.ShaderMaterial({
uniforms: depthShader.uniforms,
vertexShader: depthShader.vertexShader,
fragmentShader: depthShader.fragmentShader
});
this.materialDepth.uniforms["mNear"].value = near;
this.materialDepth.uniforms["mFar"].value = far;
this.setLens();
this.initPostProcessing();
}
// providing fnumber and coc(Circle of Confusion) as extra arguments
setLens(focalLength, filmGauge, fNumber, coc) {
if (focalLength === void 0)
focalLength = 35;
if (filmGauge !== void 0)
this.filmGauge = filmGauge;
this.setFocalLength(focalLength);
if (fNumber === void 0)
fNumber = 8;
if (coc === void 0)
coc = 0.019;
this.fNumber = fNumber;
this.coc = coc;
this.aperture = focalLength / this.fNumber;
this.hyperFocal = focalLength * focalLength / (this.aperture * this.coc);
}
linearize(depth) {
const zfar = this.far;
const znear = this.near;
return -zfar * znear / (depth * (zfar - znear) - zfar);
}
smoothstep(near, far, depth) {
const x = this.saturate((depth - near) / (far - near));
return x * x * (3 - 2 * x);
}
saturate(x) {
return Math.max(0, Math.min(1, x));
}
// function for focusing at a distance from the camera
focusAt(focusDistance) {
if (focusDistance === void 0)
focusDistance = 20;
const focalLength = this.getFocalLength();
this.focus = focusDistance;
this.nearPoint = this.hyperFocal * this.focus / (this.hyperFocal + (this.focus - focalLength));
this.farPoint = this.hyperFocal * this.focus / (this.hyperFocal - (this.focus - focalLength));
this.depthOfField = this.farPoint - this.nearPoint;
if (this.depthOfField < 0)
this.depthOfField = 0;
this.sdistance = this.smoothstep(this.near, this.far, this.focus);
this.ldistance = this.linearize(1 - this.sdistance);
this.postprocessing.bokeh_uniforms["focalDepth"].value = this.ldistance;
}
initPostProcessing() {
if (this.postprocessing.enabled) {
this.postprocessing.scene = new THREE.Scene();
this.postprocessing.camera = new THREE.OrthographicCamera(
window.innerWidth / -2,
window.innerWidth / 2,
window.innerHeight / 2,
window.innerHeight / -2,
-1e4,
1e4
);
this.postprocessing.scene.add(this.postprocessing.camera);
this.postprocessing.rtTextureDepth = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.postprocessing.rtTextureColor = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
const bokeh_shader = BokehShader2.BokehShader2;
this.postprocessing.bokeh_uniforms = THREE.UniformsUtils.clone(bokeh_shader.uniforms);
this.postprocessing.bokeh_uniforms["tColor"].value = this.postprocessing.rtTextureColor.texture;
this.postprocessing.bokeh_uniforms["tDepth"].value = this.postprocessing.rtTextureDepth.texture;
this.postprocessing.bokeh_uniforms["manualdof"].value = 0;
this.postprocessing.bokeh_uniforms["shaderFocus"].value = 0;
this.postprocessing.bokeh_uniforms["fstop"].value = 2.8;
this.postprocessing.bokeh_uniforms["showFocus"].value = 1;
this.postprocessing.bokeh_uniforms["focalDepth"].value = 0.1;
this.postprocessing.bokeh_uniforms["znear"].value = this.near;
this.postprocessing.bokeh_uniforms["zfar"].value = this.near;
this.postprocessing.bokeh_uniforms["textureWidth"].value = window.innerWidth;
this.postprocessing.bokeh_uniforms["textureHeight"].value = window.innerHeight;
this.postprocessing.materialBokeh = new THREE.ShaderMaterial({
uniforms: this.postprocessing.bokeh_uniforms,
vertexShader: bokeh_shader.vertexShader,
fragmentShader: bokeh_shader.fragmentShader,
defines: {
RINGS: this.shaderSettings.rings,
SAMPLES: this.shaderSettings.samples,
DEPTH_PACKING: 1
}
});
this.postprocessing.quad = new THREE.Mesh(
new THREE.PlaneGeometry(window.innerWidth, window.innerHeight),
this.postprocessing.materialBokeh
);
this.postprocessing.quad.position.z = -500;
this.postprocessing.scene.add(this.postprocessing.quad);
}
}
renderCinematic(scene, renderer) {
if (this.postprocessing.enabled) {
const currentRenderTarget = renderer.getRenderTarget();
renderer.clear();
scene.overrideMaterial = null;
renderer.setRenderTarget(this.postprocessing.rtTextureColor);
renderer.clear();
renderer.render(scene, this);
scene.overrideMaterial = this.materialDepth;
renderer.setRenderTarget(this.postprocessing.rtTextureDepth);
renderer.clear();
renderer.render(scene, this);
renderer.setRenderTarget(null);
renderer.render(this.postprocessing.scene, this.postprocessing.camera);
renderer.setRenderTarget(currentRenderTarget);
}
}
}
exports.CinematicCamera = CinematicCamera;
//# sourceMappingURL=CinematicCamera.cjs.map
File diff suppressed because one or more lines are too long
+34
View File
@@ -0,0 +1,34 @@
import { PerspectiveCamera, ShaderMaterial, Scene, WebGLRenderer, OrthographicCamera, WebGLRenderTarget } from 'three'
import { BokehShader2Uniforms } from './../shaders/BokehShader2'
export class CinematicCamera extends PerspectiveCamera {
constructor(fov: number, aspect: number, near: number, far: number)
postprocessing: {
enabled: boolean
scene: Scene
camera: OrthographicCamera
rtTextureDepth: WebGLRenderTarget
rtTextureColor: WebGLRenderTarget
bokeh_uniforms: BokehShader2Uniforms
}
shaderSettings: {
rings: number
samples: number
}
materialDepth: ShaderMaterial
coc: number
aperture: number
fNumber: number
hyperFocal: number
filmGauge: number
linearize(depth: number): number
smoothstep(near: number, far: number, depth: number): number
saturate(x: number): number
focusAt(focusDistance: number): void
initPostProcessing(): void
renderCinematic(scene: Scene, renderer: WebGLRenderer): void
setLens(focalLength: number, frameHeight?: number, fNumber?: number, coc?: number): void
}
+132
View File
@@ -0,0 +1,132 @@
import { PerspectiveCamera, ShaderMaterial, Scene, OrthographicCamera, WebGLRenderTarget, UniformsUtils, Mesh, PlaneGeometry } from "three";
import { BokehDepthShader, BokehShader2 } from "../shaders/BokehShader2.js";
class CinematicCamera extends PerspectiveCamera {
constructor(fov, aspect, near, far) {
super(fov, aspect, near, far);
this.type = "CinematicCamera";
this.postprocessing = { enabled: true };
this.shaderSettings = {
rings: 3,
samples: 4
};
const depthShader = BokehDepthShader;
this.materialDepth = new ShaderMaterial({
uniforms: depthShader.uniforms,
vertexShader: depthShader.vertexShader,
fragmentShader: depthShader.fragmentShader
});
this.materialDepth.uniforms["mNear"].value = near;
this.materialDepth.uniforms["mFar"].value = far;
this.setLens();
this.initPostProcessing();
}
// providing fnumber and coc(Circle of Confusion) as extra arguments
setLens(focalLength, filmGauge, fNumber, coc) {
if (focalLength === void 0)
focalLength = 35;
if (filmGauge !== void 0)
this.filmGauge = filmGauge;
this.setFocalLength(focalLength);
if (fNumber === void 0)
fNumber = 8;
if (coc === void 0)
coc = 0.019;
this.fNumber = fNumber;
this.coc = coc;
this.aperture = focalLength / this.fNumber;
this.hyperFocal = focalLength * focalLength / (this.aperture * this.coc);
}
linearize(depth) {
const zfar = this.far;
const znear = this.near;
return -zfar * znear / (depth * (zfar - znear) - zfar);
}
smoothstep(near, far, depth) {
const x = this.saturate((depth - near) / (far - near));
return x * x * (3 - 2 * x);
}
saturate(x) {
return Math.max(0, Math.min(1, x));
}
// function for focusing at a distance from the camera
focusAt(focusDistance) {
if (focusDistance === void 0)
focusDistance = 20;
const focalLength = this.getFocalLength();
this.focus = focusDistance;
this.nearPoint = this.hyperFocal * this.focus / (this.hyperFocal + (this.focus - focalLength));
this.farPoint = this.hyperFocal * this.focus / (this.hyperFocal - (this.focus - focalLength));
this.depthOfField = this.farPoint - this.nearPoint;
if (this.depthOfField < 0)
this.depthOfField = 0;
this.sdistance = this.smoothstep(this.near, this.far, this.focus);
this.ldistance = this.linearize(1 - this.sdistance);
this.postprocessing.bokeh_uniforms["focalDepth"].value = this.ldistance;
}
initPostProcessing() {
if (this.postprocessing.enabled) {
this.postprocessing.scene = new Scene();
this.postprocessing.camera = new OrthographicCamera(
window.innerWidth / -2,
window.innerWidth / 2,
window.innerHeight / 2,
window.innerHeight / -2,
-1e4,
1e4
);
this.postprocessing.scene.add(this.postprocessing.camera);
this.postprocessing.rtTextureDepth = new WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.postprocessing.rtTextureColor = new WebGLRenderTarget(window.innerWidth, window.innerHeight);
const bokeh_shader = BokehShader2;
this.postprocessing.bokeh_uniforms = UniformsUtils.clone(bokeh_shader.uniforms);
this.postprocessing.bokeh_uniforms["tColor"].value = this.postprocessing.rtTextureColor.texture;
this.postprocessing.bokeh_uniforms["tDepth"].value = this.postprocessing.rtTextureDepth.texture;
this.postprocessing.bokeh_uniforms["manualdof"].value = 0;
this.postprocessing.bokeh_uniforms["shaderFocus"].value = 0;
this.postprocessing.bokeh_uniforms["fstop"].value = 2.8;
this.postprocessing.bokeh_uniforms["showFocus"].value = 1;
this.postprocessing.bokeh_uniforms["focalDepth"].value = 0.1;
this.postprocessing.bokeh_uniforms["znear"].value = this.near;
this.postprocessing.bokeh_uniforms["zfar"].value = this.near;
this.postprocessing.bokeh_uniforms["textureWidth"].value = window.innerWidth;
this.postprocessing.bokeh_uniforms["textureHeight"].value = window.innerHeight;
this.postprocessing.materialBokeh = new ShaderMaterial({
uniforms: this.postprocessing.bokeh_uniforms,
vertexShader: bokeh_shader.vertexShader,
fragmentShader: bokeh_shader.fragmentShader,
defines: {
RINGS: this.shaderSettings.rings,
SAMPLES: this.shaderSettings.samples,
DEPTH_PACKING: 1
}
});
this.postprocessing.quad = new Mesh(
new PlaneGeometry(window.innerWidth, window.innerHeight),
this.postprocessing.materialBokeh
);
this.postprocessing.quad.position.z = -500;
this.postprocessing.scene.add(this.postprocessing.quad);
}
}
renderCinematic(scene, renderer) {
if (this.postprocessing.enabled) {
const currentRenderTarget = renderer.getRenderTarget();
renderer.clear();
scene.overrideMaterial = null;
renderer.setRenderTarget(this.postprocessing.rtTextureColor);
renderer.clear();
renderer.render(scene, this);
scene.overrideMaterial = this.materialDepth;
renderer.setRenderTarget(this.postprocessing.rtTextureDepth);
renderer.clear();
renderer.render(scene, this);
renderer.setRenderTarget(null);
renderer.render(this.postprocessing.scene, this.postprocessing.camera);
renderer.setRenderTarget(currentRenderTarget);
}
}
}
export {
CinematicCamera
};
//# sourceMappingURL=CinematicCamera.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+376
View File
@@ -0,0 +1,376 @@
import { Vector3, Scene, PerspectiveCamera, OrthographicCamera } from 'three';
import { EventDispatcher } from './EventDispatcher';
import { StandardControlsEventMap } from './StandardControlsEventMap';
type Camera = OrthographicCamera | PerspectiveCamera;
/**
*
* @param {CamOrthographicCamera | PerspectiveCameraera} camera Virtual camera used in the scene
* @param {HTMLElement=null} domElement Renderer's dom element
* @param {Scene=null} scene The scene to be rendered
*/
declare class ArcballControls extends EventDispatcher<StandardControlsEventMap> {
private camera;
private domElement;
private scene;
private mouseActions;
private _mouseOp;
private _v2_1;
private _v3_1;
private _v3_2;
private _m4_1;
private _m4_2;
private _quat;
private _translationMatrix;
private _rotationMatrix;
private _scaleMatrix;
private _rotationAxis;
private _cameraMatrixState;
private _cameraProjectionState;
private _fovState;
private _upState;
private _zoomState;
private _nearPos;
private _farPos;
private _gizmoMatrixState;
private _up0;
private _zoom0;
private _fov0;
private _initialNear;
private _nearPos0;
private _initialFar;
private _farPos0;
private _cameraMatrixState0;
private _gizmoMatrixState0;
private _button;
private _touchStart;
private _touchCurrent;
private _input;
private _switchSensibility;
private _startFingerDistance;
private _currentFingerDistance;
private _startFingerRotation;
private _currentFingerRotation;
private _devPxRatio;
private _downValid;
private _nclicks;
private _downEvents;
private _clickStart;
private _maxDownTime;
private _maxInterval;
private _posThreshold;
private _movementThreshold;
private _currentCursorPosition;
private _startCursorPosition;
private _grid;
private _gridPosition;
private _gizmos;
private _curvePts;
private _timeStart;
private _animationId;
focusAnimationTime: number;
private _timePrev;
private _timeCurrent;
private _anglePrev;
private _angleCurrent;
private _cursorPosPrev;
private _cursorPosCurr;
private _wPrev;
private _wCurr;
adjustNearFar: boolean;
scaleFactor: number;
dampingFactor: number;
wMax: number;
enableAnimations: boolean;
enableGrid: boolean;
cursorZoom: boolean;
minFov: number;
maxFov: number;
enabled: boolean;
enablePan: boolean;
enableRotate: boolean;
enableZoom: boolean;
minDistance: number;
maxDistance: number;
minZoom: number;
maxZoom: number;
readonly target: Vector3;
private _currentTarget;
private _tbRadius;
private _state;
constructor(camera: Camera | null, domElement?: HTMLElement | null | undefined, scene?: Scene | null | undefined);
private onWindowResize;
private onContextMenu;
private onPointerCancel;
private onPointerDown;
private onPointerMove;
private onPointerUp;
private onWheel;
private onSinglePanStart;
private onSinglePanMove;
private onSinglePanEnd;
private onDoubleTap;
private onDoublePanStart;
private onDoublePanMove;
private onDoublePanEnd;
private onRotateStart;
private onRotateMove;
private onRotateEnd;
private onPinchStart;
private onPinchMove;
private onPinchEnd;
private onTriplePanStart;
private onTriplePanMove;
private onTriplePanEnd;
/**
* Set _center's x/y coordinates
* @param {Number} clientX
* @param {Number} clientY
*/
private setCenter;
/**
* Set default mouse actions
*/
private initializeMouseActions;
/**
* Set a new mouse action by specifying the operation to be performed and a mouse/key combination. In case of conflict, replaces the existing one
* @param {String} operation The operation to be performed ('PAN', 'ROTATE', 'ZOOM', 'FOV)
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
* @returns {Boolean} True if the mouse action has been successfully added, false otherwise
*/
private setMouseAction;
/**
* Return the operation associated to a mouse/keyboard combination
* @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches
* @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed
* @returns The operation if it has been found, null otherwise
*/
private getOpFromAction;
/**
* Get the operation associated to mouse and key combination and returns the corresponding FSA state
* @param {Number} mouse Mouse button
* @param {String} key Keyboard modifier
* @returns The FSA state obtained from the operation associated to mouse/keyboard combination
*/
private getOpStateFromAction;
/**
* Calculate the angle between two pointers
* @param {PointerEvent} p1
* @param {PointerEvent} p2
* @returns {Number} The angle between two pointers in degrees
*/
private getAngle;
/**
* Update a PointerEvent inside current pointerevents array
* @param {PointerEvent} event
*/
private updateTouchEvent;
/**
* Apply a transformation matrix, to the camera and gizmos
* @param {Object} transformation Object containing matrices to apply to camera and gizmos
*/
private applyTransformMatrix;
/**
* Calculate the angular speed
* @param {Number} p0 Position at t0
* @param {Number} p1 Position at t1
* @param {Number} t0 Initial time in milliseconds
* @param {Number} t1 Ending time in milliseconds
*/
private calculateAngularSpeed;
/**
* Calculate the distance between two pointers
* @param {PointerEvent} p0 The first pointer
* @param {PointerEvent} p1 The second pointer
* @returns {number} The distance between the two pointers
*/
private calculatePointersDistance;
/**
* Calculate the rotation axis as the vector perpendicular between two vectors
* @param {Vector3} vec1 The first vector
* @param {Vector3} vec2 The second vector
* @returns {Vector3} The normalized rotation axis
*/
private calculateRotationAxis;
/**
* Calculate the trackball radius so that gizmo's diamater will be 2/3 of the minimum side of the camera frustum
* @param {Camera} camera
* @returns {Number} The trackball radius
*/
private calculateTbRadius;
/**
* Focus operation consist of positioning the point of interest in front of the camera and a slightly zoom in
* @param {Vector3} point The point of interest
* @param {Number} size Scale factor
* @param {Number} amount Amount of operation to be completed (used for focus animations, default is complete full operation)
*/
private focus;
/**
* Draw a grid and add it to the scene
*/
private drawGrid;
connect: (domElement: HTMLElement) => void;
/**
* Remove all listeners, stop animations and clean scene
*/
dispose: () => void;
/**
* remove the grid from the scene
*/
private disposeGrid;
/**
* Compute the easing out cubic function for ease out effect in animation
* @param {Number} t The absolute progress of the animation in the bound of 0 (beginning of the) and 1 (ending of animation)
* @returns {Number} Result of easing out cubic at time t
*/
private easeOutCubic;
/**
* Make rotation gizmos more or less visible
* @param {Boolean} isActive If true, make gizmos more visible
*/
private activateGizmos;
/**
* Calculate the cursor position in NDC
* @param {number} x Cursor horizontal coordinate within the canvas
* @param {number} y Cursor vertical coordinate within the canvas
* @param {HTMLElement} canvas The canvas where the renderer draws its output
* @returns {Vector2} Cursor normalized position inside the canvas
*/
private getCursorNDC;
/**
* Calculate the cursor position inside the canvas x/y coordinates with the origin being in the center of the canvas
* @param {Number} x Cursor horizontal coordinate within the canvas
* @param {Number} y Cursor vertical coordinate within the canvas
* @param {HTMLElement} canvas The canvas where the renderer draws its output
* @returns {Vector2} Cursor position inside the canvas
*/
private getCursorPosition;
/**
* Set the camera to be controlled
* @param {Camera} camera The virtual camera to be controlled
*/
private setCamera;
/**
* Set gizmos visibility
* @param {Boolean} value Value of gizmos visibility
*/
setGizmosVisible(value: boolean): void;
/**
* Creates the rotation gizmos matching trackball center and radius
* @param {Vector3} tbCenter The trackball center
* @param {number} tbRadius The trackball radius
*/
private makeGizmos;
/**
* Perform animation for focus operation
* @param {Number} time Instant in which this function is called as performance.now()
* @param {Vector3} point Point of interest for focus operation
* @param {Matrix4} cameraMatrix Camera matrix
* @param {Matrix4} gizmoMatrix Gizmos matrix
*/
private onFocusAnim;
/**
* Perform animation for rotation operation
* @param {Number} time Instant in which this function is called as performance.now()
* @param {Vector3} rotationAxis Rotation axis
* @param {number} w0 Initial angular velocity
*/
private onRotationAnim;
/**
* Perform pan operation moving camera between two points
* @param {Vector3} p0 Initial point
* @param {Vector3} p1 Ending point
* @param {Boolean} adjust If movement should be adjusted considering camera distance (Perspective only)
*/
private pan;
/**
* Reset trackball
*/
reset: () => void;
/**
* Rotate the camera around an axis passing by trackball's center
* @param {Vector3} axis Rotation axis
* @param {number} angle Angle in radians
* @returns {Object} Object with 'camera' field containing transformation matrix resulting from the operation to be applied to the camera
*/
private rotate;
copyState: () => void;
pasteState: () => void;
/**
* Save the current state of the control. This can later be recovered with .reset
*/
saveState: () => void;
/**
* Perform uniform scale operation around a given point
* @param {Number} size Scale factor
* @param {Vector3} point Point around which scale
* @param {Boolean} scaleGizmos If gizmos should be scaled (Perspective only)
* @returns {Object} Object with 'camera' and 'gizmo' fields containing transformation matrices resulting from the operation to be applied to the camera and gizmos
*/
private applyScale;
/**
* Set camera fov
* @param {Number} value fov to be setted
*/
private setFov;
/**
* Set the trackball's center point
* @param {Number} x X coordinate
* @param {Number} y Y coordinate
* @param {Number} z Z coordinate
*/
setTarget: (x: number, y: number, z: number) => void;
/**
* Set values in transformation object
* @param {Matrix4} camera Transformation to be applied to the camera
* @param {Matrix4} gizmos Transformation to be applied to gizmos
*/
private setTransformationMatrices;
/**
* Rotate camera around its direction axis passing by a given point by a given angle
* @param {Vector3} point The point where the rotation axis is passing trough
* @param {Number} angle Angle in radians
* @returns The computed transormation matix
*/
private zRotate;
/**
* Unproject the cursor on the 3D object surface
* @param {Vector2} cursor Cursor coordinates in NDC
* @param {Camera} camera Virtual camera
* @returns {Vector3} The point of intersection with the model, if exist, null otherwise
*/
private unprojectOnObj;
/**
* Unproject the cursor on the trackball surface
* @param {Camera} camera The virtual camera
* @param {Number} cursorX Cursor horizontal coordinate on screen
* @param {Number} cursorY Cursor vertical coordinate on screen
* @param {HTMLElement} canvas The canvas where the renderer draws its output
* @param {number} tbRadius The trackball radius
* @returns {Vector3} The unprojected point on the trackball surface
*/
private unprojectOnTbSurface;
/**
* Unproject the cursor on the plane passing through the center of the trackball orthogonal to the camera
* @param {Camera} camera The virtual camera
* @param {Number} cursorX Cursor horizontal coordinate on screen
* @param {Number} cursorY Cursor vertical coordinate on screen
* @param {HTMLElement} canvas The canvas where the renderer draws its output
* @param {Boolean} initialDistance If initial distance between camera and gizmos should be used for calculations instead of current (Perspective only)
* @returns {Vector3} The unprojected point on the trackball plane
*/
private unprojectOnTbPlane;
/**
* Update camera and gizmos state
*/
private updateMatrixState;
/**
* Update the trackball FSA
* @param {STATE} newState New state of the FSA
* @param {Boolean} updateMatrices If matriices state should be updated
*/
private updateTbState;
update: () => void;
private setStateFromJSON;
}
export { ArcballControls };
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+87
View File
@@ -0,0 +1,87 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
class DeviceOrientationControls extends EventDispatcher.EventDispatcher {
// radians
constructor(object) {
super();
__publicField(this, "object");
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "EPS", 1e-6);
__publicField(this, "enabled", true);
__publicField(this, "deviceOrientation", { alpha: 0, beta: 0, gamma: 0 });
__publicField(this, "screenOrientation", 0);
__publicField(this, "alphaOffset", 0);
__publicField(this, "onDeviceOrientationChangeEvent", (event) => {
this.deviceOrientation = event;
});
__publicField(this, "onScreenOrientationChangeEvent", () => {
this.screenOrientation = window.orientation || 0;
});
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
__publicField(this, "zee", new THREE.Vector3(0, 0, 1));
__publicField(this, "euler", new THREE.Euler());
__publicField(this, "q0", new THREE.Quaternion());
__publicField(this, "q1", new THREE.Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)));
// - PI/2 around the x-axis
__publicField(this, "setObjectQuaternion", (quaternion, alpha, beta, gamma, orient) => {
this.euler.set(beta, alpha, -gamma, "YXZ");
quaternion.setFromEuler(this.euler);
quaternion.multiply(this.q1);
quaternion.multiply(this.q0.setFromAxisAngle(this.zee, -orient));
});
__publicField(this, "connect", () => {
this.onScreenOrientationChangeEvent();
if (window.DeviceOrientationEvent !== void 0 && // @ts-ignore
typeof window.DeviceOrientationEvent.requestPermission === "function") {
window.DeviceOrientationEvent.requestPermission().then((response) => {
if (response == "granted") {
window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
}
}).catch((error) => {
console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:", error);
});
} else {
window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
}
this.enabled = true;
});
__publicField(this, "disconnect", () => {
window.removeEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.removeEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
this.enabled = false;
});
__publicField(this, "lastQuaternion", new THREE.Quaternion());
__publicField(this, "update", () => {
if (this.enabled === false)
return;
const device = this.deviceOrientation;
if (device) {
const alpha = device.alpha ? THREE.MathUtils.degToRad(device.alpha) + this.alphaOffset : 0;
const beta = device.beta ? THREE.MathUtils.degToRad(device.beta) : 0;
const gamma = device.gamma ? THREE.MathUtils.degToRad(device.gamma) : 0;
const orient = this.screenOrientation ? THREE.MathUtils.degToRad(this.screenOrientation) : 0;
this.setObjectQuaternion(this.object.quaternion, alpha, beta, gamma, orient);
if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) {
this.lastQuaternion.copy(this.object.quaternion);
this.dispatchEvent(this.changeEvent);
}
}
});
__publicField(this, "dispose", () => this.disconnect());
this.object = object;
this.object.rotation.reorder("YXZ");
this.connect();
}
}
exports.DeviceOrientationControls = DeviceOrientationControls;
//# sourceMappingURL=DeviceOrientationControls.cjs.map
File diff suppressed because one or more lines are too long
+29
View File
@@ -0,0 +1,29 @@
import { Camera } from 'three';
import { EventDispatcher } from './EventDispatcher';
import { StandardControlsEventMap } from './StandardControlsEventMap';
/**
* W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
*/
declare class DeviceOrientationControls extends EventDispatcher<StandardControlsEventMap> {
object: Camera;
private changeEvent;
private EPS;
enabled: boolean;
deviceOrientation: Partial<DeviceOrientationEvent>;
screenOrientation: string | number;
alphaOffset: number;
constructor(object: Camera);
private onDeviceOrientationChangeEvent;
private onScreenOrientationChangeEvent;
private zee;
private euler;
private q0;
private q1;
private setObjectQuaternion;
connect: () => void;
disconnect: () => void;
private lastQuaternion;
update: () => void;
dispose: () => void;
}
export { DeviceOrientationControls };
+87
View File
@@ -0,0 +1,87 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Euler, Quaternion, MathUtils } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
class DeviceOrientationControls extends EventDispatcher {
// radians
constructor(object) {
super();
__publicField(this, "object");
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "EPS", 1e-6);
__publicField(this, "enabled", true);
__publicField(this, "deviceOrientation", { alpha: 0, beta: 0, gamma: 0 });
__publicField(this, "screenOrientation", 0);
__publicField(this, "alphaOffset", 0);
__publicField(this, "onDeviceOrientationChangeEvent", (event) => {
this.deviceOrientation = event;
});
__publicField(this, "onScreenOrientationChangeEvent", () => {
this.screenOrientation = window.orientation || 0;
});
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
__publicField(this, "zee", new Vector3(0, 0, 1));
__publicField(this, "euler", new Euler());
__publicField(this, "q0", new Quaternion());
__publicField(this, "q1", new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)));
// - PI/2 around the x-axis
__publicField(this, "setObjectQuaternion", (quaternion, alpha, beta, gamma, orient) => {
this.euler.set(beta, alpha, -gamma, "YXZ");
quaternion.setFromEuler(this.euler);
quaternion.multiply(this.q1);
quaternion.multiply(this.q0.setFromAxisAngle(this.zee, -orient));
});
__publicField(this, "connect", () => {
this.onScreenOrientationChangeEvent();
if (window.DeviceOrientationEvent !== void 0 && // @ts-ignore
typeof window.DeviceOrientationEvent.requestPermission === "function") {
window.DeviceOrientationEvent.requestPermission().then((response) => {
if (response == "granted") {
window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
}
}).catch((error) => {
console.error("THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:", error);
});
} else {
window.addEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.addEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
}
this.enabled = true;
});
__publicField(this, "disconnect", () => {
window.removeEventListener("orientationchange", this.onScreenOrientationChangeEvent);
window.removeEventListener("deviceorientation", this.onDeviceOrientationChangeEvent);
this.enabled = false;
});
__publicField(this, "lastQuaternion", new Quaternion());
__publicField(this, "update", () => {
if (this.enabled === false)
return;
const device = this.deviceOrientation;
if (device) {
const alpha = device.alpha ? MathUtils.degToRad(device.alpha) + this.alphaOffset : 0;
const beta = device.beta ? MathUtils.degToRad(device.beta) : 0;
const gamma = device.gamma ? MathUtils.degToRad(device.gamma) : 0;
const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation) : 0;
this.setObjectQuaternion(this.object.quaternion, alpha, beta, gamma, orient);
if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) {
this.lastQuaternion.copy(this.object.quaternion);
this.dispatchEvent(this.changeEvent);
}
}
});
__publicField(this, "dispose", () => this.disconnect());
this.object = object;
this.object.rotation.reorder("YXZ");
this.connect();
}
}
export {
DeviceOrientationControls
};
//# sourceMappingURL=DeviceOrientationControls.js.map
File diff suppressed because one or more lines are too long
+184
View File
@@ -0,0 +1,184 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
class DragControls extends EventDispatcher.EventDispatcher {
constructor(_objects, _camera, _domElement) {
super();
__publicField(this, "enabled", true);
__publicField(this, "transformGroup", false);
__publicField(this, "_objects");
__publicField(this, "_camera");
__publicField(this, "_domElement");
__publicField(this, "_plane", new THREE.Plane());
__publicField(this, "_raycaster", new THREE.Raycaster());
__publicField(this, "_mouse", new THREE.Vector2());
__publicField(this, "_offset", new THREE.Vector3());
__publicField(this, "_intersection", new THREE.Vector3());
__publicField(this, "_worldPosition", new THREE.Vector3());
__publicField(this, "_inverseMatrix", new THREE.Matrix4());
__publicField(this, "_intersections", []);
__publicField(this, "_selected", null);
__publicField(this, "_hovered", null);
__publicField(this, "activate", () => {
this._domElement.addEventListener("pointermove", this.onPointerMove);
this._domElement.addEventListener("pointerdown", this.onPointerDown);
this._domElement.addEventListener("pointerup", this.onPointerCancel);
this._domElement.addEventListener("pointerleave", this.onPointerCancel);
this._domElement.addEventListener("touchmove", this.onTouchMove);
this._domElement.addEventListener("touchstart", this.onTouchStart);
this._domElement.addEventListener("touchend", this.onTouchEnd);
});
__publicField(this, "deactivate", () => {
this._domElement.removeEventListener("pointermove", this.onPointerMove);
this._domElement.removeEventListener("pointerdown", this.onPointerDown);
this._domElement.removeEventListener("pointerup", this.onPointerCancel);
this._domElement.removeEventListener("pointerleave", this.onPointerCancel);
this._domElement.removeEventListener("touchmove", this.onTouchMove);
this._domElement.removeEventListener("touchstart", this.onTouchStart);
this._domElement.removeEventListener("touchend", this.onTouchEnd);
this._domElement.style.cursor = "";
});
// TODO: confirm if this can be removed?
__publicField(this, "dispose", () => this.deactivate());
__publicField(this, "getObjects", () => this._objects);
__publicField(this, "getRaycaster", () => this._raycaster);
__publicField(this, "onMouseMove", (event) => {
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (event.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
this._raycaster.setFromCamera(this._mouse, this._camera);
if (this._selected && this.enabled) {
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection)) {
this._selected.position.copy(this._intersection.sub(this._offset).applyMatrix4(this._inverseMatrix));
}
this.dispatchEvent({ type: "drag", object: this._selected });
return;
}
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
const object = this._intersections[0].object;
this._plane.setFromNormalAndCoplanarPoint(
this._camera.getWorldDirection(this._plane.normal),
this._worldPosition.setFromMatrixPosition(object.matrixWorld)
);
if (this._hovered !== object) {
this.dispatchEvent({ type: "hoveron", object });
this._domElement.style.cursor = "pointer";
this._hovered = object;
}
} else {
if (this._hovered !== null) {
this.dispatchEvent({ type: "hoveroff", object: this._hovered });
this._domElement.style.cursor = "auto";
this._hovered = null;
}
}
});
__publicField(this, "onMouseDown", () => {
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
this._selected = this.transformGroup === true ? this._objects[0] : this._intersections[0].object;
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection) && this._selected.parent) {
this._inverseMatrix.copy(this._selected.parent.matrixWorld).invert();
this._offset.copy(this._intersection).sub(this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld));
}
this._domElement.style.cursor = "move";
this.dispatchEvent({ type: "dragstart", object: this._selected });
}
});
__publicField(this, "onMouseCancel", () => {
if (this._selected) {
this.dispatchEvent({ type: "dragend", object: this._selected });
this._selected = null;
}
this._domElement.style.cursor = this._hovered ? "pointer" : "auto";
});
__publicField(this, "onPointerMove", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseMove(event);
break;
}
});
__publicField(this, "onPointerDown", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseDown();
break;
}
});
__publicField(this, "onPointerCancel", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseCancel();
break;
}
});
__publicField(this, "onTouchMove", (event) => {
event.preventDefault();
const newEvent = event.changedTouches[0];
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (newEvent.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((newEvent.clientY - rect.top) / rect.height) * 2 + 1;
this._raycaster.setFromCamera(this._mouse, this._camera);
if (this._selected && this.enabled) {
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection)) {
this._selected.position.copy(this._intersection.sub(this._offset).applyMatrix4(this._inverseMatrix));
}
this.dispatchEvent({ type: "drag", object: this._selected });
return;
}
});
__publicField(this, "onTouchStart", (event) => {
event.preventDefault();
const newEvent = event.changedTouches[0];
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (newEvent.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((newEvent.clientY - rect.top) / rect.height) * 2 + 1;
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
this._selected = this.transformGroup === true ? this._objects[0] : this._intersections[0].object;
this._plane.setFromNormalAndCoplanarPoint(
this._camera.getWorldDirection(this._plane.normal),
this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld)
);
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection) && this._selected.parent) {
this._inverseMatrix.copy(this._selected.parent.matrixWorld).invert();
this._offset.copy(this._intersection).sub(this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld));
}
this._domElement.style.cursor = "move";
this.dispatchEvent({ type: "dragstart", object: this._selected });
}
});
__publicField(this, "onTouchEnd", (event) => {
event.preventDefault();
if (this._selected) {
this.dispatchEvent({ type: "dragend", object: this._selected });
this._selected = null;
}
this._domElement.style.cursor = "auto";
});
this._objects = _objects;
this._camera = _camera;
this._domElement = _domElement;
this.activate();
}
}
exports.DragControls = DragControls;
//# sourceMappingURL=DragControls.cjs.map
File diff suppressed because one or more lines are too long
+67
View File
@@ -0,0 +1,67 @@
import { Camera, Object3D, Raycaster } from 'three';
import { EventDispatcher } from './EventDispatcher';
export interface DragControlsEventMap {
/**
* Fires when the pointer is moved onto a 3D object, or onto one of its children.
*/
hoveron: {
object: Object3D;
};
/**
* Fires when the pointer is moved out of a 3D object.
*/
hoveroff: {
object: Object3D;
};
/**
* Fires when the user starts to drag a 3D object.
*/
dragstart: {
object: Object3D;
};
/**
* Fires when the user drags a 3D object.
*/
drag: {
object: Object3D;
};
/**
* Fires when the user has finished dragging a 3D object.
*/
dragend: {
object: Object3D;
};
}
declare class DragControls extends EventDispatcher<DragControlsEventMap> {
enabled: boolean;
transformGroup: boolean;
private _objects;
private _camera;
private _domElement;
private _plane;
private _raycaster;
private _mouse;
private _offset;
private _intersection;
private _worldPosition;
private _inverseMatrix;
private _intersections;
private _selected;
private _hovered;
constructor(_objects: Object3D[], _camera: Camera, _domElement: HTMLElement);
activate: () => void;
deactivate: () => void;
dispose: () => void;
getObjects: () => Object3D[];
getRaycaster: () => Raycaster;
private onMouseMove;
private onMouseDown;
private onMouseCancel;
private onPointerMove;
private onPointerDown;
private onPointerCancel;
private onTouchMove;
private onTouchStart;
private onTouchEnd;
}
export { DragControls };
+184
View File
@@ -0,0 +1,184 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Plane, Raycaster, Vector2, Vector3, Matrix4 } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
class DragControls extends EventDispatcher {
constructor(_objects, _camera, _domElement) {
super();
__publicField(this, "enabled", true);
__publicField(this, "transformGroup", false);
__publicField(this, "_objects");
__publicField(this, "_camera");
__publicField(this, "_domElement");
__publicField(this, "_plane", new Plane());
__publicField(this, "_raycaster", new Raycaster());
__publicField(this, "_mouse", new Vector2());
__publicField(this, "_offset", new Vector3());
__publicField(this, "_intersection", new Vector3());
__publicField(this, "_worldPosition", new Vector3());
__publicField(this, "_inverseMatrix", new Matrix4());
__publicField(this, "_intersections", []);
__publicField(this, "_selected", null);
__publicField(this, "_hovered", null);
__publicField(this, "activate", () => {
this._domElement.addEventListener("pointermove", this.onPointerMove);
this._domElement.addEventListener("pointerdown", this.onPointerDown);
this._domElement.addEventListener("pointerup", this.onPointerCancel);
this._domElement.addEventListener("pointerleave", this.onPointerCancel);
this._domElement.addEventListener("touchmove", this.onTouchMove);
this._domElement.addEventListener("touchstart", this.onTouchStart);
this._domElement.addEventListener("touchend", this.onTouchEnd);
});
__publicField(this, "deactivate", () => {
this._domElement.removeEventListener("pointermove", this.onPointerMove);
this._domElement.removeEventListener("pointerdown", this.onPointerDown);
this._domElement.removeEventListener("pointerup", this.onPointerCancel);
this._domElement.removeEventListener("pointerleave", this.onPointerCancel);
this._domElement.removeEventListener("touchmove", this.onTouchMove);
this._domElement.removeEventListener("touchstart", this.onTouchStart);
this._domElement.removeEventListener("touchend", this.onTouchEnd);
this._domElement.style.cursor = "";
});
// TODO: confirm if this can be removed?
__publicField(this, "dispose", () => this.deactivate());
__publicField(this, "getObjects", () => this._objects);
__publicField(this, "getRaycaster", () => this._raycaster);
__publicField(this, "onMouseMove", (event) => {
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (event.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
this._raycaster.setFromCamera(this._mouse, this._camera);
if (this._selected && this.enabled) {
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection)) {
this._selected.position.copy(this._intersection.sub(this._offset).applyMatrix4(this._inverseMatrix));
}
this.dispatchEvent({ type: "drag", object: this._selected });
return;
}
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
const object = this._intersections[0].object;
this._plane.setFromNormalAndCoplanarPoint(
this._camera.getWorldDirection(this._plane.normal),
this._worldPosition.setFromMatrixPosition(object.matrixWorld)
);
if (this._hovered !== object) {
this.dispatchEvent({ type: "hoveron", object });
this._domElement.style.cursor = "pointer";
this._hovered = object;
}
} else {
if (this._hovered !== null) {
this.dispatchEvent({ type: "hoveroff", object: this._hovered });
this._domElement.style.cursor = "auto";
this._hovered = null;
}
}
});
__publicField(this, "onMouseDown", () => {
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
this._selected = this.transformGroup === true ? this._objects[0] : this._intersections[0].object;
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection) && this._selected.parent) {
this._inverseMatrix.copy(this._selected.parent.matrixWorld).invert();
this._offset.copy(this._intersection).sub(this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld));
}
this._domElement.style.cursor = "move";
this.dispatchEvent({ type: "dragstart", object: this._selected });
}
});
__publicField(this, "onMouseCancel", () => {
if (this._selected) {
this.dispatchEvent({ type: "dragend", object: this._selected });
this._selected = null;
}
this._domElement.style.cursor = this._hovered ? "pointer" : "auto";
});
__publicField(this, "onPointerMove", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseMove(event);
break;
}
});
__publicField(this, "onPointerDown", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseDown();
break;
}
});
__publicField(this, "onPointerCancel", (event) => {
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseCancel();
break;
}
});
__publicField(this, "onTouchMove", (event) => {
event.preventDefault();
const newEvent = event.changedTouches[0];
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (newEvent.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((newEvent.clientY - rect.top) / rect.height) * 2 + 1;
this._raycaster.setFromCamera(this._mouse, this._camera);
if (this._selected && this.enabled) {
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection)) {
this._selected.position.copy(this._intersection.sub(this._offset).applyMatrix4(this._inverseMatrix));
}
this.dispatchEvent({ type: "drag", object: this._selected });
return;
}
});
__publicField(this, "onTouchStart", (event) => {
event.preventDefault();
const newEvent = event.changedTouches[0];
const rect = this._domElement.getBoundingClientRect();
this._mouse.x = (newEvent.clientX - rect.left) / rect.width * 2 - 1;
this._mouse.y = -((newEvent.clientY - rect.top) / rect.height) * 2 + 1;
this._intersections.length = 0;
this._raycaster.setFromCamera(this._mouse, this._camera);
this._raycaster.intersectObjects(this._objects, true, this._intersections);
if (this._intersections.length > 0) {
this._selected = this.transformGroup === true ? this._objects[0] : this._intersections[0].object;
this._plane.setFromNormalAndCoplanarPoint(
this._camera.getWorldDirection(this._plane.normal),
this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld)
);
if (this._raycaster.ray.intersectPlane(this._plane, this._intersection) && this._selected.parent) {
this._inverseMatrix.copy(this._selected.parent.matrixWorld).invert();
this._offset.copy(this._intersection).sub(this._worldPosition.setFromMatrixPosition(this._selected.matrixWorld));
}
this._domElement.style.cursor = "move";
this.dispatchEvent({ type: "dragstart", object: this._selected });
}
});
__publicField(this, "onTouchEnd", (event) => {
event.preventDefault();
if (this._selected) {
this.dispatchEvent({ type: "dragend", object: this._selected });
this._selected = null;
}
this._domElement.style.cursor = "auto";
});
this._objects = _objects;
this._camera = _camera;
this._domElement = _domElement;
this.activate();
}
}
export {
DragControls
};
//# sourceMappingURL=DragControls.js.map
File diff suppressed because one or more lines are too long
+78
View File
@@ -0,0 +1,78 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
class EventDispatcher {
constructor() {
// not defined in @types/three
__publicField(this, "_listeners");
}
/**
* Adds a listener to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
addEventListener(type, listener) {
if (this._listeners === void 0)
this._listeners = {};
const listeners = this._listeners;
if (listeners[type] === void 0) {
listeners[type] = [];
}
if (listeners[type].indexOf(listener) === -1) {
listeners[type].push(listener);
}
}
/**
* Checks if listener is added to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
hasEventListener(type, listener) {
if (this._listeners === void 0)
return false;
const listeners = this._listeners;
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
}
/**
* Removes a listener from an event type.
* @param type The type of the listener that gets removed.
* @param listener The listener function that gets removed.
*/
removeEventListener(type, listener) {
if (this._listeners === void 0)
return;
const listeners = this._listeners;
const listenerArray = listeners[type];
if (listenerArray !== void 0) {
const index = listenerArray.indexOf(listener);
if (index !== -1) {
listenerArray.splice(index, 1);
}
}
}
/**
* Fire an event type.
* @param event The event that gets fired.
*/
dispatchEvent(event) {
if (this._listeners === void 0)
return;
const listeners = this._listeners;
const listenerArray = listeners[event.type];
if (listenerArray !== void 0) {
event.target = this;
const array = listenerArray.slice(0);
for (let i = 0, l = array.length; i < l; i++) {
array[i].call(this, event);
}
event.target = null;
}
}
}
exports.EventDispatcher = EventDispatcher;
//# sourceMappingURL=EventDispatcher.cjs.map
File diff suppressed because one or more lines are too long
+41
View File
@@ -0,0 +1,41 @@
/**
* The minimal basic Event that can be dispatched by a {@link EventDispatcher<>}.
*/
export interface BaseEvent<TEventType extends string = string> {
readonly type: TEventType;
target: any;
}
/**
* The minimal expected contract of a fired Event that was dispatched by a {@link EventDispatcher<>}.
*/
export interface Event<TEventType extends string = string, TTarget = unknown> {
readonly type: TEventType;
readonly target: TTarget;
}
export type EventListener<TEventData, TEventType extends string, TTarget> = (event: TEventData & Event<TEventType, TTarget>) => void;
export declare class EventDispatcher<TEventMap extends {} = {}> {
private _listeners;
/**
* Adds a listener to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
addEventListener<T extends Extract<keyof TEventMap, string>>(type: T, listener: EventListener<TEventMap[T], T, this>): void;
/**
* Checks if listener is added to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
hasEventListener<T extends Extract<keyof TEventMap, string>>(type: T, listener: EventListener<TEventMap[T], T, this>): boolean;
/**
* Removes a listener from an event type.
* @param type The type of the listener that gets removed.
* @param listener The listener function that gets removed.
*/
removeEventListener<T extends Extract<keyof TEventMap, string>>(type: T, listener: EventListener<TEventMap[T], T, this>): void;
/**
* Fire an event type.
* @param event The event that gets fired.
*/
dispatchEvent<T extends Extract<keyof TEventMap, string>>(event: BaseEvent<T> & TEventMap[T]): void;
}
+78
View File
@@ -0,0 +1,78 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
class EventDispatcher {
constructor() {
// not defined in @types/three
__publicField(this, "_listeners");
}
/**
* Adds a listener to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
addEventListener(type, listener) {
if (this._listeners === void 0)
this._listeners = {};
const listeners = this._listeners;
if (listeners[type] === void 0) {
listeners[type] = [];
}
if (listeners[type].indexOf(listener) === -1) {
listeners[type].push(listener);
}
}
/**
* Checks if listener is added to an event type.
* @param type The type of event to listen to.
* @param listener The function that gets called when the event is fired.
*/
hasEventListener(type, listener) {
if (this._listeners === void 0)
return false;
const listeners = this._listeners;
return listeners[type] !== void 0 && listeners[type].indexOf(listener) !== -1;
}
/**
* Removes a listener from an event type.
* @param type The type of the listener that gets removed.
* @param listener The listener function that gets removed.
*/
removeEventListener(type, listener) {
if (this._listeners === void 0)
return;
const listeners = this._listeners;
const listenerArray = listeners[type];
if (listenerArray !== void 0) {
const index = listenerArray.indexOf(listener);
if (index !== -1) {
listenerArray.splice(index, 1);
}
}
}
/**
* Fire an event type.
* @param event The event that gets fired.
*/
dispatchEvent(event) {
if (this._listeners === void 0)
return;
const listeners = this._listeners;
const listenerArray = listeners[event.type];
if (listenerArray !== void 0) {
event.target = this;
const array = listenerArray.slice(0);
for (let i = 0, l = array.length; i < l; i++) {
array[i].call(this, event);
}
event.target = null;
}
}
}
export {
EventDispatcher
};
//# sourceMappingURL=EventDispatcher.js.map
File diff suppressed because one or more lines are too long
+231
View File
@@ -0,0 +1,231 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
const targetPosition = /* @__PURE__ */ new THREE.Vector3();
class FirstPersonControls extends EventDispatcher.EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement");
__publicField(this, "enabled", true);
__publicField(this, "movementSpeed", 1);
__publicField(this, "lookSpeed", 5e-3);
__publicField(this, "lookVertical", true);
__publicField(this, "autoForward", false);
__publicField(this, "activeLook", true);
__publicField(this, "heightSpeed", false);
__publicField(this, "heightCoef", 1);
__publicField(this, "heightMin", 0);
__publicField(this, "heightMax", 1);
__publicField(this, "constrainVertical", false);
__publicField(this, "verticalMin", 0);
__publicField(this, "verticalMax", Math.PI);
__publicField(this, "mouseDragOn", false);
// internals
__publicField(this, "autoSpeedFactor", 0);
__publicField(this, "mouseX", 0);
__publicField(this, "mouseY", 0);
__publicField(this, "moveForward", false);
__publicField(this, "moveBackward", false);
__publicField(this, "moveLeft", false);
__publicField(this, "moveRight", false);
__publicField(this, "moveUp", false);
__publicField(this, "moveDown", false);
__publicField(this, "viewHalfX", 0);
__publicField(this, "viewHalfY", 0);
__publicField(this, "lat", 0);
__publicField(this, "lon", 0);
__publicField(this, "lookDirection", new THREE.Vector3());
__publicField(this, "spherical", new THREE.Spherical());
__publicField(this, "target", new THREE.Vector3());
__publicField(this, "connect", (domElement) => {
domElement.setAttribute("tabindex", "-1");
domElement.style.touchAction = "none";
domElement.addEventListener("contextmenu", this.contextmenu);
domElement.addEventListener("mousemove", this.onMouseMove);
domElement.addEventListener("mousedown", this.onMouseDown);
domElement.addEventListener("mouseup", this.onMouseUp);
this.domElement = domElement;
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
this.handleResize();
});
__publicField(this, "dispose", () => {
var _a, _b, _c, _d;
(_a = this.domElement) == null ? void 0 : _a.removeEventListener("contextmenu", this.contextmenu);
(_b = this.domElement) == null ? void 0 : _b.removeEventListener("mousedown", this.onMouseDown);
(_c = this.domElement) == null ? void 0 : _c.removeEventListener("mousemove", this.onMouseMove);
(_d = this.domElement) == null ? void 0 : _d.removeEventListener("mouseup", this.onMouseUp);
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
});
__publicField(this, "handleResize", () => {
if (this.domElement) {
this.viewHalfX = this.domElement.offsetWidth / 2;
this.viewHalfY = this.domElement.offsetHeight / 2;
}
});
__publicField(this, "onMouseDown", (event) => {
var _a;
(_a = this.domElement) == null ? void 0 : _a.focus();
if (this.activeLook) {
switch (event.button) {
case 0:
this.moveForward = true;
break;
case 2:
this.moveBackward = true;
break;
}
}
this.mouseDragOn = true;
});
__publicField(this, "onMouseUp", (event) => {
if (this.activeLook) {
switch (event.button) {
case 0:
this.moveForward = false;
break;
case 2:
this.moveBackward = false;
break;
}
}
this.mouseDragOn = false;
});
__publicField(this, "onMouseMove", (event) => {
if (this.domElement) {
this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;
}
});
__publicField(this, "onKeyDown", (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = true;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = true;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = true;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = true;
break;
case "KeyR":
this.moveUp = true;
break;
case "KeyF":
this.moveDown = true;
break;
}
});
__publicField(this, "onKeyUp", (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = false;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = false;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = false;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = false;
break;
case "KeyR":
this.moveUp = false;
break;
case "KeyF":
this.moveDown = false;
break;
}
});
__publicField(this, "lookAt", (x, y, z) => {
if (x instanceof THREE.Vector3) {
this.target.copy(x);
} else if (y && z) {
this.target.set(x, y, z);
}
this.object.lookAt(this.target);
this.setOrientation();
return this;
});
__publicField(this, "update", (delta) => {
if (!this.enabled)
return;
if (this.heightSpeed) {
const y = THREE.MathUtils.clamp(this.object.position.y, this.heightMin, this.heightMax);
const heightDelta = y - this.heightMin;
this.autoSpeedFactor = delta * (heightDelta * this.heightCoef);
} else {
this.autoSpeedFactor = 0;
}
const actualMoveSpeed = delta * this.movementSpeed;
if (this.moveForward || this.autoForward && !this.moveBackward) {
this.object.translateZ(-(actualMoveSpeed + this.autoSpeedFactor));
}
if (this.moveBackward)
this.object.translateZ(actualMoveSpeed);
if (this.moveLeft)
this.object.translateX(-actualMoveSpeed);
if (this.moveRight)
this.object.translateX(actualMoveSpeed);
if (this.moveUp)
this.object.translateY(actualMoveSpeed);
if (this.moveDown)
this.object.translateY(-actualMoveSpeed);
let actualLookSpeed = delta * this.lookSpeed;
if (!this.activeLook) {
actualLookSpeed = 0;
}
let verticalLookRatio = 1;
if (this.constrainVertical) {
verticalLookRatio = Math.PI / (this.verticalMax - this.verticalMin);
}
this.lon -= this.mouseX * actualLookSpeed;
if (this.lookVertical)
this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;
this.lat = Math.max(-85, Math.min(85, this.lat));
let phi = THREE.MathUtils.degToRad(90 - this.lat);
const theta = THREE.MathUtils.degToRad(this.lon);
if (this.constrainVertical) {
phi = THREE.MathUtils.mapLinear(phi, 0, Math.PI, this.verticalMin, this.verticalMax);
}
const position = this.object.position;
targetPosition.setFromSphericalCoords(1, phi, theta).add(position);
this.object.lookAt(targetPosition);
});
__publicField(this, "contextmenu", (event) => event.preventDefault());
__publicField(this, "setOrientation", () => {
this.lookDirection.set(0, 0, -1).applyQuaternion(this.object.quaternion);
this.spherical.setFromVector3(this.lookDirection);
this.lat = 90 - THREE.MathUtils.radToDeg(this.spherical.phi);
this.lon = THREE.MathUtils.radToDeg(this.spherical.theta);
});
this.object = object;
this.domElement = domElement;
this.setOrientation();
if (domElement)
this.connect(domElement);
}
}
exports.FirstPersonControls = FirstPersonControls;
//# sourceMappingURL=FirstPersonControls.cjs.map
File diff suppressed because one or more lines are too long
+49
View File
@@ -0,0 +1,49 @@
import { Vector3, Camera } from 'three';
import { EventDispatcher } from './EventDispatcher';
export declare class FirstPersonControls extends EventDispatcher<{}> {
object: Camera;
domElement?: HTMLElement | null;
enabled: boolean;
movementSpeed: number;
lookSpeed: number;
lookVertical: boolean;
autoForward: boolean;
activeLook: boolean;
heightSpeed: boolean;
heightCoef: number;
heightMin: number;
heightMax: number;
constrainVertical: boolean;
verticalMin: number;
verticalMax: number;
mouseDragOn: boolean;
private autoSpeedFactor;
private mouseX;
private mouseY;
private moveForward;
private moveBackward;
private moveLeft;
private moveRight;
private moveUp;
private moveDown;
private viewHalfX;
private viewHalfY;
private lat;
private lon;
private lookDirection;
private spherical;
readonly target: Vector3;
constructor(object: Camera, domElement?: HTMLElement | null);
connect: (domElement: HTMLElement) => void;
dispose: () => void;
handleResize: () => void;
private onMouseDown;
private onMouseUp;
private onMouseMove;
private onKeyDown;
private onKeyUp;
lookAt: (x: Vector3 | number, y?: number, z?: number) => this;
update: (delta: number) => void;
private contextmenu;
private setOrientation;
}
+231
View File
@@ -0,0 +1,231 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Spherical, MathUtils } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
const targetPosition = /* @__PURE__ */ new Vector3();
class FirstPersonControls extends EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement");
__publicField(this, "enabled", true);
__publicField(this, "movementSpeed", 1);
__publicField(this, "lookSpeed", 5e-3);
__publicField(this, "lookVertical", true);
__publicField(this, "autoForward", false);
__publicField(this, "activeLook", true);
__publicField(this, "heightSpeed", false);
__publicField(this, "heightCoef", 1);
__publicField(this, "heightMin", 0);
__publicField(this, "heightMax", 1);
__publicField(this, "constrainVertical", false);
__publicField(this, "verticalMin", 0);
__publicField(this, "verticalMax", Math.PI);
__publicField(this, "mouseDragOn", false);
// internals
__publicField(this, "autoSpeedFactor", 0);
__publicField(this, "mouseX", 0);
__publicField(this, "mouseY", 0);
__publicField(this, "moveForward", false);
__publicField(this, "moveBackward", false);
__publicField(this, "moveLeft", false);
__publicField(this, "moveRight", false);
__publicField(this, "moveUp", false);
__publicField(this, "moveDown", false);
__publicField(this, "viewHalfX", 0);
__publicField(this, "viewHalfY", 0);
__publicField(this, "lat", 0);
__publicField(this, "lon", 0);
__publicField(this, "lookDirection", new Vector3());
__publicField(this, "spherical", new Spherical());
__publicField(this, "target", new Vector3());
__publicField(this, "connect", (domElement) => {
domElement.setAttribute("tabindex", "-1");
domElement.style.touchAction = "none";
domElement.addEventListener("contextmenu", this.contextmenu);
domElement.addEventListener("mousemove", this.onMouseMove);
domElement.addEventListener("mousedown", this.onMouseDown);
domElement.addEventListener("mouseup", this.onMouseUp);
this.domElement = domElement;
window.addEventListener("keydown", this.onKeyDown);
window.addEventListener("keyup", this.onKeyUp);
this.handleResize();
});
__publicField(this, "dispose", () => {
var _a, _b, _c, _d;
(_a = this.domElement) == null ? void 0 : _a.removeEventListener("contextmenu", this.contextmenu);
(_b = this.domElement) == null ? void 0 : _b.removeEventListener("mousedown", this.onMouseDown);
(_c = this.domElement) == null ? void 0 : _c.removeEventListener("mousemove", this.onMouseMove);
(_d = this.domElement) == null ? void 0 : _d.removeEventListener("mouseup", this.onMouseUp);
window.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("keyup", this.onKeyUp);
});
__publicField(this, "handleResize", () => {
if (this.domElement) {
this.viewHalfX = this.domElement.offsetWidth / 2;
this.viewHalfY = this.domElement.offsetHeight / 2;
}
});
__publicField(this, "onMouseDown", (event) => {
var _a;
(_a = this.domElement) == null ? void 0 : _a.focus();
if (this.activeLook) {
switch (event.button) {
case 0:
this.moveForward = true;
break;
case 2:
this.moveBackward = true;
break;
}
}
this.mouseDragOn = true;
});
__publicField(this, "onMouseUp", (event) => {
if (this.activeLook) {
switch (event.button) {
case 0:
this.moveForward = false;
break;
case 2:
this.moveBackward = false;
break;
}
}
this.mouseDragOn = false;
});
__publicField(this, "onMouseMove", (event) => {
if (this.domElement) {
this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;
}
});
__publicField(this, "onKeyDown", (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = true;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = true;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = true;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = true;
break;
case "KeyR":
this.moveUp = true;
break;
case "KeyF":
this.moveDown = true;
break;
}
});
__publicField(this, "onKeyUp", (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = false;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = false;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = false;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = false;
break;
case "KeyR":
this.moveUp = false;
break;
case "KeyF":
this.moveDown = false;
break;
}
});
__publicField(this, "lookAt", (x, y, z) => {
if (x instanceof Vector3) {
this.target.copy(x);
} else if (y && z) {
this.target.set(x, y, z);
}
this.object.lookAt(this.target);
this.setOrientation();
return this;
});
__publicField(this, "update", (delta) => {
if (!this.enabled)
return;
if (this.heightSpeed) {
const y = MathUtils.clamp(this.object.position.y, this.heightMin, this.heightMax);
const heightDelta = y - this.heightMin;
this.autoSpeedFactor = delta * (heightDelta * this.heightCoef);
} else {
this.autoSpeedFactor = 0;
}
const actualMoveSpeed = delta * this.movementSpeed;
if (this.moveForward || this.autoForward && !this.moveBackward) {
this.object.translateZ(-(actualMoveSpeed + this.autoSpeedFactor));
}
if (this.moveBackward)
this.object.translateZ(actualMoveSpeed);
if (this.moveLeft)
this.object.translateX(-actualMoveSpeed);
if (this.moveRight)
this.object.translateX(actualMoveSpeed);
if (this.moveUp)
this.object.translateY(actualMoveSpeed);
if (this.moveDown)
this.object.translateY(-actualMoveSpeed);
let actualLookSpeed = delta * this.lookSpeed;
if (!this.activeLook) {
actualLookSpeed = 0;
}
let verticalLookRatio = 1;
if (this.constrainVertical) {
verticalLookRatio = Math.PI / (this.verticalMax - this.verticalMin);
}
this.lon -= this.mouseX * actualLookSpeed;
if (this.lookVertical)
this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;
this.lat = Math.max(-85, Math.min(85, this.lat));
let phi = MathUtils.degToRad(90 - this.lat);
const theta = MathUtils.degToRad(this.lon);
if (this.constrainVertical) {
phi = MathUtils.mapLinear(phi, 0, Math.PI, this.verticalMin, this.verticalMax);
}
const position = this.object.position;
targetPosition.setFromSphericalCoords(1, phi, theta).add(position);
this.object.lookAt(targetPosition);
});
__publicField(this, "contextmenu", (event) => event.preventDefault());
__publicField(this, "setOrientation", () => {
this.lookDirection.set(0, 0, -1).applyQuaternion(this.object.quaternion);
this.spherical.setFromVector3(this.lookDirection);
this.lat = 90 - MathUtils.radToDeg(this.spherical.phi);
this.lon = MathUtils.radToDeg(this.spherical.theta);
});
this.object = object;
this.domElement = domElement;
this.setOrientation();
if (domElement)
this.connect(domElement);
}
}
export {
FirstPersonControls
};
//# sourceMappingURL=FirstPersonControls.js.map
File diff suppressed because one or more lines are too long
+250
View File
@@ -0,0 +1,250 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
function contextmenu(event) {
event.preventDefault();
}
class FlyControls extends EventDispatcher.EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement", null);
__publicField(this, "movementSpeed", 1);
__publicField(this, "rollSpeed", 5e-3);
__publicField(this, "dragToLook", false);
__publicField(this, "autoForward", false);
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "EPS", 1e-6);
__publicField(this, "tmpQuaternion", new THREE.Quaternion());
__publicField(this, "mouseStatus", 0);
__publicField(this, "movementSpeedMultiplier", 1);
__publicField(this, "moveState", {
up: 0,
down: 0,
left: 0,
right: 0,
forward: 0,
back: 0,
pitchUp: 0,
pitchDown: 0,
yawLeft: 0,
yawRight: 0,
rollLeft: 0,
rollRight: 0
});
__publicField(this, "moveVector", new THREE.Vector3(0, 0, 0));
__publicField(this, "rotationVector", new THREE.Vector3(0, 0, 0));
__publicField(this, "keydown", (event) => {
if (event.altKey) {
return;
}
switch (event.code) {
case "ShiftLeft":
case "ShiftRight":
this.movementSpeedMultiplier = 0.1;
break;
case "KeyW":
this.moveState.forward = 1;
break;
case "KeyS":
this.moveState.back = 1;
break;
case "KeyA":
this.moveState.left = 1;
break;
case "KeyD":
this.moveState.right = 1;
break;
case "KeyR":
this.moveState.up = 1;
break;
case "KeyF":
this.moveState.down = 1;
break;
case "ArrowUp":
this.moveState.pitchUp = 1;
break;
case "ArrowDown":
this.moveState.pitchDown = 1;
break;
case "ArrowLeft":
this.moveState.yawLeft = 1;
break;
case "ArrowRight":
this.moveState.yawRight = 1;
break;
case "KeyQ":
this.moveState.rollLeft = 1;
break;
case "KeyE":
this.moveState.rollRight = 1;
break;
}
this.updateMovementVector();
this.updateRotationVector();
});
__publicField(this, "keyup", (event) => {
switch (event.code) {
case "ShiftLeft":
case "ShiftRight":
this.movementSpeedMultiplier = 1;
break;
case "KeyW":
this.moveState.forward = 0;
break;
case "KeyS":
this.moveState.back = 0;
break;
case "KeyA":
this.moveState.left = 0;
break;
case "KeyD":
this.moveState.right = 0;
break;
case "KeyR":
this.moveState.up = 0;
break;
case "KeyF":
this.moveState.down = 0;
break;
case "ArrowUp":
this.moveState.pitchUp = 0;
break;
case "ArrowDown":
this.moveState.pitchDown = 0;
break;
case "ArrowLeft":
this.moveState.yawLeft = 0;
break;
case "ArrowRight":
this.moveState.yawRight = 0;
break;
case "KeyQ":
this.moveState.rollLeft = 0;
break;
case "KeyE":
this.moveState.rollRight = 0;
break;
}
this.updateMovementVector();
this.updateRotationVector();
});
__publicField(this, "pointerdown", (event) => {
if (this.dragToLook) {
this.mouseStatus++;
} else {
switch (event.button) {
case 0:
this.moveState.forward = 1;
break;
case 2:
this.moveState.back = 1;
break;
}
this.updateMovementVector();
}
});
__publicField(this, "pointermove", (event) => {
if (!this.dragToLook || this.mouseStatus > 0) {
const container = this.getContainerDimensions();
const halfWidth = container.size[0] / 2;
const halfHeight = container.size[1] / 2;
this.moveState.yawLeft = -(event.pageX - container.offset[0] - halfWidth) / halfWidth;
this.moveState.pitchDown = (event.pageY - container.offset[1] - halfHeight) / halfHeight;
this.updateRotationVector();
}
});
__publicField(this, "pointerup", (event) => {
if (this.dragToLook) {
this.mouseStatus--;
this.moveState.yawLeft = this.moveState.pitchDown = 0;
} else {
switch (event.button) {
case 0:
this.moveState.forward = 0;
break;
case 2:
this.moveState.back = 0;
break;
}
this.updateMovementVector();
}
this.updateRotationVector();
});
__publicField(this, "lastQuaternion", new THREE.Quaternion());
__publicField(this, "lastPosition", new THREE.Vector3());
__publicField(this, "update", (delta) => {
const moveMult = delta * this.movementSpeed;
const rotMult = delta * this.rollSpeed;
this.object.translateX(this.moveVector.x * moveMult);
this.object.translateY(this.moveVector.y * moveMult);
this.object.translateZ(this.moveVector.z * moveMult);
this.tmpQuaternion.set(this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1).normalize();
this.object.quaternion.multiply(this.tmpQuaternion);
if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || 8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) {
this.dispatchEvent(this.changeEvent);
this.lastQuaternion.copy(this.object.quaternion);
this.lastPosition.copy(this.object.position);
}
});
__publicField(this, "updateMovementVector", () => {
const forward = this.moveState.forward || this.autoForward && !this.moveState.back ? 1 : 0;
this.moveVector.x = -this.moveState.left + this.moveState.right;
this.moveVector.y = -this.moveState.down + this.moveState.up;
this.moveVector.z = -forward + this.moveState.back;
});
__publicField(this, "updateRotationVector", () => {
this.rotationVector.x = -this.moveState.pitchDown + this.moveState.pitchUp;
this.rotationVector.y = -this.moveState.yawRight + this.moveState.yawLeft;
this.rotationVector.z = -this.moveState.rollRight + this.moveState.rollLeft;
});
__publicField(this, "getContainerDimensions", () => {
if (this.domElement != document && !(this.domElement instanceof Document)) {
return {
size: [this.domElement.offsetWidth, this.domElement.offsetHeight],
offset: [this.domElement.offsetLeft, this.domElement.offsetTop]
};
} else {
return {
size: [window.innerWidth, window.innerHeight],
offset: [0, 0]
};
}
});
// https://github.com/mrdoob/three.js/issues/20575
__publicField(this, "connect", (domElement) => {
this.domElement = domElement;
if (!(domElement instanceof Document)) {
domElement.setAttribute("tabindex", -1);
}
this.domElement.addEventListener("contextmenu", contextmenu);
this.domElement.addEventListener("pointermove", this.pointermove);
this.domElement.addEventListener("pointerdown", this.pointerdown);
this.domElement.addEventListener("pointerup", this.pointerup);
window.addEventListener("keydown", this.keydown);
window.addEventListener("keyup", this.keyup);
});
__publicField(this, "dispose", () => {
this.domElement.removeEventListener("contextmenu", contextmenu);
this.domElement.removeEventListener("pointermove", this.pointermove);
this.domElement.removeEventListener("pointerdown", this.pointerdown);
this.domElement.removeEventListener("pointerup", this.pointerup);
window.removeEventListener("keydown", this.keydown);
window.removeEventListener("keyup", this.keyup);
});
this.object = object;
if (domElement !== void 0)
this.connect(domElement);
this.updateMovementVector();
this.updateRotationVector();
}
}
exports.FlyControls = FlyControls;
//# sourceMappingURL=FlyControls.cjs.map
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
import { Camera } from 'three';
import { EventDispatcher } from './EventDispatcher';
export interface FlyControlsEventMap {
/**
* Fires when the camera has been transformed by the controls.
*/
change: {};
}
declare class FlyControls extends EventDispatcher<FlyControlsEventMap> {
object: Camera;
domElement: HTMLElement | Document;
movementSpeed: number;
rollSpeed: number;
dragToLook: boolean;
autoForward: boolean;
private changeEvent;
private EPS;
private tmpQuaternion;
private mouseStatus;
private movementSpeedMultiplier;
private moveState;
private moveVector;
private rotationVector;
constructor(object: Camera, domElement?: HTMLElement | Document);
private keydown;
private keyup;
private pointerdown;
private pointermove;
private pointerup;
private lastQuaternion;
private lastPosition;
update: (delta: number) => void;
private updateMovementVector;
private updateRotationVector;
private getContainerDimensions;
connect: (domElement: HTMLElement | Document) => void;
dispose: () => void;
}
export { FlyControls };
+250
View File
@@ -0,0 +1,250 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Quaternion, Vector3 } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
function contextmenu(event) {
event.preventDefault();
}
class FlyControls extends EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement", null);
__publicField(this, "movementSpeed", 1);
__publicField(this, "rollSpeed", 5e-3);
__publicField(this, "dragToLook", false);
__publicField(this, "autoForward", false);
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "EPS", 1e-6);
__publicField(this, "tmpQuaternion", new Quaternion());
__publicField(this, "mouseStatus", 0);
__publicField(this, "movementSpeedMultiplier", 1);
__publicField(this, "moveState", {
up: 0,
down: 0,
left: 0,
right: 0,
forward: 0,
back: 0,
pitchUp: 0,
pitchDown: 0,
yawLeft: 0,
yawRight: 0,
rollLeft: 0,
rollRight: 0
});
__publicField(this, "moveVector", new Vector3(0, 0, 0));
__publicField(this, "rotationVector", new Vector3(0, 0, 0));
__publicField(this, "keydown", (event) => {
if (event.altKey) {
return;
}
switch (event.code) {
case "ShiftLeft":
case "ShiftRight":
this.movementSpeedMultiplier = 0.1;
break;
case "KeyW":
this.moveState.forward = 1;
break;
case "KeyS":
this.moveState.back = 1;
break;
case "KeyA":
this.moveState.left = 1;
break;
case "KeyD":
this.moveState.right = 1;
break;
case "KeyR":
this.moveState.up = 1;
break;
case "KeyF":
this.moveState.down = 1;
break;
case "ArrowUp":
this.moveState.pitchUp = 1;
break;
case "ArrowDown":
this.moveState.pitchDown = 1;
break;
case "ArrowLeft":
this.moveState.yawLeft = 1;
break;
case "ArrowRight":
this.moveState.yawRight = 1;
break;
case "KeyQ":
this.moveState.rollLeft = 1;
break;
case "KeyE":
this.moveState.rollRight = 1;
break;
}
this.updateMovementVector();
this.updateRotationVector();
});
__publicField(this, "keyup", (event) => {
switch (event.code) {
case "ShiftLeft":
case "ShiftRight":
this.movementSpeedMultiplier = 1;
break;
case "KeyW":
this.moveState.forward = 0;
break;
case "KeyS":
this.moveState.back = 0;
break;
case "KeyA":
this.moveState.left = 0;
break;
case "KeyD":
this.moveState.right = 0;
break;
case "KeyR":
this.moveState.up = 0;
break;
case "KeyF":
this.moveState.down = 0;
break;
case "ArrowUp":
this.moveState.pitchUp = 0;
break;
case "ArrowDown":
this.moveState.pitchDown = 0;
break;
case "ArrowLeft":
this.moveState.yawLeft = 0;
break;
case "ArrowRight":
this.moveState.yawRight = 0;
break;
case "KeyQ":
this.moveState.rollLeft = 0;
break;
case "KeyE":
this.moveState.rollRight = 0;
break;
}
this.updateMovementVector();
this.updateRotationVector();
});
__publicField(this, "pointerdown", (event) => {
if (this.dragToLook) {
this.mouseStatus++;
} else {
switch (event.button) {
case 0:
this.moveState.forward = 1;
break;
case 2:
this.moveState.back = 1;
break;
}
this.updateMovementVector();
}
});
__publicField(this, "pointermove", (event) => {
if (!this.dragToLook || this.mouseStatus > 0) {
const container = this.getContainerDimensions();
const halfWidth = container.size[0] / 2;
const halfHeight = container.size[1] / 2;
this.moveState.yawLeft = -(event.pageX - container.offset[0] - halfWidth) / halfWidth;
this.moveState.pitchDown = (event.pageY - container.offset[1] - halfHeight) / halfHeight;
this.updateRotationVector();
}
});
__publicField(this, "pointerup", (event) => {
if (this.dragToLook) {
this.mouseStatus--;
this.moveState.yawLeft = this.moveState.pitchDown = 0;
} else {
switch (event.button) {
case 0:
this.moveState.forward = 0;
break;
case 2:
this.moveState.back = 0;
break;
}
this.updateMovementVector();
}
this.updateRotationVector();
});
__publicField(this, "lastQuaternion", new Quaternion());
__publicField(this, "lastPosition", new Vector3());
__publicField(this, "update", (delta) => {
const moveMult = delta * this.movementSpeed;
const rotMult = delta * this.rollSpeed;
this.object.translateX(this.moveVector.x * moveMult);
this.object.translateY(this.moveVector.y * moveMult);
this.object.translateZ(this.moveVector.z * moveMult);
this.tmpQuaternion.set(this.rotationVector.x * rotMult, this.rotationVector.y * rotMult, this.rotationVector.z * rotMult, 1).normalize();
this.object.quaternion.multiply(this.tmpQuaternion);
if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || 8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > this.EPS) {
this.dispatchEvent(this.changeEvent);
this.lastQuaternion.copy(this.object.quaternion);
this.lastPosition.copy(this.object.position);
}
});
__publicField(this, "updateMovementVector", () => {
const forward = this.moveState.forward || this.autoForward && !this.moveState.back ? 1 : 0;
this.moveVector.x = -this.moveState.left + this.moveState.right;
this.moveVector.y = -this.moveState.down + this.moveState.up;
this.moveVector.z = -forward + this.moveState.back;
});
__publicField(this, "updateRotationVector", () => {
this.rotationVector.x = -this.moveState.pitchDown + this.moveState.pitchUp;
this.rotationVector.y = -this.moveState.yawRight + this.moveState.yawLeft;
this.rotationVector.z = -this.moveState.rollRight + this.moveState.rollLeft;
});
__publicField(this, "getContainerDimensions", () => {
if (this.domElement != document && !(this.domElement instanceof Document)) {
return {
size: [this.domElement.offsetWidth, this.domElement.offsetHeight],
offset: [this.domElement.offsetLeft, this.domElement.offsetTop]
};
} else {
return {
size: [window.innerWidth, window.innerHeight],
offset: [0, 0]
};
}
});
// https://github.com/mrdoob/three.js/issues/20575
__publicField(this, "connect", (domElement) => {
this.domElement = domElement;
if (!(domElement instanceof Document)) {
domElement.setAttribute("tabindex", -1);
}
this.domElement.addEventListener("contextmenu", contextmenu);
this.domElement.addEventListener("pointermove", this.pointermove);
this.domElement.addEventListener("pointerdown", this.pointerdown);
this.domElement.addEventListener("pointerup", this.pointerup);
window.addEventListener("keydown", this.keydown);
window.addEventListener("keyup", this.keyup);
});
__publicField(this, "dispose", () => {
this.domElement.removeEventListener("contextmenu", contextmenu);
this.domElement.removeEventListener("pointermove", this.pointermove);
this.domElement.removeEventListener("pointerdown", this.pointerdown);
this.domElement.removeEventListener("pointerup", this.pointerup);
window.removeEventListener("keydown", this.keydown);
window.removeEventListener("keyup", this.keyup);
});
this.object = object;
if (domElement !== void 0)
this.connect(domElement);
this.updateMovementVector();
this.updateRotationVector();
}
}
export {
FlyControls
};
//# sourceMappingURL=FlyControls.js.map
File diff suppressed because one or more lines are too long
+882
View File
@@ -0,0 +1,882 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
const _ray = /* @__PURE__ */ new THREE.Ray();
const _plane = /* @__PURE__ */ new THREE.Plane();
const TILT_LIMIT = Math.cos(70 * (Math.PI / 180));
const moduloWrapAround = (offset, capacity) => (offset % capacity + capacity) % capacity;
class OrbitControls extends EventDispatcher.EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement");
// Set to false to disable this control
__publicField(this, "enabled", true);
// "target" sets the location of focus, where the object orbits around
__publicField(this, "target", new THREE.Vector3());
// How far you can dolly in and out ( PerspectiveCamera only )
__publicField(this, "minDistance", 0);
__publicField(this, "maxDistance", Infinity);
// How far you can zoom in and out ( OrthographicCamera only )
__publicField(this, "minZoom", 0);
__publicField(this, "maxZoom", Infinity);
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
__publicField(this, "minPolarAngle", 0);
// radians
__publicField(this, "maxPolarAngle", Math.PI);
// radians
// How far you can orbit horizontally, upper and lower limits.
// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )
__publicField(this, "minAzimuthAngle", -Infinity);
// radians
__publicField(this, "maxAzimuthAngle", Infinity);
// radians
// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
__publicField(this, "enableDamping", false);
__publicField(this, "dampingFactor", 0.05);
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
// Set to false to disable zooming
__publicField(this, "enableZoom", true);
__publicField(this, "zoomSpeed", 1);
// Set to false to disable rotating
__publicField(this, "enableRotate", true);
__publicField(this, "rotateSpeed", 1);
// Set to false to disable panning
__publicField(this, "enablePan", true);
__publicField(this, "panSpeed", 1);
__publicField(this, "screenSpacePanning", true);
// if false, pan orthogonal to world-space direction camera.up
__publicField(this, "keyPanSpeed", 7);
// pixels moved per arrow key push
__publicField(this, "zoomToCursor", false);
// Set to true to automatically rotate around the target
// If auto-rotate is enabled, you must call controls.update() in your animation loop
__publicField(this, "autoRotate", false);
__publicField(this, "autoRotateSpeed", 2);
// 30 seconds per orbit when fps is 60
__publicField(this, "reverseOrbit", false);
// true if you want to reverse the orbit to mouse drag from left to right = orbits left
__publicField(this, "reverseHorizontalOrbit", false);
// true if you want to reverse the horizontal orbit direction
__publicField(this, "reverseVerticalOrbit", false);
// true if you want to reverse the vertical orbit direction
// The four arrow keys
__publicField(this, "keys", { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" });
// Mouse buttons
__publicField(this, "mouseButtons", {
LEFT: THREE.MOUSE.ROTATE,
MIDDLE: THREE.MOUSE.DOLLY,
RIGHT: THREE.MOUSE.PAN
});
// Touch fingers
__publicField(this, "touches", { ONE: THREE.TOUCH.ROTATE, TWO: THREE.TOUCH.DOLLY_PAN });
__publicField(this, "target0");
__publicField(this, "position0");
__publicField(this, "zoom0");
// the target DOM element for key events
__publicField(this, "_domElementKeyEvents", null);
__publicField(this, "getPolarAngle");
__publicField(this, "getAzimuthalAngle");
__publicField(this, "setPolarAngle");
__publicField(this, "setAzimuthalAngle");
__publicField(this, "getDistance");
// Not used in most scenarios, however they can be useful for specific use cases
__publicField(this, "getZoomScale");
__publicField(this, "listenToKeyEvents");
__publicField(this, "stopListenToKeyEvents");
__publicField(this, "saveState");
__publicField(this, "reset");
__publicField(this, "update");
__publicField(this, "connect");
__publicField(this, "dispose");
// Dolly in programmatically
__publicField(this, "dollyIn");
// Dolly out programmatically
__publicField(this, "dollyOut");
// Get the current scale
__publicField(this, "getScale");
// Set the current scale (these are not used in most scenarios, however they can be useful for specific use cases)
__publicField(this, "setScale");
this.object = object;
this.domElement = domElement;
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
this.getPolarAngle = () => spherical.phi;
this.getAzimuthalAngle = () => spherical.theta;
this.setPolarAngle = (value) => {
let phi = moduloWrapAround(value, 2 * Math.PI);
let currentPhi = spherical.phi;
if (currentPhi < 0)
currentPhi += 2 * Math.PI;
if (phi < 0)
phi += 2 * Math.PI;
let phiDist = Math.abs(phi - currentPhi);
if (2 * Math.PI - phiDist < phiDist) {
if (phi < currentPhi) {
phi += 2 * Math.PI;
} else {
currentPhi += 2 * Math.PI;
}
}
sphericalDelta.phi = phi - currentPhi;
scope.update();
};
this.setAzimuthalAngle = (value) => {
let theta = moduloWrapAround(value, 2 * Math.PI);
let currentTheta = spherical.theta;
if (currentTheta < 0)
currentTheta += 2 * Math.PI;
if (theta < 0)
theta += 2 * Math.PI;
let thetaDist = Math.abs(theta - currentTheta);
if (2 * Math.PI - thetaDist < thetaDist) {
if (theta < currentTheta) {
theta += 2 * Math.PI;
} else {
currentTheta += 2 * Math.PI;
}
}
sphericalDelta.theta = theta - currentTheta;
scope.update();
};
this.getDistance = () => scope.object.position.distanceTo(scope.target);
this.listenToKeyEvents = (domElement2) => {
domElement2.addEventListener("keydown", onKeyDown);
this._domElementKeyEvents = domElement2;
};
this.stopListenToKeyEvents = () => {
this._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
this._domElementKeyEvents = null;
};
this.saveState = () => {
scope.target0.copy(scope.target);
scope.position0.copy(scope.object.position);
scope.zoom0 = scope.object.zoom;
};
this.reset = () => {
scope.target.copy(scope.target0);
scope.object.position.copy(scope.position0);
scope.object.zoom = scope.zoom0;
scope.object.updateProjectionMatrix();
scope.dispatchEvent(changeEvent);
scope.update();
state = STATE.NONE;
};
this.update = (() => {
const offset = new THREE.Vector3();
const up = new THREE.Vector3(0, 1, 0);
const quat = new THREE.Quaternion().setFromUnitVectors(object.up, up);
const quatInverse = quat.clone().invert();
const lastPosition = new THREE.Vector3();
const lastQuaternion = new THREE.Quaternion();
const twoPI = 2 * Math.PI;
return function update() {
const position = scope.object.position;
quat.setFromUnitVectors(object.up, up);
quatInverse.copy(quat).invert();
offset.copy(position).sub(scope.target);
offset.applyQuaternion(quat);
spherical.setFromVector3(offset);
if (scope.autoRotate && state === STATE.NONE) {
rotateLeft(getAutoRotationAngle());
}
if (scope.enableDamping) {
spherical.theta += sphericalDelta.theta * scope.dampingFactor;
spherical.phi += sphericalDelta.phi * scope.dampingFactor;
} else {
spherical.theta += sphericalDelta.theta;
spherical.phi += sphericalDelta.phi;
}
let min = scope.minAzimuthAngle;
let max = scope.maxAzimuthAngle;
if (isFinite(min) && isFinite(max)) {
if (min < -Math.PI)
min += twoPI;
else if (min > Math.PI)
min -= twoPI;
if (max < -Math.PI)
max += twoPI;
else if (max > Math.PI)
max -= twoPI;
if (min <= max) {
spherical.theta = Math.max(min, Math.min(max, spherical.theta));
} else {
spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
}
}
spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
spherical.makeSafe();
if (scope.enableDamping === true) {
scope.target.addScaledVector(panOffset, scope.dampingFactor);
} else {
scope.target.add(panOffset);
}
if (scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera) {
spherical.radius = clampDistance(spherical.radius);
} else {
spherical.radius = clampDistance(spherical.radius * scale);
}
offset.setFromSpherical(spherical);
offset.applyQuaternion(quatInverse);
position.copy(scope.target).add(offset);
if (!scope.object.matrixAutoUpdate)
scope.object.updateMatrix();
scope.object.lookAt(scope.target);
if (scope.enableDamping === true) {
sphericalDelta.theta *= 1 - scope.dampingFactor;
sphericalDelta.phi *= 1 - scope.dampingFactor;
panOffset.multiplyScalar(1 - scope.dampingFactor);
} else {
sphericalDelta.set(0, 0, 0);
panOffset.set(0, 0, 0);
}
let zoomChanged = false;
if (scope.zoomToCursor && performCursorZoom) {
let newRadius = null;
if (scope.object instanceof THREE.PerspectiveCamera && scope.object.isPerspectiveCamera) {
const prevRadius = offset.length();
newRadius = clampDistance(prevRadius * scale);
const radiusDelta = prevRadius - newRadius;
scope.object.position.addScaledVector(dollyDirection, radiusDelta);
scope.object.updateMatrixWorld();
} else if (scope.object.isOrthographicCamera) {
const mouseBefore = new THREE.Vector3(mouse.x, mouse.y, 0);
mouseBefore.unproject(scope.object);
scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale));
scope.object.updateProjectionMatrix();
zoomChanged = true;
const mouseAfter = new THREE.Vector3(mouse.x, mouse.y, 0);
mouseAfter.unproject(scope.object);
scope.object.position.sub(mouseAfter).add(mouseBefore);
scope.object.updateMatrixWorld();
newRadius = offset.length();
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.");
scope.zoomToCursor = false;
}
if (newRadius !== null) {
if (scope.screenSpacePanning) {
scope.target.set(0, 0, -1).transformDirection(scope.object.matrix).multiplyScalar(newRadius).add(scope.object.position);
} else {
_ray.origin.copy(scope.object.position);
_ray.direction.set(0, 0, -1).transformDirection(scope.object.matrix);
if (Math.abs(scope.object.up.dot(_ray.direction)) < TILT_LIMIT) {
object.lookAt(scope.target);
} else {
_plane.setFromNormalAndCoplanarPoint(scope.object.up, scope.target);
_ray.intersectPlane(_plane, scope.target);
}
}
}
} else if (scope.object instanceof THREE.OrthographicCamera && scope.object.isOrthographicCamera) {
zoomChanged = scale !== 1;
if (zoomChanged) {
scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale));
scope.object.updateProjectionMatrix();
}
}
scale = 1;
performCursorZoom = false;
if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
scope.dispatchEvent(changeEvent);
lastPosition.copy(scope.object.position);
lastQuaternion.copy(scope.object.quaternion);
zoomChanged = false;
return true;
}
return false;
};
})();
this.connect = (domElement2) => {
scope.domElement = domElement2;
scope.domElement.style.touchAction = "none";
scope.domElement.addEventListener("contextmenu", onContextMenu);
scope.domElement.addEventListener("pointerdown", onPointerDown);
scope.domElement.addEventListener("pointercancel", onPointerUp);
scope.domElement.addEventListener("wheel", onMouseWheel);
};
this.dispose = () => {
var _a, _b, _c, _d, _e, _f;
if (scope.domElement) {
scope.domElement.style.touchAction = "auto";
}
(_a = scope.domElement) == null ? void 0 : _a.removeEventListener("contextmenu", onContextMenu);
(_b = scope.domElement) == null ? void 0 : _b.removeEventListener("pointerdown", onPointerDown);
(_c = scope.domElement) == null ? void 0 : _c.removeEventListener("pointercancel", onPointerUp);
(_d = scope.domElement) == null ? void 0 : _d.removeEventListener("wheel", onMouseWheel);
(_e = scope.domElement) == null ? void 0 : _e.ownerDocument.removeEventListener("pointermove", onPointerMove);
(_f = scope.domElement) == null ? void 0 : _f.ownerDocument.removeEventListener("pointerup", onPointerUp);
if (scope._domElementKeyEvents !== null) {
scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
}
};
const scope = this;
const changeEvent = { type: "change" };
const startEvent = { type: "start" };
const endEvent = { type: "end" };
const STATE = {
NONE: -1,
ROTATE: 0,
DOLLY: 1,
PAN: 2,
TOUCH_ROTATE: 3,
TOUCH_PAN: 4,
TOUCH_DOLLY_PAN: 5,
TOUCH_DOLLY_ROTATE: 6
};
let state = STATE.NONE;
const EPS = 1e-6;
const spherical = new THREE.Spherical();
const sphericalDelta = new THREE.Spherical();
let scale = 1;
const panOffset = new THREE.Vector3();
const rotateStart = new THREE.Vector2();
const rotateEnd = new THREE.Vector2();
const rotateDelta = new THREE.Vector2();
const panStart = new THREE.Vector2();
const panEnd = new THREE.Vector2();
const panDelta = new THREE.Vector2();
const dollyStart = new THREE.Vector2();
const dollyEnd = new THREE.Vector2();
const dollyDelta = new THREE.Vector2();
const dollyDirection = new THREE.Vector3();
const mouse = new THREE.Vector2();
let performCursorZoom = false;
const pointers = [];
const pointerPositions = {};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow(0.95, scope.zoomSpeed);
}
function rotateLeft(angle) {
if (scope.reverseOrbit || scope.reverseHorizontalOrbit) {
sphericalDelta.theta += angle;
} else {
sphericalDelta.theta -= angle;
}
}
function rotateUp(angle) {
if (scope.reverseOrbit || scope.reverseVerticalOrbit) {
sphericalDelta.phi += angle;
} else {
sphericalDelta.phi -= angle;
}
}
const panLeft = (() => {
const v = new THREE.Vector3();
return function panLeft2(distance, objectMatrix) {
v.setFromMatrixColumn(objectMatrix, 0);
v.multiplyScalar(-distance);
panOffset.add(v);
};
})();
const panUp = (() => {
const v = new THREE.Vector3();
return function panUp2(distance, objectMatrix) {
if (scope.screenSpacePanning === true) {
v.setFromMatrixColumn(objectMatrix, 1);
} else {
v.setFromMatrixColumn(objectMatrix, 0);
v.crossVectors(scope.object.up, v);
}
v.multiplyScalar(distance);
panOffset.add(v);
};
})();
const pan = (() => {
const offset = new THREE.Vector3();
return function pan2(deltaX, deltaY) {
const element = scope.domElement;
if (element && scope.object instanceof THREE.PerspectiveCamera && scope.object.isPerspectiveCamera) {
const position = scope.object.position;
offset.copy(position).sub(scope.target);
let targetDistance = offset.length();
targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
} else if (element && scope.object instanceof THREE.OrthographicCamera && scope.object.isOrthographicCamera) {
panLeft(
deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth,
scope.object.matrix
);
panUp(
deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight,
scope.object.matrix
);
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
scope.enablePan = false;
}
};
})();
function setScale(newScale) {
if (scope.object instanceof THREE.PerspectiveCamera && scope.object.isPerspectiveCamera || scope.object instanceof THREE.OrthographicCamera && scope.object.isOrthographicCamera) {
scale = newScale;
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
scope.enableZoom = false;
}
}
function dollyOut(dollyScale) {
setScale(scale / dollyScale);
}
function dollyIn(dollyScale) {
setScale(scale * dollyScale);
}
function updateMouseParameters(event) {
if (!scope.zoomToCursor || !scope.domElement) {
return;
}
performCursorZoom = true;
const rect = scope.domElement.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const w = rect.width;
const h = rect.height;
mouse.x = x / w * 2 - 1;
mouse.y = -(y / h) * 2 + 1;
dollyDirection.set(mouse.x, mouse.y, 1).unproject(scope.object).sub(scope.object.position).normalize();
}
function clampDistance(dist) {
return Math.max(scope.minDistance, Math.min(scope.maxDistance, dist));
}
function handleMouseDownRotate(event) {
rotateStart.set(event.clientX, event.clientY);
}
function handleMouseDownDolly(event) {
updateMouseParameters(event);
dollyStart.set(event.clientX, event.clientY);
}
function handleMouseDownPan(event) {
panStart.set(event.clientX, event.clientY);
}
function handleMouseMoveRotate(event) {
rotateEnd.set(event.clientX, event.clientY);
rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
const element = scope.domElement;
if (element) {
rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
}
rotateStart.copy(rotateEnd);
scope.update();
}
function handleMouseMoveDolly(event) {
dollyEnd.set(event.clientX, event.clientY);
dollyDelta.subVectors(dollyEnd, dollyStart);
if (dollyDelta.y > 0) {
dollyOut(getZoomScale());
} else if (dollyDelta.y < 0) {
dollyIn(getZoomScale());
}
dollyStart.copy(dollyEnd);
scope.update();
}
function handleMouseMovePan(event) {
panEnd.set(event.clientX, event.clientY);
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
scope.update();
}
function handleMouseWheel(event) {
updateMouseParameters(event);
if (event.deltaY < 0) {
dollyIn(getZoomScale());
} else if (event.deltaY > 0) {
dollyOut(getZoomScale());
}
scope.update();
}
function handleKeyDown(event) {
let needsUpdate = false;
switch (event.code) {
case scope.keys.UP:
pan(0, scope.keyPanSpeed);
needsUpdate = true;
break;
case scope.keys.BOTTOM:
pan(0, -scope.keyPanSpeed);
needsUpdate = true;
break;
case scope.keys.LEFT:
pan(scope.keyPanSpeed, 0);
needsUpdate = true;
break;
case scope.keys.RIGHT:
pan(-scope.keyPanSpeed, 0);
needsUpdate = true;
break;
}
if (needsUpdate) {
event.preventDefault();
scope.update();
}
}
function handleTouchStartRotate() {
if (pointers.length == 1) {
rotateStart.set(pointers[0].pageX, pointers[0].pageY);
} else {
const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
rotateStart.set(x, y);
}
}
function handleTouchStartPan() {
if (pointers.length == 1) {
panStart.set(pointers[0].pageX, pointers[0].pageY);
} else {
const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
panStart.set(x, y);
}
}
function handleTouchStartDolly() {
const dx = pointers[0].pageX - pointers[1].pageX;
const dy = pointers[0].pageY - pointers[1].pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
}
function handleTouchStartDollyPan() {
if (scope.enableZoom)
handleTouchStartDolly();
if (scope.enablePan)
handleTouchStartPan();
}
function handleTouchStartDollyRotate() {
if (scope.enableZoom)
handleTouchStartDolly();
if (scope.enableRotate)
handleTouchStartRotate();
}
function handleTouchMoveRotate(event) {
if (pointers.length == 1) {
rotateEnd.set(event.pageX, event.pageY);
} else {
const position = getSecondPointerPosition(event);
const x = 0.5 * (event.pageX + position.x);
const y = 0.5 * (event.pageY + position.y);
rotateEnd.set(x, y);
}
rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
const element = scope.domElement;
if (element) {
rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
}
rotateStart.copy(rotateEnd);
}
function handleTouchMovePan(event) {
if (pointers.length == 1) {
panEnd.set(event.pageX, event.pageY);
} else {
const position = getSecondPointerPosition(event);
const x = 0.5 * (event.pageX + position.x);
const y = 0.5 * (event.pageY + position.y);
panEnd.set(x, y);
}
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
}
function handleTouchMoveDolly(event) {
const position = getSecondPointerPosition(event);
const dx = event.pageX - position.x;
const dy = event.pageY - position.y;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyEnd.set(0, distance);
dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
dollyOut(dollyDelta.y);
dollyStart.copy(dollyEnd);
}
function handleTouchMoveDollyPan(event) {
if (scope.enableZoom)
handleTouchMoveDolly(event);
if (scope.enablePan)
handleTouchMovePan(event);
}
function handleTouchMoveDollyRotate(event) {
if (scope.enableZoom)
handleTouchMoveDolly(event);
if (scope.enableRotate)
handleTouchMoveRotate(event);
}
function onPointerDown(event) {
var _a, _b;
if (scope.enabled === false)
return;
if (pointers.length === 0) {
(_a = scope.domElement) == null ? void 0 : _a.ownerDocument.addEventListener("pointermove", onPointerMove);
(_b = scope.domElement) == null ? void 0 : _b.ownerDocument.addEventListener("pointerup", onPointerUp);
}
addPointer(event);
if (event.pointerType === "touch") {
onTouchStart(event);
} else {
onMouseDown(event);
}
}
function onPointerMove(event) {
if (scope.enabled === false)
return;
if (event.pointerType === "touch") {
onTouchMove(event);
} else {
onMouseMove(event);
}
}
function onPointerUp(event) {
var _a, _b, _c;
removePointer(event);
if (pointers.length === 0) {
(_a = scope.domElement) == null ? void 0 : _a.releasePointerCapture(event.pointerId);
(_b = scope.domElement) == null ? void 0 : _b.ownerDocument.removeEventListener("pointermove", onPointerMove);
(_c = scope.domElement) == null ? void 0 : _c.ownerDocument.removeEventListener("pointerup", onPointerUp);
}
scope.dispatchEvent(endEvent);
state = STATE.NONE;
}
function onMouseDown(event) {
let mouseAction;
switch (event.button) {
case 0:
mouseAction = scope.mouseButtons.LEFT;
break;
case 1:
mouseAction = scope.mouseButtons.MIDDLE;
break;
case 2:
mouseAction = scope.mouseButtons.RIGHT;
break;
default:
mouseAction = -1;
}
switch (mouseAction) {
case THREE.MOUSE.DOLLY:
if (scope.enableZoom === false)
return;
handleMouseDownDolly(event);
state = STATE.DOLLY;
break;
case THREE.MOUSE.ROTATE:
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (scope.enablePan === false)
return;
handleMouseDownPan(event);
state = STATE.PAN;
} else {
if (scope.enableRotate === false)
return;
handleMouseDownRotate(event);
state = STATE.ROTATE;
}
break;
case THREE.MOUSE.PAN:
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (scope.enableRotate === false)
return;
handleMouseDownRotate(event);
state = STATE.ROTATE;
} else {
if (scope.enablePan === false)
return;
handleMouseDownPan(event);
state = STATE.PAN;
}
break;
default:
state = STATE.NONE;
}
if (state !== STATE.NONE) {
scope.dispatchEvent(startEvent);
}
}
function onMouseMove(event) {
if (scope.enabled === false)
return;
switch (state) {
case STATE.ROTATE:
if (scope.enableRotate === false)
return;
handleMouseMoveRotate(event);
break;
case STATE.DOLLY:
if (scope.enableZoom === false)
return;
handleMouseMoveDolly(event);
break;
case STATE.PAN:
if (scope.enablePan === false)
return;
handleMouseMovePan(event);
break;
}
}
function onMouseWheel(event) {
if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE) {
return;
}
event.preventDefault();
scope.dispatchEvent(startEvent);
handleMouseWheel(event);
scope.dispatchEvent(endEvent);
}
function onKeyDown(event) {
if (scope.enabled === false || scope.enablePan === false)
return;
handleKeyDown(event);
}
function onTouchStart(event) {
trackPointer(event);
switch (pointers.length) {
case 1:
switch (scope.touches.ONE) {
case THREE.TOUCH.ROTATE:
if (scope.enableRotate === false)
return;
handleTouchStartRotate();
state = STATE.TOUCH_ROTATE;
break;
case THREE.TOUCH.PAN:
if (scope.enablePan === false)
return;
handleTouchStartPan();
state = STATE.TOUCH_PAN;
break;
default:
state = STATE.NONE;
}
break;
case 2:
switch (scope.touches.TWO) {
case THREE.TOUCH.DOLLY_PAN:
if (scope.enableZoom === false && scope.enablePan === false)
return;
handleTouchStartDollyPan();
state = STATE.TOUCH_DOLLY_PAN;
break;
case THREE.TOUCH.DOLLY_ROTATE:
if (scope.enableZoom === false && scope.enableRotate === false)
return;
handleTouchStartDollyRotate();
state = STATE.TOUCH_DOLLY_ROTATE;
break;
default:
state = STATE.NONE;
}
break;
default:
state = STATE.NONE;
}
if (state !== STATE.NONE) {
scope.dispatchEvent(startEvent);
}
}
function onTouchMove(event) {
trackPointer(event);
switch (state) {
case STATE.TOUCH_ROTATE:
if (scope.enableRotate === false)
return;
handleTouchMoveRotate(event);
scope.update();
break;
case STATE.TOUCH_PAN:
if (scope.enablePan === false)
return;
handleTouchMovePan(event);
scope.update();
break;
case STATE.TOUCH_DOLLY_PAN:
if (scope.enableZoom === false && scope.enablePan === false)
return;
handleTouchMoveDollyPan(event);
scope.update();
break;
case STATE.TOUCH_DOLLY_ROTATE:
if (scope.enableZoom === false && scope.enableRotate === false)
return;
handleTouchMoveDollyRotate(event);
scope.update();
break;
default:
state = STATE.NONE;
}
}
function onContextMenu(event) {
if (scope.enabled === false)
return;
event.preventDefault();
}
function addPointer(event) {
pointers.push(event);
}
function removePointer(event) {
delete pointerPositions[event.pointerId];
for (let i = 0; i < pointers.length; i++) {
if (pointers[i].pointerId == event.pointerId) {
pointers.splice(i, 1);
return;
}
}
}
function trackPointer(event) {
let position = pointerPositions[event.pointerId];
if (position === void 0) {
position = new THREE.Vector2();
pointerPositions[event.pointerId] = position;
}
position.set(event.pageX, event.pageY);
}
function getSecondPointerPosition(event) {
const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
return pointerPositions[pointer.pointerId];
}
this.dollyIn = (dollyScale = getZoomScale()) => {
dollyIn(dollyScale);
scope.update();
};
this.dollyOut = (dollyScale = getZoomScale()) => {
dollyOut(dollyScale);
scope.update();
};
this.getScale = () => {
return scale;
};
this.setScale = (newScale) => {
setScale(newScale);
scope.update();
};
this.getZoomScale = () => {
return getZoomScale();
};
if (domElement !== void 0)
this.connect(domElement);
this.update();
}
}
class MapControls extends OrbitControls {
constructor(object, domElement) {
super(object, domElement);
this.screenSpacePanning = false;
this.mouseButtons.LEFT = THREE.MOUSE.PAN;
this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE;
this.touches.ONE = THREE.TOUCH.PAN;
this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;
}
}
exports.MapControls = MapControls;
exports.OrbitControls = OrbitControls;
//# sourceMappingURL=OrbitControls.cjs.map
File diff suppressed because one or more lines are too long
+74
View File
@@ -0,0 +1,74 @@
import { MOUSE, OrthographicCamera, PerspectiveCamera, TOUCH, Vector3 } from 'three';
import { EventDispatcher } from './EventDispatcher';
import { StandardControlsEventMap } from './StandardControlsEventMap';
declare class OrbitControls extends EventDispatcher<StandardControlsEventMap> {
object: PerspectiveCamera | OrthographicCamera;
domElement: HTMLElement | undefined;
enabled: boolean;
target: Vector3;
minDistance: number;
maxDistance: number;
minZoom: number;
maxZoom: number;
minPolarAngle: number;
maxPolarAngle: number;
minAzimuthAngle: number;
maxAzimuthAngle: number;
enableDamping: boolean;
dampingFactor: number;
enableZoom: boolean;
zoomSpeed: number;
enableRotate: boolean;
rotateSpeed: number;
enablePan: boolean;
panSpeed: number;
screenSpacePanning: boolean;
keyPanSpeed: number;
zoomToCursor: boolean;
autoRotate: boolean;
autoRotateSpeed: number;
reverseOrbit: boolean;
reverseHorizontalOrbit: boolean;
reverseVerticalOrbit: boolean;
keys: {
LEFT: string;
UP: string;
RIGHT: string;
BOTTOM: string;
};
mouseButtons: Partial<{
LEFT: MOUSE;
MIDDLE: MOUSE;
RIGHT: MOUSE;
}>;
touches: Partial<{
ONE: TOUCH;
TWO: TOUCH;
}>;
target0: Vector3;
position0: Vector3;
zoom0: number;
_domElementKeyEvents: any;
getPolarAngle: () => number;
getAzimuthalAngle: () => number;
setPolarAngle: (x: number) => void;
setAzimuthalAngle: (x: number) => void;
getDistance: () => number;
getZoomScale: () => number;
listenToKeyEvents: (domElement: HTMLElement) => void;
stopListenToKeyEvents: () => void;
saveState: () => void;
reset: () => void;
update: () => void;
connect: (domElement: HTMLElement) => void;
dispose: () => void;
dollyIn: (dollyScale?: number) => void;
dollyOut: (dollyScale?: number) => void;
getScale: () => number;
setScale: (newScale: number) => void;
constructor(object: PerspectiveCamera | OrthographicCamera, domElement?: HTMLElement);
}
declare class MapControls extends OrbitControls {
constructor(object: PerspectiveCamera | OrthographicCamera, domElement?: HTMLElement);
}
export { OrbitControls, MapControls };
+882
View File
@@ -0,0 +1,882 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, MOUSE, TOUCH, Quaternion, PerspectiveCamera, OrthographicCamera, Spherical, Vector2, Ray, Plane } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
const _ray = /* @__PURE__ */ new Ray();
const _plane = /* @__PURE__ */ new Plane();
const TILT_LIMIT = Math.cos(70 * (Math.PI / 180));
const moduloWrapAround = (offset, capacity) => (offset % capacity + capacity) % capacity;
class OrbitControls extends EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "object");
__publicField(this, "domElement");
// Set to false to disable this control
__publicField(this, "enabled", true);
// "target" sets the location of focus, where the object orbits around
__publicField(this, "target", new Vector3());
// How far you can dolly in and out ( PerspectiveCamera only )
__publicField(this, "minDistance", 0);
__publicField(this, "maxDistance", Infinity);
// How far you can zoom in and out ( OrthographicCamera only )
__publicField(this, "minZoom", 0);
__publicField(this, "maxZoom", Infinity);
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
__publicField(this, "minPolarAngle", 0);
// radians
__publicField(this, "maxPolarAngle", Math.PI);
// radians
// How far you can orbit horizontally, upper and lower limits.
// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )
__publicField(this, "minAzimuthAngle", -Infinity);
// radians
__publicField(this, "maxAzimuthAngle", Infinity);
// radians
// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
__publicField(this, "enableDamping", false);
__publicField(this, "dampingFactor", 0.05);
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
// Set to false to disable zooming
__publicField(this, "enableZoom", true);
__publicField(this, "zoomSpeed", 1);
// Set to false to disable rotating
__publicField(this, "enableRotate", true);
__publicField(this, "rotateSpeed", 1);
// Set to false to disable panning
__publicField(this, "enablePan", true);
__publicField(this, "panSpeed", 1);
__publicField(this, "screenSpacePanning", true);
// if false, pan orthogonal to world-space direction camera.up
__publicField(this, "keyPanSpeed", 7);
// pixels moved per arrow key push
__publicField(this, "zoomToCursor", false);
// Set to true to automatically rotate around the target
// If auto-rotate is enabled, you must call controls.update() in your animation loop
__publicField(this, "autoRotate", false);
__publicField(this, "autoRotateSpeed", 2);
// 30 seconds per orbit when fps is 60
__publicField(this, "reverseOrbit", false);
// true if you want to reverse the orbit to mouse drag from left to right = orbits left
__publicField(this, "reverseHorizontalOrbit", false);
// true if you want to reverse the horizontal orbit direction
__publicField(this, "reverseVerticalOrbit", false);
// true if you want to reverse the vertical orbit direction
// The four arrow keys
__publicField(this, "keys", { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" });
// Mouse buttons
__publicField(this, "mouseButtons", {
LEFT: MOUSE.ROTATE,
MIDDLE: MOUSE.DOLLY,
RIGHT: MOUSE.PAN
});
// Touch fingers
__publicField(this, "touches", { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN });
__publicField(this, "target0");
__publicField(this, "position0");
__publicField(this, "zoom0");
// the target DOM element for key events
__publicField(this, "_domElementKeyEvents", null);
__publicField(this, "getPolarAngle");
__publicField(this, "getAzimuthalAngle");
__publicField(this, "setPolarAngle");
__publicField(this, "setAzimuthalAngle");
__publicField(this, "getDistance");
// Not used in most scenarios, however they can be useful for specific use cases
__publicField(this, "getZoomScale");
__publicField(this, "listenToKeyEvents");
__publicField(this, "stopListenToKeyEvents");
__publicField(this, "saveState");
__publicField(this, "reset");
__publicField(this, "update");
__publicField(this, "connect");
__publicField(this, "dispose");
// Dolly in programmatically
__publicField(this, "dollyIn");
// Dolly out programmatically
__publicField(this, "dollyOut");
// Get the current scale
__publicField(this, "getScale");
// Set the current scale (these are not used in most scenarios, however they can be useful for specific use cases)
__publicField(this, "setScale");
this.object = object;
this.domElement = domElement;
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
this.getPolarAngle = () => spherical.phi;
this.getAzimuthalAngle = () => spherical.theta;
this.setPolarAngle = (value) => {
let phi = moduloWrapAround(value, 2 * Math.PI);
let currentPhi = spherical.phi;
if (currentPhi < 0)
currentPhi += 2 * Math.PI;
if (phi < 0)
phi += 2 * Math.PI;
let phiDist = Math.abs(phi - currentPhi);
if (2 * Math.PI - phiDist < phiDist) {
if (phi < currentPhi) {
phi += 2 * Math.PI;
} else {
currentPhi += 2 * Math.PI;
}
}
sphericalDelta.phi = phi - currentPhi;
scope.update();
};
this.setAzimuthalAngle = (value) => {
let theta = moduloWrapAround(value, 2 * Math.PI);
let currentTheta = spherical.theta;
if (currentTheta < 0)
currentTheta += 2 * Math.PI;
if (theta < 0)
theta += 2 * Math.PI;
let thetaDist = Math.abs(theta - currentTheta);
if (2 * Math.PI - thetaDist < thetaDist) {
if (theta < currentTheta) {
theta += 2 * Math.PI;
} else {
currentTheta += 2 * Math.PI;
}
}
sphericalDelta.theta = theta - currentTheta;
scope.update();
};
this.getDistance = () => scope.object.position.distanceTo(scope.target);
this.listenToKeyEvents = (domElement2) => {
domElement2.addEventListener("keydown", onKeyDown);
this._domElementKeyEvents = domElement2;
};
this.stopListenToKeyEvents = () => {
this._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
this._domElementKeyEvents = null;
};
this.saveState = () => {
scope.target0.copy(scope.target);
scope.position0.copy(scope.object.position);
scope.zoom0 = scope.object.zoom;
};
this.reset = () => {
scope.target.copy(scope.target0);
scope.object.position.copy(scope.position0);
scope.object.zoom = scope.zoom0;
scope.object.updateProjectionMatrix();
scope.dispatchEvent(changeEvent);
scope.update();
state = STATE.NONE;
};
this.update = (() => {
const offset = new Vector3();
const up = new Vector3(0, 1, 0);
const quat = new Quaternion().setFromUnitVectors(object.up, up);
const quatInverse = quat.clone().invert();
const lastPosition = new Vector3();
const lastQuaternion = new Quaternion();
const twoPI = 2 * Math.PI;
return function update() {
const position = scope.object.position;
quat.setFromUnitVectors(object.up, up);
quatInverse.copy(quat).invert();
offset.copy(position).sub(scope.target);
offset.applyQuaternion(quat);
spherical.setFromVector3(offset);
if (scope.autoRotate && state === STATE.NONE) {
rotateLeft(getAutoRotationAngle());
}
if (scope.enableDamping) {
spherical.theta += sphericalDelta.theta * scope.dampingFactor;
spherical.phi += sphericalDelta.phi * scope.dampingFactor;
} else {
spherical.theta += sphericalDelta.theta;
spherical.phi += sphericalDelta.phi;
}
let min = scope.minAzimuthAngle;
let max = scope.maxAzimuthAngle;
if (isFinite(min) && isFinite(max)) {
if (min < -Math.PI)
min += twoPI;
else if (min > Math.PI)
min -= twoPI;
if (max < -Math.PI)
max += twoPI;
else if (max > Math.PI)
max -= twoPI;
if (min <= max) {
spherical.theta = Math.max(min, Math.min(max, spherical.theta));
} else {
spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
}
}
spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
spherical.makeSafe();
if (scope.enableDamping === true) {
scope.target.addScaledVector(panOffset, scope.dampingFactor);
} else {
scope.target.add(panOffset);
}
if (scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera) {
spherical.radius = clampDistance(spherical.radius);
} else {
spherical.radius = clampDistance(spherical.radius * scale);
}
offset.setFromSpherical(spherical);
offset.applyQuaternion(quatInverse);
position.copy(scope.target).add(offset);
if (!scope.object.matrixAutoUpdate)
scope.object.updateMatrix();
scope.object.lookAt(scope.target);
if (scope.enableDamping === true) {
sphericalDelta.theta *= 1 - scope.dampingFactor;
sphericalDelta.phi *= 1 - scope.dampingFactor;
panOffset.multiplyScalar(1 - scope.dampingFactor);
} else {
sphericalDelta.set(0, 0, 0);
panOffset.set(0, 0, 0);
}
let zoomChanged = false;
if (scope.zoomToCursor && performCursorZoom) {
let newRadius = null;
if (scope.object instanceof PerspectiveCamera && scope.object.isPerspectiveCamera) {
const prevRadius = offset.length();
newRadius = clampDistance(prevRadius * scale);
const radiusDelta = prevRadius - newRadius;
scope.object.position.addScaledVector(dollyDirection, radiusDelta);
scope.object.updateMatrixWorld();
} else if (scope.object.isOrthographicCamera) {
const mouseBefore = new Vector3(mouse.x, mouse.y, 0);
mouseBefore.unproject(scope.object);
scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale));
scope.object.updateProjectionMatrix();
zoomChanged = true;
const mouseAfter = new Vector3(mouse.x, mouse.y, 0);
mouseAfter.unproject(scope.object);
scope.object.position.sub(mouseAfter).add(mouseBefore);
scope.object.updateMatrixWorld();
newRadius = offset.length();
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.");
scope.zoomToCursor = false;
}
if (newRadius !== null) {
if (scope.screenSpacePanning) {
scope.target.set(0, 0, -1).transformDirection(scope.object.matrix).multiplyScalar(newRadius).add(scope.object.position);
} else {
_ray.origin.copy(scope.object.position);
_ray.direction.set(0, 0, -1).transformDirection(scope.object.matrix);
if (Math.abs(scope.object.up.dot(_ray.direction)) < TILT_LIMIT) {
object.lookAt(scope.target);
} else {
_plane.setFromNormalAndCoplanarPoint(scope.object.up, scope.target);
_ray.intersectPlane(_plane, scope.target);
}
}
}
} else if (scope.object instanceof OrthographicCamera && scope.object.isOrthographicCamera) {
zoomChanged = scale !== 1;
if (zoomChanged) {
scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / scale));
scope.object.updateProjectionMatrix();
}
}
scale = 1;
performCursorZoom = false;
if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
scope.dispatchEvent(changeEvent);
lastPosition.copy(scope.object.position);
lastQuaternion.copy(scope.object.quaternion);
zoomChanged = false;
return true;
}
return false;
};
})();
this.connect = (domElement2) => {
scope.domElement = domElement2;
scope.domElement.style.touchAction = "none";
scope.domElement.addEventListener("contextmenu", onContextMenu);
scope.domElement.addEventListener("pointerdown", onPointerDown);
scope.domElement.addEventListener("pointercancel", onPointerUp);
scope.domElement.addEventListener("wheel", onMouseWheel);
};
this.dispose = () => {
var _a, _b, _c, _d, _e, _f;
if (scope.domElement) {
scope.domElement.style.touchAction = "auto";
}
(_a = scope.domElement) == null ? void 0 : _a.removeEventListener("contextmenu", onContextMenu);
(_b = scope.domElement) == null ? void 0 : _b.removeEventListener("pointerdown", onPointerDown);
(_c = scope.domElement) == null ? void 0 : _c.removeEventListener("pointercancel", onPointerUp);
(_d = scope.domElement) == null ? void 0 : _d.removeEventListener("wheel", onMouseWheel);
(_e = scope.domElement) == null ? void 0 : _e.ownerDocument.removeEventListener("pointermove", onPointerMove);
(_f = scope.domElement) == null ? void 0 : _f.ownerDocument.removeEventListener("pointerup", onPointerUp);
if (scope._domElementKeyEvents !== null) {
scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
}
};
const scope = this;
const changeEvent = { type: "change" };
const startEvent = { type: "start" };
const endEvent = { type: "end" };
const STATE = {
NONE: -1,
ROTATE: 0,
DOLLY: 1,
PAN: 2,
TOUCH_ROTATE: 3,
TOUCH_PAN: 4,
TOUCH_DOLLY_PAN: 5,
TOUCH_DOLLY_ROTATE: 6
};
let state = STATE.NONE;
const EPS = 1e-6;
const spherical = new Spherical();
const sphericalDelta = new Spherical();
let scale = 1;
const panOffset = new Vector3();
const rotateStart = new Vector2();
const rotateEnd = new Vector2();
const rotateDelta = new Vector2();
const panStart = new Vector2();
const panEnd = new Vector2();
const panDelta = new Vector2();
const dollyStart = new Vector2();
const dollyEnd = new Vector2();
const dollyDelta = new Vector2();
const dollyDirection = new Vector3();
const mouse = new Vector2();
let performCursorZoom = false;
const pointers = [];
const pointerPositions = {};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow(0.95, scope.zoomSpeed);
}
function rotateLeft(angle) {
if (scope.reverseOrbit || scope.reverseHorizontalOrbit) {
sphericalDelta.theta += angle;
} else {
sphericalDelta.theta -= angle;
}
}
function rotateUp(angle) {
if (scope.reverseOrbit || scope.reverseVerticalOrbit) {
sphericalDelta.phi += angle;
} else {
sphericalDelta.phi -= angle;
}
}
const panLeft = (() => {
const v = new Vector3();
return function panLeft2(distance, objectMatrix) {
v.setFromMatrixColumn(objectMatrix, 0);
v.multiplyScalar(-distance);
panOffset.add(v);
};
})();
const panUp = (() => {
const v = new Vector3();
return function panUp2(distance, objectMatrix) {
if (scope.screenSpacePanning === true) {
v.setFromMatrixColumn(objectMatrix, 1);
} else {
v.setFromMatrixColumn(objectMatrix, 0);
v.crossVectors(scope.object.up, v);
}
v.multiplyScalar(distance);
panOffset.add(v);
};
})();
const pan = (() => {
const offset = new Vector3();
return function pan2(deltaX, deltaY) {
const element = scope.domElement;
if (element && scope.object instanceof PerspectiveCamera && scope.object.isPerspectiveCamera) {
const position = scope.object.position;
offset.copy(position).sub(scope.target);
let targetDistance = offset.length();
targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
} else if (element && scope.object instanceof OrthographicCamera && scope.object.isOrthographicCamera) {
panLeft(
deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth,
scope.object.matrix
);
panUp(
deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight,
scope.object.matrix
);
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
scope.enablePan = false;
}
};
})();
function setScale(newScale) {
if (scope.object instanceof PerspectiveCamera && scope.object.isPerspectiveCamera || scope.object instanceof OrthographicCamera && scope.object.isOrthographicCamera) {
scale = newScale;
} else {
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
scope.enableZoom = false;
}
}
function dollyOut(dollyScale) {
setScale(scale / dollyScale);
}
function dollyIn(dollyScale) {
setScale(scale * dollyScale);
}
function updateMouseParameters(event) {
if (!scope.zoomToCursor || !scope.domElement) {
return;
}
performCursorZoom = true;
const rect = scope.domElement.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const w = rect.width;
const h = rect.height;
mouse.x = x / w * 2 - 1;
mouse.y = -(y / h) * 2 + 1;
dollyDirection.set(mouse.x, mouse.y, 1).unproject(scope.object).sub(scope.object.position).normalize();
}
function clampDistance(dist) {
return Math.max(scope.minDistance, Math.min(scope.maxDistance, dist));
}
function handleMouseDownRotate(event) {
rotateStart.set(event.clientX, event.clientY);
}
function handleMouseDownDolly(event) {
updateMouseParameters(event);
dollyStart.set(event.clientX, event.clientY);
}
function handleMouseDownPan(event) {
panStart.set(event.clientX, event.clientY);
}
function handleMouseMoveRotate(event) {
rotateEnd.set(event.clientX, event.clientY);
rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
const element = scope.domElement;
if (element) {
rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
}
rotateStart.copy(rotateEnd);
scope.update();
}
function handleMouseMoveDolly(event) {
dollyEnd.set(event.clientX, event.clientY);
dollyDelta.subVectors(dollyEnd, dollyStart);
if (dollyDelta.y > 0) {
dollyOut(getZoomScale());
} else if (dollyDelta.y < 0) {
dollyIn(getZoomScale());
}
dollyStart.copy(dollyEnd);
scope.update();
}
function handleMouseMovePan(event) {
panEnd.set(event.clientX, event.clientY);
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
scope.update();
}
function handleMouseWheel(event) {
updateMouseParameters(event);
if (event.deltaY < 0) {
dollyIn(getZoomScale());
} else if (event.deltaY > 0) {
dollyOut(getZoomScale());
}
scope.update();
}
function handleKeyDown(event) {
let needsUpdate = false;
switch (event.code) {
case scope.keys.UP:
pan(0, scope.keyPanSpeed);
needsUpdate = true;
break;
case scope.keys.BOTTOM:
pan(0, -scope.keyPanSpeed);
needsUpdate = true;
break;
case scope.keys.LEFT:
pan(scope.keyPanSpeed, 0);
needsUpdate = true;
break;
case scope.keys.RIGHT:
pan(-scope.keyPanSpeed, 0);
needsUpdate = true;
break;
}
if (needsUpdate) {
event.preventDefault();
scope.update();
}
}
function handleTouchStartRotate() {
if (pointers.length == 1) {
rotateStart.set(pointers[0].pageX, pointers[0].pageY);
} else {
const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
rotateStart.set(x, y);
}
}
function handleTouchStartPan() {
if (pointers.length == 1) {
panStart.set(pointers[0].pageX, pointers[0].pageY);
} else {
const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
panStart.set(x, y);
}
}
function handleTouchStartDolly() {
const dx = pointers[0].pageX - pointers[1].pageX;
const dy = pointers[0].pageY - pointers[1].pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
}
function handleTouchStartDollyPan() {
if (scope.enableZoom)
handleTouchStartDolly();
if (scope.enablePan)
handleTouchStartPan();
}
function handleTouchStartDollyRotate() {
if (scope.enableZoom)
handleTouchStartDolly();
if (scope.enableRotate)
handleTouchStartRotate();
}
function handleTouchMoveRotate(event) {
if (pointers.length == 1) {
rotateEnd.set(event.pageX, event.pageY);
} else {
const position = getSecondPointerPosition(event);
const x = 0.5 * (event.pageX + position.x);
const y = 0.5 * (event.pageY + position.y);
rotateEnd.set(x, y);
}
rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
const element = scope.domElement;
if (element) {
rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
}
rotateStart.copy(rotateEnd);
}
function handleTouchMovePan(event) {
if (pointers.length == 1) {
panEnd.set(event.pageX, event.pageY);
} else {
const position = getSecondPointerPosition(event);
const x = 0.5 * (event.pageX + position.x);
const y = 0.5 * (event.pageY + position.y);
panEnd.set(x, y);
}
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
pan(panDelta.x, panDelta.y);
panStart.copy(panEnd);
}
function handleTouchMoveDolly(event) {
const position = getSecondPointerPosition(event);
const dx = event.pageX - position.x;
const dy = event.pageY - position.y;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyEnd.set(0, distance);
dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
dollyOut(dollyDelta.y);
dollyStart.copy(dollyEnd);
}
function handleTouchMoveDollyPan(event) {
if (scope.enableZoom)
handleTouchMoveDolly(event);
if (scope.enablePan)
handleTouchMovePan(event);
}
function handleTouchMoveDollyRotate(event) {
if (scope.enableZoom)
handleTouchMoveDolly(event);
if (scope.enableRotate)
handleTouchMoveRotate(event);
}
function onPointerDown(event) {
var _a, _b;
if (scope.enabled === false)
return;
if (pointers.length === 0) {
(_a = scope.domElement) == null ? void 0 : _a.ownerDocument.addEventListener("pointermove", onPointerMove);
(_b = scope.domElement) == null ? void 0 : _b.ownerDocument.addEventListener("pointerup", onPointerUp);
}
addPointer(event);
if (event.pointerType === "touch") {
onTouchStart(event);
} else {
onMouseDown(event);
}
}
function onPointerMove(event) {
if (scope.enabled === false)
return;
if (event.pointerType === "touch") {
onTouchMove(event);
} else {
onMouseMove(event);
}
}
function onPointerUp(event) {
var _a, _b, _c;
removePointer(event);
if (pointers.length === 0) {
(_a = scope.domElement) == null ? void 0 : _a.releasePointerCapture(event.pointerId);
(_b = scope.domElement) == null ? void 0 : _b.ownerDocument.removeEventListener("pointermove", onPointerMove);
(_c = scope.domElement) == null ? void 0 : _c.ownerDocument.removeEventListener("pointerup", onPointerUp);
}
scope.dispatchEvent(endEvent);
state = STATE.NONE;
}
function onMouseDown(event) {
let mouseAction;
switch (event.button) {
case 0:
mouseAction = scope.mouseButtons.LEFT;
break;
case 1:
mouseAction = scope.mouseButtons.MIDDLE;
break;
case 2:
mouseAction = scope.mouseButtons.RIGHT;
break;
default:
mouseAction = -1;
}
switch (mouseAction) {
case MOUSE.DOLLY:
if (scope.enableZoom === false)
return;
handleMouseDownDolly(event);
state = STATE.DOLLY;
break;
case MOUSE.ROTATE:
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (scope.enablePan === false)
return;
handleMouseDownPan(event);
state = STATE.PAN;
} else {
if (scope.enableRotate === false)
return;
handleMouseDownRotate(event);
state = STATE.ROTATE;
}
break;
case MOUSE.PAN:
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (scope.enableRotate === false)
return;
handleMouseDownRotate(event);
state = STATE.ROTATE;
} else {
if (scope.enablePan === false)
return;
handleMouseDownPan(event);
state = STATE.PAN;
}
break;
default:
state = STATE.NONE;
}
if (state !== STATE.NONE) {
scope.dispatchEvent(startEvent);
}
}
function onMouseMove(event) {
if (scope.enabled === false)
return;
switch (state) {
case STATE.ROTATE:
if (scope.enableRotate === false)
return;
handleMouseMoveRotate(event);
break;
case STATE.DOLLY:
if (scope.enableZoom === false)
return;
handleMouseMoveDolly(event);
break;
case STATE.PAN:
if (scope.enablePan === false)
return;
handleMouseMovePan(event);
break;
}
}
function onMouseWheel(event) {
if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE) {
return;
}
event.preventDefault();
scope.dispatchEvent(startEvent);
handleMouseWheel(event);
scope.dispatchEvent(endEvent);
}
function onKeyDown(event) {
if (scope.enabled === false || scope.enablePan === false)
return;
handleKeyDown(event);
}
function onTouchStart(event) {
trackPointer(event);
switch (pointers.length) {
case 1:
switch (scope.touches.ONE) {
case TOUCH.ROTATE:
if (scope.enableRotate === false)
return;
handleTouchStartRotate();
state = STATE.TOUCH_ROTATE;
break;
case TOUCH.PAN:
if (scope.enablePan === false)
return;
handleTouchStartPan();
state = STATE.TOUCH_PAN;
break;
default:
state = STATE.NONE;
}
break;
case 2:
switch (scope.touches.TWO) {
case TOUCH.DOLLY_PAN:
if (scope.enableZoom === false && scope.enablePan === false)
return;
handleTouchStartDollyPan();
state = STATE.TOUCH_DOLLY_PAN;
break;
case TOUCH.DOLLY_ROTATE:
if (scope.enableZoom === false && scope.enableRotate === false)
return;
handleTouchStartDollyRotate();
state = STATE.TOUCH_DOLLY_ROTATE;
break;
default:
state = STATE.NONE;
}
break;
default:
state = STATE.NONE;
}
if (state !== STATE.NONE) {
scope.dispatchEvent(startEvent);
}
}
function onTouchMove(event) {
trackPointer(event);
switch (state) {
case STATE.TOUCH_ROTATE:
if (scope.enableRotate === false)
return;
handleTouchMoveRotate(event);
scope.update();
break;
case STATE.TOUCH_PAN:
if (scope.enablePan === false)
return;
handleTouchMovePan(event);
scope.update();
break;
case STATE.TOUCH_DOLLY_PAN:
if (scope.enableZoom === false && scope.enablePan === false)
return;
handleTouchMoveDollyPan(event);
scope.update();
break;
case STATE.TOUCH_DOLLY_ROTATE:
if (scope.enableZoom === false && scope.enableRotate === false)
return;
handleTouchMoveDollyRotate(event);
scope.update();
break;
default:
state = STATE.NONE;
}
}
function onContextMenu(event) {
if (scope.enabled === false)
return;
event.preventDefault();
}
function addPointer(event) {
pointers.push(event);
}
function removePointer(event) {
delete pointerPositions[event.pointerId];
for (let i = 0; i < pointers.length; i++) {
if (pointers[i].pointerId == event.pointerId) {
pointers.splice(i, 1);
return;
}
}
}
function trackPointer(event) {
let position = pointerPositions[event.pointerId];
if (position === void 0) {
position = new Vector2();
pointerPositions[event.pointerId] = position;
}
position.set(event.pageX, event.pageY);
}
function getSecondPointerPosition(event) {
const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
return pointerPositions[pointer.pointerId];
}
this.dollyIn = (dollyScale = getZoomScale()) => {
dollyIn(dollyScale);
scope.update();
};
this.dollyOut = (dollyScale = getZoomScale()) => {
dollyOut(dollyScale);
scope.update();
};
this.getScale = () => {
return scale;
};
this.setScale = (newScale) => {
setScale(newScale);
scope.update();
};
this.getZoomScale = () => {
return getZoomScale();
};
if (domElement !== void 0)
this.connect(domElement);
this.update();
}
}
class MapControls extends OrbitControls {
constructor(object, domElement) {
super(object, domElement);
this.screenSpacePanning = false;
this.mouseButtons.LEFT = MOUSE.PAN;
this.mouseButtons.RIGHT = MOUSE.ROTATE;
this.touches.ONE = TOUCH.PAN;
this.touches.TWO = TOUCH.DOLLY_ROTATE;
}
}
export {
MapControls,
OrbitControls
};
//# sourceMappingURL=OrbitControls.js.map
File diff suppressed because one or more lines are too long
+104
View File
@@ -0,0 +1,104 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
const _euler = /* @__PURE__ */ new THREE.Euler(0, 0, 0, "YXZ");
const _vector = /* @__PURE__ */ new THREE.Vector3();
const _changeEvent = { type: "change" };
const _lockEvent = { type: "lock" };
const _unlockEvent = { type: "unlock" };
const _MOUSE_SENSITIVITY = 2e-3;
const _PI_2 = Math.PI / 2;
class PointerLockControls extends EventDispatcher.EventDispatcher {
constructor(camera, domElement) {
super();
__publicField(this, "camera");
__publicField(this, "domElement");
__publicField(this, "isLocked");
__publicField(this, "minPolarAngle");
__publicField(this, "maxPolarAngle");
__publicField(this, "pointerSpeed");
__publicField(this, "onMouseMove", (event) => {
if (!this.domElement || this.isLocked === false)
return;
_euler.setFromQuaternion(this.camera.quaternion);
_euler.y -= event.movementX * _MOUSE_SENSITIVITY * this.pointerSpeed;
_euler.x -= event.movementY * _MOUSE_SENSITIVITY * this.pointerSpeed;
_euler.x = Math.max(_PI_2 - this.maxPolarAngle, Math.min(_PI_2 - this.minPolarAngle, _euler.x));
this.camera.quaternion.setFromEuler(_euler);
this.dispatchEvent(_changeEvent);
});
__publicField(this, "onPointerlockChange", () => {
if (!this.domElement)
return;
if (this.domElement.ownerDocument.pointerLockElement === this.domElement) {
this.dispatchEvent(_lockEvent);
this.isLocked = true;
} else {
this.dispatchEvent(_unlockEvent);
this.isLocked = false;
}
});
__publicField(this, "onPointerlockError", () => {
console.error("THREE.PointerLockControls: Unable to use Pointer Lock API");
});
__publicField(this, "connect", (domElement) => {
this.domElement = domElement || this.domElement;
if (!this.domElement)
return;
this.domElement.ownerDocument.addEventListener("mousemove", this.onMouseMove);
this.domElement.ownerDocument.addEventListener("pointerlockchange", this.onPointerlockChange);
this.domElement.ownerDocument.addEventListener("pointerlockerror", this.onPointerlockError);
});
__publicField(this, "disconnect", () => {
if (!this.domElement)
return;
this.domElement.ownerDocument.removeEventListener("mousemove", this.onMouseMove);
this.domElement.ownerDocument.removeEventListener("pointerlockchange", this.onPointerlockChange);
this.domElement.ownerDocument.removeEventListener("pointerlockerror", this.onPointerlockError);
});
__publicField(this, "dispose", () => {
this.disconnect();
});
__publicField(this, "getObject", () => {
return this.camera;
});
__publicField(this, "direction", new THREE.Vector3(0, 0, -1));
__publicField(this, "getDirection", (v) => {
return v.copy(this.direction).applyQuaternion(this.camera.quaternion);
});
__publicField(this, "moveForward", (distance) => {
_vector.setFromMatrixColumn(this.camera.matrix, 0);
_vector.crossVectors(this.camera.up, _vector);
this.camera.position.addScaledVector(_vector, distance);
});
__publicField(this, "moveRight", (distance) => {
_vector.setFromMatrixColumn(this.camera.matrix, 0);
this.camera.position.addScaledVector(_vector, distance);
});
__publicField(this, "lock", () => {
if (this.domElement)
this.domElement.requestPointerLock();
});
__publicField(this, "unlock", () => {
if (this.domElement)
this.domElement.ownerDocument.exitPointerLock();
});
this.camera = camera;
this.domElement = domElement;
this.isLocked = false;
this.minPolarAngle = 0;
this.maxPolarAngle = Math.PI;
this.pointerSpeed = 1;
if (domElement)
this.connect(domElement);
}
}
exports.PointerLockControls = PointerLockControls;
//# sourceMappingURL=PointerLockControls.cjs.map
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
import { Camera, Vector3 } from 'three';
import { EventDispatcher } from './EventDispatcher';
export interface PointerLockControlsEventMap {
/**
* Fires when the user moves the mouse.
*/
change: {};
/**
* Fires when the pointer lock status is "locked" (in other words: the mouse is captured).
*/
lock: {};
/**
* Fires when the pointer lock status is "unlocked" (in other words: the mouse is not captured anymore).
*/
unlock: {};
}
declare class PointerLockControls extends EventDispatcher<PointerLockControlsEventMap> {
camera: Camera;
domElement?: HTMLElement;
isLocked: boolean;
minPolarAngle: number;
maxPolarAngle: number;
pointerSpeed: number;
constructor(camera: Camera, domElement?: HTMLElement);
private onMouseMove;
private onPointerlockChange;
private onPointerlockError;
connect: (domElement: HTMLElement) => void;
disconnect: () => void;
dispose: () => void;
getObject: () => Camera;
private direction;
getDirection: (v: Vector3) => Vector3;
moveForward: (distance: number) => void;
moveRight: (distance: number) => void;
lock: () => void;
unlock: () => void;
}
export { PointerLockControls };
+104
View File
@@ -0,0 +1,104 @@
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { Vector3, Euler } from "three";
import { EventDispatcher } from "./EventDispatcher.js";
const _euler = /* @__PURE__ */ new Euler(0, 0, 0, "YXZ");
const _vector = /* @__PURE__ */ new Vector3();
const _changeEvent = { type: "change" };
const _lockEvent = { type: "lock" };
const _unlockEvent = { type: "unlock" };
const _MOUSE_SENSITIVITY = 2e-3;
const _PI_2 = Math.PI / 2;
class PointerLockControls extends EventDispatcher {
constructor(camera, domElement) {
super();
__publicField(this, "camera");
__publicField(this, "domElement");
__publicField(this, "isLocked");
__publicField(this, "minPolarAngle");
__publicField(this, "maxPolarAngle");
__publicField(this, "pointerSpeed");
__publicField(this, "onMouseMove", (event) => {
if (!this.domElement || this.isLocked === false)
return;
_euler.setFromQuaternion(this.camera.quaternion);
_euler.y -= event.movementX * _MOUSE_SENSITIVITY * this.pointerSpeed;
_euler.x -= event.movementY * _MOUSE_SENSITIVITY * this.pointerSpeed;
_euler.x = Math.max(_PI_2 - this.maxPolarAngle, Math.min(_PI_2 - this.minPolarAngle, _euler.x));
this.camera.quaternion.setFromEuler(_euler);
this.dispatchEvent(_changeEvent);
});
__publicField(this, "onPointerlockChange", () => {
if (!this.domElement)
return;
if (this.domElement.ownerDocument.pointerLockElement === this.domElement) {
this.dispatchEvent(_lockEvent);
this.isLocked = true;
} else {
this.dispatchEvent(_unlockEvent);
this.isLocked = false;
}
});
__publicField(this, "onPointerlockError", () => {
console.error("THREE.PointerLockControls: Unable to use Pointer Lock API");
});
__publicField(this, "connect", (domElement) => {
this.domElement = domElement || this.domElement;
if (!this.domElement)
return;
this.domElement.ownerDocument.addEventListener("mousemove", this.onMouseMove);
this.domElement.ownerDocument.addEventListener("pointerlockchange", this.onPointerlockChange);
this.domElement.ownerDocument.addEventListener("pointerlockerror", this.onPointerlockError);
});
__publicField(this, "disconnect", () => {
if (!this.domElement)
return;
this.domElement.ownerDocument.removeEventListener("mousemove", this.onMouseMove);
this.domElement.ownerDocument.removeEventListener("pointerlockchange", this.onPointerlockChange);
this.domElement.ownerDocument.removeEventListener("pointerlockerror", this.onPointerlockError);
});
__publicField(this, "dispose", () => {
this.disconnect();
});
__publicField(this, "getObject", () => {
return this.camera;
});
__publicField(this, "direction", new Vector3(0, 0, -1));
__publicField(this, "getDirection", (v) => {
return v.copy(this.direction).applyQuaternion(this.camera.quaternion);
});
__publicField(this, "moveForward", (distance) => {
_vector.setFromMatrixColumn(this.camera.matrix, 0);
_vector.crossVectors(this.camera.up, _vector);
this.camera.position.addScaledVector(_vector, distance);
});
__publicField(this, "moveRight", (distance) => {
_vector.setFromMatrixColumn(this.camera.matrix, 0);
this.camera.position.addScaledVector(_vector, distance);
});
__publicField(this, "lock", () => {
if (this.domElement)
this.domElement.requestPointerLock();
});
__publicField(this, "unlock", () => {
if (this.domElement)
this.domElement.ownerDocument.exitPointerLock();
});
this.camera = camera;
this.domElement = domElement;
this.isLocked = false;
this.minPolarAngle = 0;
this.maxPolarAngle = Math.PI;
this.pointerSpeed = 1;
if (domElement)
this.connect(domElement);
}
}
export {
PointerLockControls
};
//# sourceMappingURL=PointerLockControls.js.map
File diff suppressed because one or more lines are too long
+14
View File
@@ -0,0 +1,14 @@
export interface StandardControlsEventMap {
/**
* Fires when the camera has been transformed by the controls.
*/
change: {};
/**
* Fires when an interaction was initiated.
*/
start: {};
/**
* Fires when an interaction has finished.
*/
end: {};
}
+502
View File
@@ -0,0 +1,502 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const EventDispatcher = require("./EventDispatcher.cjs");
class TrackballControls extends EventDispatcher.EventDispatcher {
constructor(object, domElement) {
super();
__publicField(this, "enabled", true);
__publicField(this, "screen", { left: 0, top: 0, width: 0, height: 0 });
__publicField(this, "rotateSpeed", 1);
__publicField(this, "zoomSpeed", 1.2);
__publicField(this, "panSpeed", 0.3);
__publicField(this, "noRotate", false);
__publicField(this, "noZoom", false);
__publicField(this, "noPan", false);
__publicField(this, "staticMoving", false);
__publicField(this, "dynamicDampingFactor", 0.2);
__publicField(this, "minDistance", 0);
__publicField(this, "maxDistance", Infinity);
__publicField(this, "keys", [
"KeyA",
"KeyS",
"KeyD"
/*D*/
]);
__publicField(this, "mouseButtons", {
LEFT: THREE.MOUSE.ROTATE,
MIDDLE: THREE.MOUSE.DOLLY,
RIGHT: THREE.MOUSE.PAN
});
__publicField(this, "object");
__publicField(this, "domElement");
__publicField(this, "cursorZoom", false);
__publicField(this, "target", new THREE.Vector3());
__publicField(this, "mousePosition", new THREE.Vector2());
// internals
__publicField(this, "STATE", {
NONE: -1,
ROTATE: 0,
ZOOM: 1,
PAN: 2,
TOUCH_ROTATE: 3,
TOUCH_ZOOM_PAN: 4
});
__publicField(this, "EPS", 1e-6);
__publicField(this, "lastZoom", 1);
__publicField(this, "lastPosition", new THREE.Vector3());
__publicField(this, "cursorVector", new THREE.Vector3());
__publicField(this, "targetVector", new THREE.Vector3());
__publicField(this, "_state", this.STATE.NONE);
__publicField(this, "_keyState", this.STATE.NONE);
__publicField(this, "_eye", new THREE.Vector3());
__publicField(this, "_movePrev", new THREE.Vector2());
__publicField(this, "_moveCurr", new THREE.Vector2());
__publicField(this, "_lastAxis", new THREE.Vector3());
__publicField(this, "_lastAngle", 0);
__publicField(this, "_zoomStart", new THREE.Vector2());
__publicField(this, "_zoomEnd", new THREE.Vector2());
__publicField(this, "_touchZoomDistanceStart", 0);
__publicField(this, "_touchZoomDistanceEnd", 0);
__publicField(this, "_panStart", new THREE.Vector2());
__publicField(this, "_panEnd", new THREE.Vector2());
__publicField(this, "target0");
__publicField(this, "position0");
__publicField(this, "up0");
__publicField(this, "zoom0");
// events
__publicField(this, "changeEvent", { type: "change" });
__publicField(this, "startEvent", { type: "start" });
__publicField(this, "endEvent", { type: "end" });
__publicField(this, "onScreenVector", new THREE.Vector2());
__publicField(this, "getMouseOnScreen", (pageX, pageY) => {
this.onScreenVector.set(
(pageX - this.screen.left) / this.screen.width,
(pageY - this.screen.top) / this.screen.height
);
return this.onScreenVector;
});
__publicField(this, "onCircleVector", new THREE.Vector2());
__publicField(this, "getMouseOnCircle", (pageX, pageY) => {
this.onCircleVector.set(
(pageX - this.screen.width * 0.5 - this.screen.left) / (this.screen.width * 0.5),
(this.screen.height + 2 * (this.screen.top - pageY)) / this.screen.width
// screen.width intentional
);
return this.onCircleVector;
});
__publicField(this, "axis", new THREE.Vector3());
__publicField(this, "quaternion", new THREE.Quaternion());
__publicField(this, "eyeDirection", new THREE.Vector3());
__publicField(this, "objectUpDirection", new THREE.Vector3());
__publicField(this, "objectSidewaysDirection", new THREE.Vector3());
__publicField(this, "moveDirection", new THREE.Vector3());
__publicField(this, "angle", 0);
__publicField(this, "rotateCamera", () => {
this.moveDirection.set(this._moveCurr.x - this._movePrev.x, this._moveCurr.y - this._movePrev.y, 0);
this.angle = this.moveDirection.length();
if (this.angle) {
this._eye.copy(this.object.position).sub(this.target);
this.eyeDirection.copy(this._eye).normalize();
this.objectUpDirection.copy(this.object.up).normalize();
this.objectSidewaysDirection.crossVectors(this.objectUpDirection, this.eyeDirection).normalize();
this.objectUpDirection.setLength(this._moveCurr.y - this._movePrev.y);
this.objectSidewaysDirection.setLength(this._moveCurr.x - this._movePrev.x);
this.moveDirection.copy(this.objectUpDirection.add(this.objectSidewaysDirection));
this.axis.crossVectors(this.moveDirection, this._eye).normalize();
this.angle *= this.rotateSpeed;
this.quaternion.setFromAxisAngle(this.axis, this.angle);
this._eye.applyQuaternion(this.quaternion);
this.object.up.applyQuaternion(this.quaternion);
this._lastAxis.copy(this.axis);
this._lastAngle = this.angle;
} else if (!this.staticMoving && this._lastAngle) {
this._lastAngle *= Math.sqrt(1 - this.dynamicDampingFactor);
this._eye.copy(this.object.position).sub(this.target);
this.quaternion.setFromAxisAngle(this._lastAxis, this._lastAngle);
this._eye.applyQuaternion(this.quaternion);
this.object.up.applyQuaternion(this.quaternion);
}
this._movePrev.copy(this._moveCurr);
});
__publicField(this, "zoomCamera", () => {
let factor;
if (this._state === this.STATE.TOUCH_ZOOM_PAN) {
factor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd;
this._touchZoomDistanceStart = this._touchZoomDistanceEnd;
if (this.object.isPerspectiveCamera) {
this._eye.multiplyScalar(factor);
} else if (this.object.isOrthographicCamera) {
this.object.zoom /= factor;
this.object.updateProjectionMatrix();
} else {
console.warn("THREE.TrackballControls: Unsupported camera type");
}
} else {
factor = 1 + (this._zoomEnd.y - this._zoomStart.y) * this.zoomSpeed;
if (Math.abs(factor - 1) > this.EPS && factor > 0) {
if (this.object.isPerspectiveCamera) {
if (factor > 1 && this._eye.length() >= this.maxDistance - this.EPS) {
factor = 1;
}
this._eye.multiplyScalar(factor);
} else if (this.object.isOrthographicCamera) {
if (factor > 1 && this.object.zoom < this.maxDistance * this.maxDistance) {
factor = 1;
}
this.object.zoom /= factor;
} else {
console.warn("THREE.TrackballControls: Unsupported camera type");
}
}
if (this.staticMoving) {
this._zoomStart.copy(this._zoomEnd);
} else {
this._zoomStart.y += (this._zoomEnd.y - this._zoomStart.y) * this.dynamicDampingFactor;
}
if (this.cursorZoom) {
this.targetVector.copy(this.target).project(this.object);
let worldPos = this.cursorVector.set(this.mousePosition.x, this.mousePosition.y, this.targetVector.z).unproject(this.object);
this.target.lerpVectors(worldPos, this.target, factor);
}
if (this.object.isOrthographicCamera) {
this.object.updateProjectionMatrix();
}
}
});
__publicField(this, "mouseChange", new THREE.Vector2());
__publicField(this, "objectUp", new THREE.Vector3());
__publicField(this, "pan", new THREE.Vector3());
__publicField(this, "panCamera", () => {
if (!this.domElement)
return;
this.mouseChange.copy(this._panEnd).sub(this._panStart);
if (this.mouseChange.lengthSq() > this.EPS) {
if (this.object.isOrthographicCamera) {
const orthoObject = this.object;
const scale_x = (orthoObject.right - orthoObject.left) / this.object.zoom;
const scale_y = (orthoObject.top - orthoObject.bottom) / this.object.zoom;
this.mouseChange.x *= scale_x;
this.mouseChange.y *= scale_y;
} else {
this.mouseChange.multiplyScalar(this._eye.length() * this.panSpeed);
}
this.pan.copy(this._eye).cross(this.object.up).setLength(this.mouseChange.x);
this.pan.add(this.objectUp.copy(this.object.up).setLength(this.mouseChange.y));
this.object.position.add(this.pan);
this.target.add(this.pan);
if (this.staticMoving) {
this._panStart.copy(this._panEnd);
} else {
this._panStart.add(
this.mouseChange.subVectors(this._panEnd, this._panStart).multiplyScalar(this.dynamicDampingFactor)
);
}
}
});
__publicField(this, "checkDistances", () => {
if (!this.noZoom || !this.noPan) {
if (this._eye.lengthSq() > this.maxDistance * this.maxDistance) {
this.object.position.addVectors(this.target, this._eye.setLength(this.maxDistance));
this._zoomStart.copy(this._zoomEnd);
}
if (this._eye.lengthSq() < this.minDistance * this.minDistance) {
this.object.position.addVectors(this.target, this._eye.setLength(this.minDistance));
this._zoomStart.copy(this._zoomEnd);
}
}
});
__publicField(this, "handleResize", () => {
if (!this.domElement)
return;
const box = this.domElement.getBoundingClientRect();
const d = this.domElement.ownerDocument.documentElement;
this.screen.left = box.left + window.pageXOffset - d.clientLeft;
this.screen.top = box.top + window.pageYOffset - d.clientTop;
this.screen.width = box.width;
this.screen.height = box.height;
});
__publicField(this, "update", () => {
this._eye.subVectors(this.object.position, this.target);
if (!this.noRotate) {
this.rotateCamera();
}
if (!this.noZoom) {
this.zoomCamera();
}
if (!this.noPan) {
this.panCamera();
}
this.object.position.addVectors(this.target, this._eye);
if (this.object.isPerspectiveCamera) {
this.checkDistances();
this.object.lookAt(this.target);
if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS) {
this.dispatchEvent(this.changeEvent);
this.lastPosition.copy(this.object.position);
}
} else if (this.object.isOrthographicCamera) {
this.object.lookAt(this.target);
if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || this.lastZoom !== this.object.zoom) {
this.dispatchEvent(this.changeEvent);
this.lastPosition.copy(this.object.position);
this.lastZoom = this.object.zoom;
}
} else {
console.warn("THREE.TrackballControls: Unsupported camera type");
}
});
__publicField(this, "reset", () => {
this._state = this.STATE.NONE;
this._keyState = this.STATE.NONE;
this.target.copy(this.target0);
this.object.position.copy(this.position0);
this.object.up.copy(this.up0);
this.object.zoom = this.zoom0;
this.object.updateProjectionMatrix();
this._eye.subVectors(this.object.position, this.target);
this.object.lookAt(this.target);
this.dispatchEvent(this.changeEvent);
this.lastPosition.copy(this.object.position);
this.lastZoom = this.object.zoom;
});
__publicField(this, "keydown", (event) => {
if (this.enabled === false)
return;
window.removeEventListener("keydown", this.keydown);
if (this._keyState !== this.STATE.NONE) {
return;
} else if (event.code === this.keys[this.STATE.ROTATE] && !this.noRotate) {
this._keyState = this.STATE.ROTATE;
} else if (event.code === this.keys[this.STATE.ZOOM] && !this.noZoom) {
this._keyState = this.STATE.ZOOM;
} else if (event.code === this.keys[this.STATE.PAN] && !this.noPan) {
this._keyState = this.STATE.PAN;
}
});
__publicField(this, "onPointerDown", (event) => {
if (this.enabled === false)
return;
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseDown(event);
break;
}
});
__publicField(this, "onPointerMove", (event) => {
if (this.enabled === false)
return;
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseMove(event);
break;
}
});
__publicField(this, "onPointerUp", (event) => {
if (this.enabled === false)
return;
switch (event.pointerType) {
case "mouse":
case "pen":
this.onMouseUp();
break;
}
});
__publicField(this, "keyup", () => {
if (this.enabled === false)
return;
this._keyState = this.STATE.NONE;
window.addEventListener("keydown", this.keydown);
});
__publicField(this, "onMouseDown", (event) => {
if (!this.domElement)
return;
if (this._state === this.STATE.NONE) {
switch (event.button) {
case this.mouseButtons.LEFT:
this._state = this.STATE.ROTATE;
break;
case this.mouseButtons.MIDDLE:
this._state = this.STATE.ZOOM;
break;
case this.mouseButtons.RIGHT:
this._state = this.STATE.PAN;
break;
}
}
const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state;
if (state === this.STATE.ROTATE && !this.noRotate) {
this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY));
this._movePrev.copy(this._moveCurr);
} else if (state === this.STATE.ZOOM && !this.noZoom) {
this._zoomStart.copy(this.getMouseOnScreen(event.pageX, event.pageY));
this._zoomEnd.copy(this._zoomStart);
} else if (state === this.STATE.PAN && !this.noPan) {
this._panStart.copy(this.getMouseOnScreen(event.pageX, event.pageY));
this._panEnd.copy(this._panStart);
}
this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove);
this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp);
this.dispatchEvent(this.startEvent);
});
__publicField(this, "onMouseMove", (event) => {
if (this.enabled === false)
return;
const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state;
if (state === this.STATE.ROTATE && !this.noRotate) {
this._movePrev.copy(this._moveCurr);
this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY));
} else if (state === this.STATE.ZOOM && !this.noZoom) {
this._zoomEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY));
} else if (state === this.STATE.PAN && !this.noPan) {
this._panEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY));
}
});
__publicField(this, "onMouseUp", () => {
if (!this.domElement)
return;
if (this.enabled === false)
return;
this._state = this.STATE.NONE;
this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove);
this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp);
this.dispatchEvent(this.endEvent);
});
__publicField(this, "mousewheel", (event) => {
if (this.enabled === false)
return;
if (this.noZoom === true)
return;
event.preventDefault();
switch (event.deltaMode) {
case 2:
this._zoomStart.y -= event.deltaY * 0.025;
break;
case 1:
this._zoomStart.y -= event.deltaY * 0.01;
break;
default:
this._zoomStart.y -= event.deltaY * 25e-5;
break;
}
this.mousePosition.x = event.offsetX / this.screen.width * 2 - 1;
this.mousePosition.y = -(event.offsetY / this.screen.height) * 2 + 1;
this.dispatchEvent(this.startEvent);
this.dispatchEvent(this.endEvent);
});
__publicField(this, "touchstart", (event) => {
if (this.enabled === false)
return;
event.preventDefault();
switch (event.touches.length) {
case 1:
this._state = this.STATE.TOUCH_ROTATE;
this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
this._movePrev.copy(this._moveCurr);
break;
default:
this._state = this.STATE.TOUCH_ZOOM_PAN;
const dx = event.touches[0].pageX - event.touches[1].pageX;
const dy = event.touches[0].pageY - event.touches[1].pageY;
this._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy);
const x = (event.touches[0].pageX + event.touches[1].pageX) / 2;
const y = (event.touches[0].pageY + event.touches[1].pageY) / 2;
this._panStart.copy(this.getMouseOnScreen(x, y));
this._panEnd.copy(this._panStart);
break;
}
this.dispatchEvent(this.startEvent);
});
__publicField(this, "touchmove", (event) => {
if (this.enabled === false)
return;
event.preventDefault();
switch (event.touches.length) {
case 1:
this._movePrev.copy(this._moveCurr);
this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
break;
default:
const dx = event.touches[0].pageX - event.touches[1].pageX;
const dy = event.touches[0].pageY - event.touches[1].pageY;
this._touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy);
const x = (event.touches[0].pageX + event.touches[1].pageX) / 2;
const y = (event.touches[0].pageY + event.touches[1].pageY) / 2;
this._panEnd.copy(this.getMouseOnScreen(x, y));
break;
}
});
__publicField(this, "touchend", (event) => {
if (this.enabled === false)
return;
switch (event.touches.length) {
case 0:
this._state = this.STATE.NONE;
break;
case 1:
this._state = this.STATE.TOUCH_ROTATE;
this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY));
this._movePrev.copy(this._moveCurr);
break;
}
this.dispatchEvent(this.endEvent);
});
__publicField(this, "contextmenu", (event) => {
if (this.enabled === false)
return;
event.preventDefault();
});
// https://github.com/mrdoob/three.js/issues/20575
__publicField(this, "connect", (domElement) => {
if (domElement === document) {
console.error(
'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.'
);
}
this.domElement = domElement;
this.domElement.addEventListener("contextmenu", this.contextmenu);
this.domElement.addEventListener("pointerdown", this.onPointerDown);
this.domElement.addEventListener("wheel", this.mousewheel);
this.domElement.addEventListener("touchstart", this.touchstart);
this.domElement.addEventListener("touchend", this.touchend);
this.domElement.addEventListener("touchmove", this.touchmove);
this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove);
this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp);
window.addEventListener("keydown", this.keydown);
window.addEventListener("keyup", this.keyup);
this.handleResize();
});
__publicField(this, "dispose", () => {
if (!this.domElement)
return;
this.domElement.removeEventListener("contextmenu", this.contextmenu);
this.domElement.removeEventListener("pointerdown", this.onPointerDown);
this.domElement.removeEventListener("wheel", this.mousewheel);
this.domElement.removeEventListener("touchstart", this.touchstart);
this.domElement.removeEventListener("touchend", this.touchend);
this.domElement.removeEventListener("touchmove", this.touchmove);
this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove);
this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp);
window.removeEventListener("keydown", this.keydown);
window.removeEventListener("keyup", this.keyup);
});
this.object = object;
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.up0 = this.object.up.clone();
this.zoom0 = this.object.zoom;
if (domElement !== void 0)
this.connect(domElement);
this.update();
}
}
exports.TrackballControls = TrackballControls;
//# sourceMappingURL=TrackballControls.cjs.map
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More