Ai_Assistant/client/node_modules/.vite/deps/@pixiv_three-vrm.js

5844 lines
248 KiB
JavaScript
Raw Permalink Normal View History

2026-05-24 13:31:30 +02:00
import { Ai as Object3D, Cn as GLBufferAttribute, Cs as Vector2, Er as LineSegments, G as BufferAttribute, Gr as MathUtils, Jr as Matrix4, K as BufferGeometry, N as AxesHelper, Nn as Group, So as SkinnedMesh, Ur as Material, Xr as Mesh, Zr as MeshBasicMaterial, at as Color, bo as Skeleton, i as UniformsLib, ms as UniformsUtils, oa as Quaternion, po as ShaderMaterial, qr as Matrix3, tn as DynamicDrawUsage, un as Euler, ws as Vector3, xr as LineBasicMaterial, yr as Line, zn as ImageLoader } from "./three.module-C9LqGydR.js";
//#region node_modules/@pixiv/three-vrm/lib/three-vrm.module.js
/*!
* @pixiv/three-vrm v3.4.1
* VRM file loader for three.js.
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var __async2 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var VRMExpression = class extends Object3D {
constructor(expressionName) {
super();
this.weight = 0;
this.isBinary = false;
this.overrideBlink = "none";
this.overrideLookAt = "none";
this.overrideMouth = "none";
this._binds = [];
this.name = `VRMExpression_${expressionName}`;
this.expressionName = expressionName;
this.type = "VRMExpression";
this.visible = false;
}
/**
* Binds that this expression influences.
*/
get binds() {
return this._binds;
}
/**
* A value represents how much it should override blink expressions.
* `0.0` == no override at all, `1.0` == completely block the expressions.
*/
get overrideBlinkAmount() {
if (this.overrideBlink === "block") return 0 < this.outputWeight ? 1 : 0;
else if (this.overrideBlink === "blend") return this.outputWeight;
else return 0;
}
/**
* A value represents how much it should override lookAt expressions.
* `0.0` == no override at all, `1.0` == completely block the expressions.
*/
get overrideLookAtAmount() {
if (this.overrideLookAt === "block") return 0 < this.outputWeight ? 1 : 0;
else if (this.overrideLookAt === "blend") return this.outputWeight;
else return 0;
}
/**
* A value represents how much it should override mouth expressions.
* `0.0` == no override at all, `1.0` == completely block the expressions.
*/
get overrideMouthAmount() {
if (this.overrideMouth === "block") return 0 < this.outputWeight ? 1 : 0;
else if (this.overrideMouth === "blend") return this.outputWeight;
else return 0;
}
/**
* An output weight of this expression, considering the {@link isBinary}.
*/
get outputWeight() {
if (this.isBinary) return this.weight > .5 ? 1 : 0;
return this.weight;
}
/**
* Add an expression bind to the expression.
*
* @param bind A bind to add
*/
addBind(bind) {
this._binds.push(bind);
}
/**
* Delete an expression bind from the expression.
*
* @param bind A bind to delete
*/
deleteBind(bind) {
const index = this._binds.indexOf(bind);
if (index >= 0) this._binds.splice(index, 1);
}
/**
* Apply weight to every assigned blend shapes.
* Should be called every frame.
*/
applyWeight(options) {
var _a;
let actualWeight = this.outputWeight;
actualWeight *= (_a = options == null ? void 0 : options.multiplier) != null ? _a : 1;
if (this.isBinary && actualWeight < 1) actualWeight = 0;
this._binds.forEach((bind) => bind.applyWeight(actualWeight));
}
/**
* Clear previously assigned blend shapes.
*/
clearAppliedWeight() {
this._binds.forEach((bind) => bind.clearAppliedWeight());
}
};
function extractPrimitivesInternal(gltf, nodeIndex, node) {
var _a, _b;
const json = gltf.parser.json;
const schemaNode = (_a = json.nodes) == null ? void 0 : _a[nodeIndex];
if (schemaNode == null) {
console.warn(`extractPrimitivesInternal: Attempt to use nodes[${nodeIndex}] of glTF but the node doesn't exist`);
return null;
}
const meshIndex = schemaNode.mesh;
if (meshIndex == null) return null;
const schemaMesh = (_b = json.meshes) == null ? void 0 : _b[meshIndex];
if (schemaMesh == null) {
console.warn(`extractPrimitivesInternal: Attempt to use meshes[${meshIndex}] of glTF but the mesh doesn't exist`);
return null;
}
const primitiveCount = schemaMesh.primitives.length;
const primitives = [];
node.traverse((object) => {
if (primitives.length < primitiveCount) {
if (object.isMesh) primitives.push(object);
}
});
return primitives;
}
function gltfExtractPrimitivesFromNode(gltf, nodeIndex) {
return __async2(this, null, function* () {
return extractPrimitivesInternal(gltf, nodeIndex, yield gltf.parser.getDependency("node", nodeIndex));
});
}
function gltfExtractPrimitivesFromNodes(gltf) {
return __async2(this, null, function* () {
const nodes = yield gltf.parser.getDependencies("node");
const map = /* @__PURE__ */ new Map();
nodes.forEach((node, index) => {
const result = extractPrimitivesInternal(gltf, index, node);
if (result != null) map.set(index, result);
});
return map;
});
}
var VRMExpressionPresetName = {
Aa: "aa",
Ih: "ih",
Ou: "ou",
Ee: "ee",
Oh: "oh",
Blink: "blink",
Happy: "happy",
Angry: "angry",
Sad: "sad",
Relaxed: "relaxed",
LookUp: "lookUp",
Surprised: "surprised",
LookDown: "lookDown",
LookLeft: "lookLeft",
LookRight: "lookRight",
BlinkLeft: "blinkLeft",
BlinkRight: "blinkRight",
Neutral: "neutral"
};
function saturate(value) {
return Math.max(Math.min(value, 1), 0);
}
var VRMExpressionManager = class _VRMExpressionManager {
/**
* Create a new {@link VRMExpressionManager}.
*/
constructor() {
this.blinkExpressionNames = [
"blink",
"blinkLeft",
"blinkRight"
];
this.lookAtExpressionNames = [
"lookLeft",
"lookRight",
"lookUp",
"lookDown"
];
this.mouthExpressionNames = [
"aa",
"ee",
"ih",
"oh",
"ou"
];
this._expressions = [];
this._expressionMap = {};
}
get expressions() {
return this._expressions.concat();
}
get expressionMap() {
return Object.assign({}, this._expressionMap);
}
/**
* A map from name to expression, but excluding custom expressions.
*/
get presetExpressionMap() {
const result = {};
const presetNameSet = new Set(Object.values(VRMExpressionPresetName));
Object.entries(this._expressionMap).forEach(([name, expression]) => {
if (presetNameSet.has(name)) result[name] = expression;
});
return result;
}
/**
* A map from name to expression, but excluding preset expressions.
*/
get customExpressionMap() {
const result = {};
const presetNameSet = new Set(Object.values(VRMExpressionPresetName));
Object.entries(this._expressionMap).forEach(([name, expression]) => {
if (!presetNameSet.has(name)) result[name] = expression;
});
return result;
}
/**
* Copy the given {@link VRMExpressionManager} into this one.
* @param source The {@link VRMExpressionManager} you want to copy
* @returns this
*/
copy(source) {
this._expressions.concat().forEach((expression) => {
this.unregisterExpression(expression);
});
source._expressions.forEach((expression) => {
this.registerExpression(expression);
});
this.blinkExpressionNames = source.blinkExpressionNames.concat();
this.lookAtExpressionNames = source.lookAtExpressionNames.concat();
this.mouthExpressionNames = source.mouthExpressionNames.concat();
return this;
}
/**
* Returns a clone of this {@link VRMExpressionManager}.
* @returns Copied {@link VRMExpressionManager}
*/
clone() {
return new _VRMExpressionManager().copy(this);
}
/**
* Return a registered expression.
* If it cannot find an expression, it will return `null` instead.
*
* @param name Name or preset name of the expression
*/
getExpression(name) {
var _a;
return (_a = this._expressionMap[name]) != null ? _a : null;
}
/**
* Register an expression.
*
* @param expression {@link VRMExpression} that describes the expression
*/
registerExpression(expression) {
this._expressions.push(expression);
this._expressionMap[expression.expressionName] = expression;
}
/**
* Unregister an expression.
*
* @param expression The expression you want to unregister
*/
unregisterExpression(expression) {
const index = this._expressions.indexOf(expression);
if (index === -1) console.warn("VRMExpressionManager: The specified expressions is not registered");
this._expressions.splice(index, 1);
delete this._expressionMap[expression.expressionName];
}
/**
* Get the current weight of the specified expression.
* If it doesn't have an expression of given name, it will return `null` instead.
*
* @param name Name of the expression
*/
getValue(name) {
var _a;
const expression = this.getExpression(name);
return (_a = expression == null ? void 0 : expression.weight) != null ? _a : null;
}
/**
* Set a weight to the specified expression.
*
* @param name Name of the expression
* @param weight Weight
*/
setValue(name, weight) {
const expression = this.getExpression(name);
if (expression) expression.weight = saturate(weight);
}
/**
* Reset weights of all expressions to `0.0`.
*/
resetValues() {
this._expressions.forEach((expression) => {
expression.weight = 0;
});
}
/**
* Get a track name of specified expression.
* This track name is needed to manipulate its expression via keyframe animations.
*
* @example Manipulate an expression using keyframe animation
* ```js
* const trackName = vrm.expressionManager.getExpressionTrackName( 'blink' );
* const track = new THREE.NumberKeyframeTrack(
* name,
* [ 0.0, 0.5, 1.0 ], // times
* [ 0.0, 1.0, 0.0 ] // values
* );
*
* const clip = new THREE.AnimationClip(
* 'blink', // name
* 1.0, // duration
* [ track ] // tracks
* );
*
* const mixer = new THREE.AnimationMixer( vrm.scene );
* const action = mixer.clipAction( clip );
* action.play();
* ```
*
* @param name Name of the expression
*/
getExpressionTrackName(name) {
const expression = this.getExpression(name);
return expression ? `${expression.name}.weight` : null;
}
/**
* Update every expressions.
*/
update() {
const weightMultipliers = this._calculateWeightMultipliers();
this._expressions.forEach((expression) => {
expression.clearAppliedWeight();
});
this._expressions.forEach((expression) => {
let multiplier = 1;
const name = expression.expressionName;
if (this.blinkExpressionNames.indexOf(name) !== -1) multiplier *= weightMultipliers.blink;
if (this.lookAtExpressionNames.indexOf(name) !== -1) multiplier *= weightMultipliers.lookAt;
if (this.mouthExpressionNames.indexOf(name) !== -1) multiplier *= weightMultipliers.mouth;
expression.applyWeight({ multiplier });
});
}
/**
* Calculate sum of override amounts to see how much we should multiply weights of certain expressions.
*/
_calculateWeightMultipliers() {
let blink = 1;
let lookAt = 1;
let mouth = 1;
this._expressions.forEach((expression) => {
blink -= expression.overrideBlinkAmount;
lookAt -= expression.overrideLookAtAmount;
mouth -= expression.overrideMouthAmount;
});
blink = Math.max(0, blink);
lookAt = Math.max(0, lookAt);
mouth = Math.max(0, mouth);
return {
blink,
lookAt,
mouth
};
}
};
var VRMExpressionMaterialColorType = {
Color: "color",
EmissionColor: "emissionColor",
ShadeColor: "shadeColor",
MatcapColor: "matcapColor",
RimColor: "rimColor",
OutlineColor: "outlineColor"
};
var v0ExpressionMaterialColorMap = {
_Color: VRMExpressionMaterialColorType.Color,
_EmissionColor: VRMExpressionMaterialColorType.EmissionColor,
_ShadeColor: VRMExpressionMaterialColorType.ShadeColor,
_RimColor: VRMExpressionMaterialColorType.RimColor,
_OutlineColor: VRMExpressionMaterialColorType.OutlineColor
};
var _color = new Color();
var _VRMExpressionMaterialColorBind = class _VRMExpressionMaterialColorBind2 {
constructor({ material, type, targetValue, targetAlpha }) {
this.material = material;
this.type = type;
this.targetValue = targetValue;
this.targetAlpha = targetAlpha != null ? targetAlpha : 1;
const color = this._initColorBindState();
const alpha = this._initAlphaBindState();
this._state = {
color,
alpha
};
}
applyWeight(weight) {
const { color, alpha } = this._state;
if (color != null) {
const { propertyName, deltaValue } = color;
const target = this.material[propertyName];
if (target != void 0) target.add(_color.copy(deltaValue).multiplyScalar(weight));
}
if (alpha != null) {
const { propertyName, deltaValue } = alpha;
if (this.material[propertyName] != void 0) this.material[propertyName] += deltaValue * weight;
}
}
clearAppliedWeight() {
const { color, alpha } = this._state;
if (color != null) {
const { propertyName, initialValue } = color;
const target = this.material[propertyName];
if (target != void 0) target.copy(initialValue);
}
if (alpha != null) {
const { propertyName, initialValue } = alpha;
if (this.material[propertyName] != void 0) this.material[propertyName] = initialValue;
}
}
_initColorBindState() {
var _a, _b, _c;
const { material, type, targetValue } = this;
const propertyNameMap = this._getPropertyNameMap();
const propertyName = (_b = (_a = propertyNameMap == null ? void 0 : propertyNameMap[type]) == null ? void 0 : _a[0]) != null ? _b : null;
if (propertyName == null) {
console.warn(`Tried to add a material color bind to the material ${(_c = material.name) != null ? _c : "(no name)"}, the type ${type} but the material or the type is not supported.`);
return null;
}
const initialValue = material[propertyName].clone();
return {
propertyName,
initialValue,
deltaValue: new Color(targetValue.r - initialValue.r, targetValue.g - initialValue.g, targetValue.b - initialValue.b)
};
}
_initAlphaBindState() {
var _a, _b, _c;
const { material, type, targetAlpha } = this;
const propertyNameMap = this._getPropertyNameMap();
const propertyName = (_b = (_a = propertyNameMap == null ? void 0 : propertyNameMap[type]) == null ? void 0 : _a[1]) != null ? _b : null;
if (propertyName == null && targetAlpha !== 1) {
console.warn(`Tried to add a material alpha bind to the material ${(_c = material.name) != null ? _c : "(no name)"}, the type ${type} but the material or the type does not support alpha.`);
return null;
}
if (propertyName == null) return null;
const initialValue = material[propertyName];
return {
propertyName,
initialValue,
deltaValue: targetAlpha - initialValue
};
}
_getPropertyNameMap() {
var _a, _b;
return (_b = (_a = Object.entries(_VRMExpressionMaterialColorBind2._propertyNameMapMap).find(([distinguisher]) => {
return this.material[distinguisher] === true;
})) == null ? void 0 : _a[1]) != null ? _b : null;
}
};
_VRMExpressionMaterialColorBind._propertyNameMapMap = {
isMeshStandardMaterial: {
color: ["color", "opacity"],
emissionColor: ["emissive", null]
},
isMeshBasicMaterial: { color: ["color", "opacity"] },
isMToonMaterial: {
color: ["color", "opacity"],
emissionColor: ["emissive", null],
outlineColor: ["outlineColorFactor", null],
matcapColor: ["matcapFactor", null],
rimColor: ["parametricRimColorFactor", null],
shadeColor: ["shadeColorFactor", null]
}
};
var VRMExpressionMaterialColorBind = _VRMExpressionMaterialColorBind;
var VRMExpressionMorphTargetBind = class {
constructor({ primitives, index, weight }) {
this.primitives = primitives;
this.index = index;
this.weight = weight;
}
applyWeight(weight) {
this.primitives.forEach((mesh) => {
var _a;
if (((_a = mesh.morphTargetInfluences) == null ? void 0 : _a[this.index]) != null) mesh.morphTargetInfluences[this.index] += this.weight * weight;
});
}
clearAppliedWeight() {
this.primitives.forEach((mesh) => {
var _a;
if (((_a = mesh.morphTargetInfluences) == null ? void 0 : _a[this.index]) != null) mesh.morphTargetInfluences[this.index] = 0;
});
}
};
var _v2 = new Vector2();
var _VRMExpressionTextureTransformBind = class _VRMExpressionTextureTransformBind2 {
constructor({ material, scale, offset }) {
var _a, _b;
this.material = material;
this.scale = scale;
this.offset = offset;
const propertyNames = (_a = Object.entries(_VRMExpressionTextureTransformBind2._propertyNamesMap).find(([distinguisher]) => {
return material[distinguisher] === true;
})) == null ? void 0 : _a[1];
if (propertyNames == null) {
console.warn(`Tried to add a texture transform bind to the material ${(_b = material.name) != null ? _b : "(no name)"} but the material is not supported.`);
this._properties = [];
} else {
this._properties = [];
propertyNames.forEach((propertyName) => {
var _a2;
const texture = (_a2 = material[propertyName]) == null ? void 0 : _a2.clone();
if (!texture) return null;
material[propertyName] = texture;
const initialOffset = texture.offset.clone();
const initialScale = texture.repeat.clone();
const deltaOffset = offset.clone().sub(initialOffset);
const deltaScale = scale.clone().sub(initialScale);
this._properties.push({
name: propertyName,
initialOffset,
deltaOffset,
initialScale,
deltaScale
});
});
}
}
applyWeight(weight) {
this._properties.forEach((property) => {
const target = this.material[property.name];
if (target === void 0) return;
target.offset.add(_v2.copy(property.deltaOffset).multiplyScalar(weight));
target.repeat.add(_v2.copy(property.deltaScale).multiplyScalar(weight));
});
}
clearAppliedWeight() {
this._properties.forEach((property) => {
const target = this.material[property.name];
if (target === void 0) return;
target.offset.copy(property.initialOffset);
target.repeat.copy(property.initialScale);
});
}
};
_VRMExpressionTextureTransformBind._propertyNamesMap = {
isMeshStandardMaterial: [
"map",
"emissiveMap",
"bumpMap",
"normalMap",
"displacementMap",
"roughnessMap",
"metalnessMap",
"alphaMap"
],
isMeshBasicMaterial: [
"map",
"specularMap",
"alphaMap"
],
isMToonMaterial: [
"map",
"normalMap",
"emissiveMap",
"shadeMultiplyTexture",
"rimMultiplyTexture",
"outlineWidthMultiplyTexture",
"uvAnimationMaskTexture"
]
};
var VRMExpressionTextureTransformBind = _VRMExpressionTextureTransformBind;
var POSSIBLE_SPEC_VERSIONS = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var _VRMExpressionLoaderPlugin = class _VRMExpressionLoaderPlugin2 {
get name() {
return "VRMExpressionLoaderPlugin";
}
constructor(parser) {
this.parser = parser;
}
afterRoot(gltf) {
return __async2(this, null, function* () {
gltf.userData.vrmExpressionManager = yield this._import(gltf);
});
}
/**
* Import a {@link VRMExpressionManager} from a VRM.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
*/
_import(gltf) {
return __async2(this, null, function* () {
const v1Result = yield this._v1Import(gltf);
if (v1Result) return v1Result;
const v0Result = yield this._v0Import(gltf);
if (v0Result) return v0Result;
return null;
});
}
_v1Import(gltf) {
return __async2(this, null, function* () {
var _a, _b;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRMC_vrm")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRMC_vrm"];
if (!extension) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS.has(specVersion)) {
console.warn(`VRMExpressionLoaderPlugin: Unknown VRMC_vrm specVersion "${specVersion}"`);
return null;
}
const schemaExpressions = extension.expressions;
if (!schemaExpressions) return null;
const presetNameSet = new Set(Object.values(VRMExpressionPresetName));
const nameSchemaExpressionMap = /* @__PURE__ */ new Map();
if (schemaExpressions.preset != null) Object.entries(schemaExpressions.preset).forEach(([name, schemaExpression]) => {
if (schemaExpression == null) return;
if (!presetNameSet.has(name)) {
console.warn(`VRMExpressionLoaderPlugin: Unknown preset name "${name}" detected. Ignoring the expression`);
return;
}
nameSchemaExpressionMap.set(name, schemaExpression);
});
if (schemaExpressions.custom != null) Object.entries(schemaExpressions.custom).forEach(([name, schemaExpression]) => {
if (presetNameSet.has(name)) {
console.warn(`VRMExpressionLoaderPlugin: Custom expression cannot have preset name "${name}". Ignoring the expression`);
return;
}
nameSchemaExpressionMap.set(name, schemaExpression);
});
const manager = new VRMExpressionManager();
yield Promise.all(Array.from(nameSchemaExpressionMap.entries()).map((_0) => __async2(this, [_0], function* ([name, schemaExpression]) {
var _a2, _b2, _c, _d, _e, _f, _g;
const expression = new VRMExpression(name);
gltf.scene.add(expression);
expression.isBinary = (_a2 = schemaExpression.isBinary) != null ? _a2 : false;
expression.overrideBlink = (_b2 = schemaExpression.overrideBlink) != null ? _b2 : "none";
expression.overrideLookAt = (_c = schemaExpression.overrideLookAt) != null ? _c : "none";
expression.overrideMouth = (_d = schemaExpression.overrideMouth) != null ? _d : "none";
(_e = schemaExpression.morphTargetBinds) == null || _e.forEach((bind) => __async2(this, null, function* () {
var _a3;
if (bind.node === void 0 || bind.index === void 0) return;
const primitives = yield gltfExtractPrimitivesFromNode(gltf, bind.node);
const morphTargetIndex = bind.index;
if (!primitives.every((primitive) => Array.isArray(primitive.morphTargetInfluences) && morphTargetIndex < primitive.morphTargetInfluences.length)) {
console.warn(`VRMExpressionLoaderPlugin: ${schemaExpression.name} attempts to index morph #${morphTargetIndex} but not found.`);
return;
}
expression.addBind(new VRMExpressionMorphTargetBind({
primitives,
index: morphTargetIndex,
weight: (_a3 = bind.weight) != null ? _a3 : 1
}));
}));
if (schemaExpression.materialColorBinds || schemaExpression.textureTransformBinds) {
const gltfMaterials = [];
gltf.scene.traverse((object) => {
const material = object.material;
if (material) if (Array.isArray(material)) gltfMaterials.push(...material);
else gltfMaterials.push(material);
});
(_f = schemaExpression.materialColorBinds) == null || _f.forEach((bind) => __async2(this, null, function* () {
gltfMaterials.filter((material) => {
var _a3;
const materialIndex = (_a3 = this.parser.associations.get(material)) == null ? void 0 : _a3.materials;
return bind.material === materialIndex;
}).forEach((material) => {
expression.addBind(new VRMExpressionMaterialColorBind({
material,
type: bind.type,
targetValue: new Color().fromArray(bind.targetValue),
targetAlpha: bind.targetValue[3]
}));
});
}));
(_g = schemaExpression.textureTransformBinds) == null || _g.forEach((bind) => __async2(this, null, function* () {
gltfMaterials.filter((material) => {
var _a3;
const materialIndex = (_a3 = this.parser.associations.get(material)) == null ? void 0 : _a3.materials;
return bind.material === materialIndex;
}).forEach((material) => {
var _a3, _b3;
expression.addBind(new VRMExpressionTextureTransformBind({
material,
offset: new Vector2().fromArray((_a3 = bind.offset) != null ? _a3 : [0, 0]),
scale: new Vector2().fromArray((_b3 = bind.scale) != null ? _b3 : [1, 1])
}));
});
}));
}
manager.registerExpression(expression);
})));
return manager;
});
}
_v0Import(gltf) {
return __async2(this, null, function* () {
var _a;
const json = this.parser.json;
const vrmExt = (_a = json.extensions) == null ? void 0 : _a.VRM;
if (!vrmExt) return null;
const schemaBlendShape = vrmExt.blendShapeMaster;
if (!schemaBlendShape) return null;
const manager = new VRMExpressionManager();
const schemaBlendShapeGroups = schemaBlendShape.blendShapeGroups;
if (!schemaBlendShapeGroups) return manager;
const blendShapeNameSet = /* @__PURE__ */ new Set();
yield Promise.all(schemaBlendShapeGroups.map((schemaGroup) => __async2(this, null, function* () {
var _a2;
const v0PresetName = schemaGroup.presetName;
const v1PresetName = v0PresetName != null && _VRMExpressionLoaderPlugin2.v0v1PresetNameMap[v0PresetName] || null;
const name = v1PresetName != null ? v1PresetName : schemaGroup.name;
if (name == null) {
console.warn("VRMExpressionLoaderPlugin: One of custom expressions has no name. Ignoring the expression");
return;
}
if (blendShapeNameSet.has(name)) {
console.warn(`VRMExpressionLoaderPlugin: An expression preset ${v0PresetName} has duplicated entries. Ignoring the expression`);
return;
}
blendShapeNameSet.add(name);
const expression = new VRMExpression(name);
gltf.scene.add(expression);
expression.isBinary = (_a2 = schemaGroup.isBinary) != null ? _a2 : false;
if (schemaGroup.binds) schemaGroup.binds.forEach((bind) => __async2(this, null, function* () {
var _a3;
if (bind.mesh === void 0 || bind.index === void 0) return;
const nodesUsingMesh = [];
(_a3 = json.nodes) == null || _a3.forEach((node, i) => {
if (node.mesh === bind.mesh) nodesUsingMesh.push(i);
});
const morphTargetIndex = bind.index;
yield Promise.all(nodesUsingMesh.map((nodeIndex) => __async2(this, null, function* () {
var _a4;
const primitives = yield gltfExtractPrimitivesFromNode(gltf, nodeIndex);
if (!primitives.every((primitive) => Array.isArray(primitive.morphTargetInfluences) && morphTargetIndex < primitive.morphTargetInfluences.length)) {
console.warn(`VRMExpressionLoaderPlugin: ${schemaGroup.name} attempts to index ${morphTargetIndex}th morph but not found.`);
return;
}
expression.addBind(new VRMExpressionMorphTargetBind({
primitives,
index: morphTargetIndex,
weight: .01 * ((_a4 = bind.weight) != null ? _a4 : 100)
}));
})));
}));
const materialValues = schemaGroup.materialValues;
if (materialValues && materialValues.length !== 0) materialValues.forEach((materialValue) => {
if (materialValue.materialName === void 0 || materialValue.propertyName === void 0 || materialValue.targetValue === void 0) return;
const materials = [];
gltf.scene.traverse((object) => {
if (object.material) {
const material = object.material;
if (Array.isArray(material)) materials.push(...material.filter((mtl) => (mtl.name === materialValue.materialName || mtl.name === materialValue.materialName + " (Outline)") && materials.indexOf(mtl) === -1));
else if (material.name === materialValue.materialName && materials.indexOf(material) === -1) materials.push(material);
}
});
const materialPropertyName = materialValue.propertyName;
materials.forEach((material) => {
if (materialPropertyName === "_MainTex_ST") {
const scale = new Vector2(materialValue.targetValue[0], materialValue.targetValue[1]);
const offset = new Vector2(materialValue.targetValue[2], materialValue.targetValue[3]);
offset.y = 1 - offset.y - scale.y;
expression.addBind(new VRMExpressionTextureTransformBind({
material,
scale,
offset
}));
return;
}
const materialColorType = v0ExpressionMaterialColorMap[materialPropertyName];
if (materialColorType) {
expression.addBind(new VRMExpressionMaterialColorBind({
material,
type: materialColorType,
targetValue: new Color().fromArray(materialValue.targetValue),
targetAlpha: materialValue.targetValue[3]
}));
return;
}
console.warn(materialPropertyName + " is not supported");
});
});
manager.registerExpression(expression);
})));
return manager;
});
}
};
_VRMExpressionLoaderPlugin.v0v1PresetNameMap = {
a: "aa",
e: "ee",
i: "ih",
o: "oh",
u: "ou",
blink: "blink",
joy: "happy",
angry: "angry",
sorrow: "sad",
fun: "relaxed",
lookup: "lookUp",
lookdown: "lookDown",
lookleft: "lookLeft",
lookright: "lookRight",
blink_l: "blinkLeft",
blink_r: "blinkRight",
neutral: "neutral"
};
var VRMExpressionLoaderPlugin = _VRMExpressionLoaderPlugin;
var VRMExpressionOverrideType = {
None: "none",
Block: "block",
Blend: "blend"
};
var _VRMFirstPerson = class _VRMFirstPerson2 {
/**
* Create a new VRMFirstPerson object.
*
* @param humanoid A {@link VRMHumanoid}
* @param meshAnnotations A {@link VRMFirstPersonMeshAnnotation}
*/
constructor(humanoid, meshAnnotations) {
this._firstPersonOnlyLayer = _VRMFirstPerson2.DEFAULT_FIRSTPERSON_ONLY_LAYER;
this._thirdPersonOnlyLayer = _VRMFirstPerson2.DEFAULT_THIRDPERSON_ONLY_LAYER;
this._initializedLayers = false;
this.humanoid = humanoid;
this.meshAnnotations = meshAnnotations;
}
/**
* Copy the given {@link VRMFirstPerson} into this one.
* {@link humanoid} must be same as the source one.
* @param source The {@link VRMFirstPerson} you want to copy
* @returns this
*/
copy(source) {
if (this.humanoid !== source.humanoid) throw new Error("VRMFirstPerson: humanoid must be same in order to copy");
this.meshAnnotations = source.meshAnnotations.map((annotation) => ({
meshes: annotation.meshes.concat(),
type: annotation.type
}));
return this;
}
/**
* Returns a clone of this {@link VRMFirstPerson}.
* @returns Copied {@link VRMFirstPerson}
*/
clone() {
return new _VRMFirstPerson2(this.humanoid, this.meshAnnotations).copy(this);
}
/**
* A camera layer represents `FirstPersonOnly` layer.
* Note that **you must call {@link setup} first before you use the layer feature** or it does not work properly.
*
* The value is {@link DEFAULT_FIRSTPERSON_ONLY_LAYER} by default but you can change the layer by specifying via {@link setup} if you prefer.
*
* @see https://vrm.dev/en/univrm/api/univrm_use_firstperson/
* @see https://threejs.org/docs/#api/en/core/Layers
*/
get firstPersonOnlyLayer() {
return this._firstPersonOnlyLayer;
}
/**
* A camera layer represents `ThirdPersonOnly` layer.
* Note that **you must call {@link setup} first before you use the layer feature** or it does not work properly.
*
* The value is {@link DEFAULT_THIRDPERSON_ONLY_LAYER} by default but you can change the layer by specifying via {@link setup} if you prefer.
*
* @see https://vrm.dev/en/univrm/api/univrm_use_firstperson/
* @see https://threejs.org/docs/#api/en/core/Layers
*/
get thirdPersonOnlyLayer() {
return this._thirdPersonOnlyLayer;
}
/**
* In this method, it assigns layers for every meshes based on mesh annotations.
* You must call this method first before you use the layer feature.
*
* This is an equivalent of [VRMFirstPerson.Setup](https://github.com/vrm-c/UniVRM/blob/73a5bd8fcddaa2a7a8735099a97e63c9db3e5ea0/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs#L295-L299) of the UniVRM.
*
* The `cameraLayer` parameter specifies which layer will be assigned for `FirstPersonOnly` / `ThirdPersonOnly`.
* In UniVRM, we specified those by naming each desired layer as `FIRSTPERSON_ONLY_LAYER` / `THIRDPERSON_ONLY_LAYER`
* but we are going to specify these layers at here since we are unable to name layers in Three.js.
*
* @param cameraLayer Specify which layer will be for `FirstPersonOnly` / `ThirdPersonOnly`.
*/
setup({ firstPersonOnlyLayer = _VRMFirstPerson2.DEFAULT_FIRSTPERSON_ONLY_LAYER, thirdPersonOnlyLayer = _VRMFirstPerson2.DEFAULT_THIRDPERSON_ONLY_LAYER } = {}) {
if (this._initializedLayers) return;
this._firstPersonOnlyLayer = firstPersonOnlyLayer;
this._thirdPersonOnlyLayer = thirdPersonOnlyLayer;
this.meshAnnotations.forEach((item) => {
item.meshes.forEach((mesh) => {
if (item.type === "firstPersonOnly") {
mesh.layers.set(this._firstPersonOnlyLayer);
mesh.traverse((child) => child.layers.set(this._firstPersonOnlyLayer));
} else if (item.type === "thirdPersonOnly") {
mesh.layers.set(this._thirdPersonOnlyLayer);
mesh.traverse((child) => child.layers.set(this._thirdPersonOnlyLayer));
} else if (item.type === "auto") this._createHeadlessModel(mesh);
});
});
this._initializedLayers = true;
}
_excludeTriangles(triangles, bws, skinIndex, exclude) {
let count = 0;
if (bws != null && bws.length > 0) for (let i = 0; i < triangles.length; i += 3) {
const a = triangles[i];
const b = triangles[i + 1];
const c = triangles[i + 2];
const bw0 = bws[a];
const skin0 = skinIndex[a];
if (bw0[0] > 0 && exclude.includes(skin0[0])) continue;
if (bw0[1] > 0 && exclude.includes(skin0[1])) continue;
if (bw0[2] > 0 && exclude.includes(skin0[2])) continue;
if (bw0[3] > 0 && exclude.includes(skin0[3])) continue;
const bw1 = bws[b];
const skin1 = skinIndex[b];
if (bw1[0] > 0 && exclude.includes(skin1[0])) continue;
if (bw1[1] > 0 && exclude.includes(skin1[1])) continue;
if (bw1[2] > 0 && exclude.includes(skin1[2])) continue;
if (bw1[3] > 0 && exclude.includes(skin1[3])) continue;
const bw2 = bws[c];
const skin2 = skinIndex[c];
if (bw2[0] > 0 && exclude.includes(skin2[0])) continue;
if (bw2[1] > 0 && exclude.includes(skin2[1])) continue;
if (bw2[2] > 0 && exclude.includes(skin2[2])) continue;
if (bw2[3] > 0 && exclude.includes(skin2[3])) continue;
triangles[count++] = a;
triangles[count++] = b;
triangles[count++] = c;
}
return count;
}
_createErasedMesh(src, erasingBonesIndex) {
const dst = new SkinnedMesh(src.geometry.clone(), src.material);
dst.name = `${src.name}(erase)`;
dst.frustumCulled = src.frustumCulled;
dst.layers.set(this._firstPersonOnlyLayer);
const geometry = dst.geometry;
const skinIndexAttr = geometry.getAttribute("skinIndex");
const skinIndexAttrArray = skinIndexAttr instanceof GLBufferAttribute ? [] : skinIndexAttr.array;
const skinIndex = [];
for (let i = 0; i < skinIndexAttrArray.length; i += 4) skinIndex.push([
skinIndexAttrArray[i],
skinIndexAttrArray[i + 1],
skinIndexAttrArray[i + 2],
skinIndexAttrArray[i + 3]
]);
const skinWeightAttr = geometry.getAttribute("skinWeight");
const skinWeightAttrArray = skinWeightAttr instanceof GLBufferAttribute ? [] : skinWeightAttr.array;
const skinWeight = [];
for (let i = 0; i < skinWeightAttrArray.length; i += 4) skinWeight.push([
skinWeightAttrArray[i],
skinWeightAttrArray[i + 1],
skinWeightAttrArray[i + 2],
skinWeightAttrArray[i + 3]
]);
const index = geometry.getIndex();
if (!index) throw new Error("The geometry doesn't have an index buffer");
const oldTriangles = Array.from(index.array);
const count = this._excludeTriangles(oldTriangles, skinWeight, skinIndex, erasingBonesIndex);
const newTriangle = [];
for (let i = 0; i < count; i++) newTriangle[i] = oldTriangles[i];
geometry.setIndex(newTriangle);
if (src.onBeforeRender) dst.onBeforeRender = src.onBeforeRender;
dst.bind(new Skeleton(src.skeleton.bones, src.skeleton.boneInverses), new Matrix4());
return dst;
}
_createHeadlessModelForSkinnedMesh(parent, mesh) {
const eraseBoneIndexes = [];
mesh.skeleton.bones.forEach((bone, index) => {
if (this._isEraseTarget(bone)) eraseBoneIndexes.push(index);
});
if (!eraseBoneIndexes.length) {
mesh.layers.enable(this._thirdPersonOnlyLayer);
mesh.layers.enable(this._firstPersonOnlyLayer);
return;
}
mesh.layers.set(this._thirdPersonOnlyLayer);
const newMesh = this._createErasedMesh(mesh, eraseBoneIndexes);
parent.add(newMesh);
}
_createHeadlessModel(node) {
if (node.type === "Group") {
node.layers.set(this._thirdPersonOnlyLayer);
if (this._isEraseTarget(node)) node.traverse((child) => child.layers.set(this._thirdPersonOnlyLayer));
else {
const parent = new Group();
parent.name = `_headless_${node.name}`;
parent.layers.set(this._firstPersonOnlyLayer);
node.parent.add(parent);
node.children.filter((child) => child.type === "SkinnedMesh").forEach((child) => {
const skinnedMesh = child;
this._createHeadlessModelForSkinnedMesh(parent, skinnedMesh);
});
}
} else if (node.type === "SkinnedMesh") {
const skinnedMesh = node;
this._createHeadlessModelForSkinnedMesh(node.parent, skinnedMesh);
} else if (this._isEraseTarget(node)) {
node.layers.set(this._thirdPersonOnlyLayer);
node.traverse((child) => child.layers.set(this._thirdPersonOnlyLayer));
}
}
_isEraseTarget(bone) {
if (bone === this.humanoid.getRawBoneNode("head")) return true;
else if (!bone.parent) return false;
else return this._isEraseTarget(bone.parent);
}
};
_VRMFirstPerson.DEFAULT_FIRSTPERSON_ONLY_LAYER = 9;
_VRMFirstPerson.DEFAULT_THIRDPERSON_ONLY_LAYER = 10;
var VRMFirstPerson = _VRMFirstPerson;
var POSSIBLE_SPEC_VERSIONS2 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var VRMFirstPersonLoaderPlugin = class {
get name() {
return "VRMFirstPersonLoaderPlugin";
}
constructor(parser) {
this.parser = parser;
}
afterRoot(gltf) {
return __async2(this, null, function* () {
const vrmHumanoid = gltf.userData.vrmHumanoid;
if (vrmHumanoid === null) return;
else if (vrmHumanoid === void 0) throw new Error("VRMFirstPersonLoaderPlugin: vrmHumanoid is undefined. VRMHumanoidLoaderPlugin have to be used first");
gltf.userData.vrmFirstPerson = yield this._import(gltf, vrmHumanoid);
});
}
/**
* Import a {@link VRMFirstPerson} from a VRM.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
* @param humanoid A {@link VRMHumanoid} instance that represents the VRM
*/
_import(gltf, humanoid) {
return __async2(this, null, function* () {
if (humanoid == null) return null;
const v1Result = yield this._v1Import(gltf, humanoid);
if (v1Result) return v1Result;
const v0Result = yield this._v0Import(gltf, humanoid);
if (v0Result) return v0Result;
return null;
});
}
_v1Import(gltf, humanoid) {
return __async2(this, null, function* () {
var _a, _b;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRMC_vrm")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRMC_vrm"];
if (!extension) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS2.has(specVersion)) {
console.warn(`VRMFirstPersonLoaderPlugin: Unknown VRMC_vrm specVersion "${specVersion}"`);
return null;
}
const schemaFirstPerson = extension.firstPerson;
const meshAnnotations = [];
const nodePrimitivesMap = yield gltfExtractPrimitivesFromNodes(gltf);
Array.from(nodePrimitivesMap.entries()).forEach(([nodeIndex, primitives]) => {
var _a2, _b2;
const annotation = (_a2 = schemaFirstPerson == null ? void 0 : schemaFirstPerson.meshAnnotations) == null ? void 0 : _a2.find((a) => a.node === nodeIndex);
meshAnnotations.push({
meshes: primitives,
type: (_b2 = annotation == null ? void 0 : annotation.type) != null ? _b2 : "auto"
});
});
return new VRMFirstPerson(humanoid, meshAnnotations);
});
}
_v0Import(gltf, humanoid) {
return __async2(this, null, function* () {
var _a;
const json = this.parser.json;
const vrmExt = (_a = json.extensions) == null ? void 0 : _a.VRM;
if (!vrmExt) return null;
const schemaFirstPerson = vrmExt.firstPerson;
if (!schemaFirstPerson) return null;
const meshAnnotations = [];
const nodePrimitivesMap = yield gltfExtractPrimitivesFromNodes(gltf);
Array.from(nodePrimitivesMap.entries()).forEach(([nodeIndex, primitives]) => {
const schemaNode = json.nodes[nodeIndex];
const flag = schemaFirstPerson.meshAnnotations ? schemaFirstPerson.meshAnnotations.find((a) => a.mesh === schemaNode.mesh) : void 0;
meshAnnotations.push({
meshes: primitives,
type: this._convertV0FlagToV1Type(flag == null ? void 0 : flag.firstPersonFlag)
});
});
return new VRMFirstPerson(humanoid, meshAnnotations);
});
}
_convertV0FlagToV1Type(flag) {
if (flag === "FirstPersonOnly") return "firstPersonOnly";
else if (flag === "ThirdPersonOnly") return "thirdPersonOnly";
else if (flag === "Both") return "both";
else return "auto";
}
};
var VRMFirstPersonMeshAnnotationType = {
Auto: "auto",
Both: "both",
ThirdPersonOnly: "thirdPersonOnly",
FirstPersonOnly: "firstPersonOnly"
};
var _v3A = new Vector3();
var _v3B = new Vector3();
var _quatA = new Quaternion();
var VRMHumanoidHelper = class extends Group {
constructor(humanoid) {
super();
this.vrmHumanoid = humanoid;
this._boneAxesMap = /* @__PURE__ */ new Map();
Object.values(humanoid.humanBones).forEach((bone) => {
const helper = new AxesHelper(1);
helper.matrixAutoUpdate = false;
helper.material.depthTest = false;
helper.material.depthWrite = false;
this.add(helper);
this._boneAxesMap.set(bone, helper);
});
}
dispose() {
Array.from(this._boneAxesMap.values()).forEach((axes) => {
axes.geometry.dispose();
axes.material.dispose();
});
}
updateMatrixWorld(force) {
Array.from(this._boneAxesMap.entries()).forEach(([bone, axes]) => {
bone.node.updateWorldMatrix(true, false);
bone.node.matrixWorld.decompose(_v3A, _quatA, _v3B);
const scale = _v3A.set(.1, .1, .1).divide(_v3B);
axes.matrix.copy(bone.node.matrixWorld).scale(scale);
});
super.updateMatrixWorld(force);
}
};
var VRMHumanBoneList = [
"hips",
"spine",
"chest",
"upperChest",
"neck",
"head",
"leftEye",
"rightEye",
"jaw",
"leftUpperLeg",
"leftLowerLeg",
"leftFoot",
"leftToes",
"rightUpperLeg",
"rightLowerLeg",
"rightFoot",
"rightToes",
"leftShoulder",
"leftUpperArm",
"leftLowerArm",
"leftHand",
"rightShoulder",
"rightUpperArm",
"rightLowerArm",
"rightHand",
"leftThumbMetacarpal",
"leftThumbProximal",
"leftThumbDistal",
"leftIndexProximal",
"leftIndexIntermediate",
"leftIndexDistal",
"leftMiddleProximal",
"leftMiddleIntermediate",
"leftMiddleDistal",
"leftRingProximal",
"leftRingIntermediate",
"leftRingDistal",
"leftLittleProximal",
"leftLittleIntermediate",
"leftLittleDistal",
"rightThumbMetacarpal",
"rightThumbProximal",
"rightThumbDistal",
"rightIndexProximal",
"rightIndexIntermediate",
"rightIndexDistal",
"rightMiddleProximal",
"rightMiddleIntermediate",
"rightMiddleDistal",
"rightRingProximal",
"rightRingIntermediate",
"rightRingDistal",
"rightLittleProximal",
"rightLittleIntermediate",
"rightLittleDistal"
];
var VRMHumanBoneName = {
Hips: "hips",
Spine: "spine",
Chest: "chest",
UpperChest: "upperChest",
Neck: "neck",
Head: "head",
LeftEye: "leftEye",
RightEye: "rightEye",
Jaw: "jaw",
LeftUpperLeg: "leftUpperLeg",
LeftLowerLeg: "leftLowerLeg",
LeftFoot: "leftFoot",
LeftToes: "leftToes",
RightUpperLeg: "rightUpperLeg",
RightLowerLeg: "rightLowerLeg",
RightFoot: "rightFoot",
RightToes: "rightToes",
LeftShoulder: "leftShoulder",
LeftUpperArm: "leftUpperArm",
LeftLowerArm: "leftLowerArm",
LeftHand: "leftHand",
RightShoulder: "rightShoulder",
RightUpperArm: "rightUpperArm",
RightLowerArm: "rightLowerArm",
RightHand: "rightHand",
LeftThumbMetacarpal: "leftThumbMetacarpal",
LeftThumbProximal: "leftThumbProximal",
LeftThumbDistal: "leftThumbDistal",
LeftIndexProximal: "leftIndexProximal",
LeftIndexIntermediate: "leftIndexIntermediate",
LeftIndexDistal: "leftIndexDistal",
LeftMiddleProximal: "leftMiddleProximal",
LeftMiddleIntermediate: "leftMiddleIntermediate",
LeftMiddleDistal: "leftMiddleDistal",
LeftRingProximal: "leftRingProximal",
LeftRingIntermediate: "leftRingIntermediate",
LeftRingDistal: "leftRingDistal",
LeftLittleProximal: "leftLittleProximal",
LeftLittleIntermediate: "leftLittleIntermediate",
LeftLittleDistal: "leftLittleDistal",
RightThumbMetacarpal: "rightThumbMetacarpal",
RightThumbProximal: "rightThumbProximal",
RightThumbDistal: "rightThumbDistal",
RightIndexProximal: "rightIndexProximal",
RightIndexIntermediate: "rightIndexIntermediate",
RightIndexDistal: "rightIndexDistal",
RightMiddleProximal: "rightMiddleProximal",
RightMiddleIntermediate: "rightMiddleIntermediate",
RightMiddleDistal: "rightMiddleDistal",
RightRingProximal: "rightRingProximal",
RightRingIntermediate: "rightRingIntermediate",
RightRingDistal: "rightRingDistal",
RightLittleProximal: "rightLittleProximal",
RightLittleIntermediate: "rightLittleIntermediate",
RightLittleDistal: "rightLittleDistal"
};
var VRMHumanBoneParentMap = {
hips: null,
spine: "hips",
chest: "spine",
upperChest: "chest",
neck: "upperChest",
head: "neck",
leftEye: "head",
rightEye: "head",
jaw: "head",
leftUpperLeg: "hips",
leftLowerLeg: "leftUpperLeg",
leftFoot: "leftLowerLeg",
leftToes: "leftFoot",
rightUpperLeg: "hips",
rightLowerLeg: "rightUpperLeg",
rightFoot: "rightLowerLeg",
rightToes: "rightFoot",
leftShoulder: "upperChest",
leftUpperArm: "leftShoulder",
leftLowerArm: "leftUpperArm",
leftHand: "leftLowerArm",
rightShoulder: "upperChest",
rightUpperArm: "rightShoulder",
rightLowerArm: "rightUpperArm",
rightHand: "rightLowerArm",
leftThumbMetacarpal: "leftHand",
leftThumbProximal: "leftThumbMetacarpal",
leftThumbDistal: "leftThumbProximal",
leftIndexProximal: "leftHand",
leftIndexIntermediate: "leftIndexProximal",
leftIndexDistal: "leftIndexIntermediate",
leftMiddleProximal: "leftHand",
leftMiddleIntermediate: "leftMiddleProximal",
leftMiddleDistal: "leftMiddleIntermediate",
leftRingProximal: "leftHand",
leftRingIntermediate: "leftRingProximal",
leftRingDistal: "leftRingIntermediate",
leftLittleProximal: "leftHand",
leftLittleIntermediate: "leftLittleProximal",
leftLittleDistal: "leftLittleIntermediate",
rightThumbMetacarpal: "rightHand",
rightThumbProximal: "rightThumbMetacarpal",
rightThumbDistal: "rightThumbProximal",
rightIndexProximal: "rightHand",
rightIndexIntermediate: "rightIndexProximal",
rightIndexDistal: "rightIndexIntermediate",
rightMiddleProximal: "rightHand",
rightMiddleIntermediate: "rightMiddleProximal",
rightMiddleDistal: "rightMiddleIntermediate",
rightRingProximal: "rightHand",
rightRingIntermediate: "rightRingProximal",
rightRingDistal: "rightRingIntermediate",
rightLittleProximal: "rightHand",
rightLittleIntermediate: "rightLittleProximal",
rightLittleDistal: "rightLittleIntermediate"
};
function quatInvertCompat(target) {
if (target.invert) target.invert();
else target.inverse();
return target;
}
var _v3A2 = new Vector3();
var _quatA2 = new Quaternion();
var VRMRig = class {
/**
* Create a new {@link VRMHumanoid}.
* @param humanBones A {@link VRMHumanBones} contains all the bones of the new humanoid
*/
constructor(humanBones) {
this.humanBones = humanBones;
this.restPose = this.getAbsolutePose();
}
/**
* Return the current absolute pose of this humanoid as a {@link VRMPose}.
* Note that the output result will contain initial state of the VRM and not compatible between different models.
* You might want to use {@link getPose} instead.
*/
getAbsolutePose() {
const pose = {};
Object.keys(this.humanBones).forEach((vrmBoneNameString) => {
const vrmBoneName = vrmBoneNameString;
const node = this.getBoneNode(vrmBoneName);
if (!node) return;
_v3A2.copy(node.position);
_quatA2.copy(node.quaternion);
pose[vrmBoneName] = {
position: _v3A2.toArray(),
rotation: _quatA2.toArray()
};
});
return pose;
}
/**
* Return the current pose of this humanoid as a {@link VRMPose}.
*
* Each transform is a local transform relative from rest pose (T-pose).
*/
getPose() {
const pose = {};
Object.keys(this.humanBones).forEach((boneNameString) => {
const boneName = boneNameString;
const node = this.getBoneNode(boneName);
if (!node) return;
_v3A2.set(0, 0, 0);
_quatA2.identity();
const restState = this.restPose[boneName];
if (restState == null ? void 0 : restState.position) _v3A2.fromArray(restState.position).negate();
if (restState == null ? void 0 : restState.rotation) quatInvertCompat(_quatA2.fromArray(restState.rotation));
_v3A2.add(node.position);
_quatA2.premultiply(node.quaternion);
pose[boneName] = {
position: _v3A2.toArray(),
rotation: _quatA2.toArray()
};
});
return pose;
}
/**
* Let the humanoid do a specified pose.
*
* Each transform have to be a local transform relative from rest pose (T-pose).
* You can pass what you got from {@link getPose}.
*
* @param poseObject A {@link VRMPose} that represents a single pose
*/
setPose(poseObject) {
Object.entries(poseObject).forEach(([boneNameString, state]) => {
const boneName = boneNameString;
const node = this.getBoneNode(boneName);
if (!node) return;
const restState = this.restPose[boneName];
if (!restState) return;
if (state == null ? void 0 : state.position) {
node.position.fromArray(state.position);
if (restState.position) node.position.add(_v3A2.fromArray(restState.position));
}
if (state == null ? void 0 : state.rotation) {
node.quaternion.fromArray(state.rotation);
if (restState.rotation) node.quaternion.multiply(_quatA2.fromArray(restState.rotation));
}
});
}
/**
* Reset the humanoid to its rest pose.
*/
resetPose() {
Object.entries(this.restPose).forEach(([boneName, rest]) => {
const node = this.getBoneNode(boneName);
if (!node) return;
if (rest == null ? void 0 : rest.position) node.position.fromArray(rest.position);
if (rest == null ? void 0 : rest.rotation) node.quaternion.fromArray(rest.rotation);
});
}
/**
* Return a bone bound to a specified {@link VRMHumanBoneName}, as a {@link VRMHumanBone}.
*
* @param name Name of the bone you want
*/
getBone(name) {
var _a;
return (_a = this.humanBones[name]) != null ? _a : void 0;
}
/**
* Return a bone bound to a specified {@link VRMHumanBoneName}, as a `THREE.Object3D`.
*
* @param name Name of the bone you want
*/
getBoneNode(name) {
var _a, _b;
return (_b = (_a = this.humanBones[name]) == null ? void 0 : _a.node) != null ? _b : null;
}
};
var _v3A3 = new Vector3();
var _quatA3 = new Quaternion();
var _boneWorldPos = new Vector3();
var VRMHumanoidRig = class _VRMHumanoidRig extends VRMRig {
static _setupTransforms(modelRig) {
const root = new Object3D();
root.name = "VRMHumanoidRig";
const boneWorldPositions = {};
const boneWorldRotations = {};
const boneRotations = {};
const parentWorldRotations = {};
VRMHumanBoneList.forEach((boneName) => {
var _a;
const boneNode = modelRig.getBoneNode(boneName);
if (boneNode) {
const boneWorldPosition = new Vector3();
const boneWorldRotation = new Quaternion();
boneNode.updateWorldMatrix(true, false);
boneNode.matrixWorld.decompose(boneWorldPosition, boneWorldRotation, _v3A3);
boneWorldPositions[boneName] = boneWorldPosition;
boneWorldRotations[boneName] = boneWorldRotation;
boneRotations[boneName] = boneNode.quaternion.clone();
const parentWorldRotation = new Quaternion();
(_a = boneNode.parent) == null || _a.matrixWorld.decompose(_v3A3, parentWorldRotation, _v3A3);
parentWorldRotations[boneName] = parentWorldRotation;
}
});
const rigBones = {};
VRMHumanBoneList.forEach((boneName) => {
var _a;
const boneNode = modelRig.getBoneNode(boneName);
if (boneNode) {
const boneWorldPosition = boneWorldPositions[boneName];
let currentBoneName = boneName;
let parentBoneWorldPosition;
while (parentBoneWorldPosition == null) {
currentBoneName = VRMHumanBoneParentMap[currentBoneName];
if (currentBoneName == null) break;
parentBoneWorldPosition = boneWorldPositions[currentBoneName];
}
const rigBoneNode = new Object3D();
rigBoneNode.name = "Normalized_" + boneNode.name;
(currentBoneName ? (_a = rigBones[currentBoneName]) == null ? void 0 : _a.node : root).add(rigBoneNode);
rigBoneNode.position.copy(boneWorldPosition);
if (parentBoneWorldPosition) rigBoneNode.position.sub(parentBoneWorldPosition);
rigBones[boneName] = { node: rigBoneNode };
}
});
return {
rigBones,
root,
parentWorldRotations,
boneRotations
};
}
constructor(humanoid) {
const { rigBones, root, parentWorldRotations, boneRotations } = _VRMHumanoidRig._setupTransforms(humanoid);
super(rigBones);
this.original = humanoid;
this.root = root;
this._parentWorldRotations = parentWorldRotations;
this._boneRotations = boneRotations;
}
/**
* Update this humanoid rig.
*/
update() {
VRMHumanBoneList.forEach((boneName) => {
const boneNode = this.original.getBoneNode(boneName);
if (boneNode != null) {
const rigBoneNode = this.getBoneNode(boneName);
const parentWorldRotation = this._parentWorldRotations[boneName];
const invParentWorldRotation = _quatA3.copy(parentWorldRotation).invert();
const boneRotation = this._boneRotations[boneName];
boneNode.quaternion.copy(rigBoneNode.quaternion).multiply(parentWorldRotation).premultiply(invParentWorldRotation).multiply(boneRotation);
if (boneName === "hips") {
const boneWorldPosition = rigBoneNode.getWorldPosition(_boneWorldPos);
boneNode.parent.updateWorldMatrix(true, false);
const parentWorldMatrix = boneNode.parent.matrixWorld;
const localPosition = boneWorldPosition.applyMatrix4(parentWorldMatrix.invert());
boneNode.position.copy(localPosition);
}
}
});
}
};
var VRMHumanoid = class _VRMHumanoid {
/**
* @deprecated Deprecated. Use either {@link rawRestPose} or {@link normalizedRestPose} instead.
*/
get restPose() {
console.warn("VRMHumanoid: restPose is deprecated. Use either rawRestPose or normalizedRestPose instead.");
return this.rawRestPose;
}
/**
* A {@link VRMPose} of its raw human bones that is its default state.
* Note that it's not compatible with {@link setRawPose} and {@link getRawPose}, since it contains non-relative values of each local transforms.
*/
get rawRestPose() {
return this._rawHumanBones.restPose;
}
/**
* A {@link VRMPose} of its normalized human bones that is its default state.
* Note that it's not compatible with {@link setNormalizedPose} and {@link getNormalizedPose}, since it contains non-relative values of each local transforms.
*/
get normalizedRestPose() {
return this._normalizedHumanBones.restPose;
}
/**
* A map from {@link VRMHumanBoneName} to raw {@link VRMHumanBone}s.
*/
get humanBones() {
return this._rawHumanBones.humanBones;
}
/**
* A map from {@link VRMHumanBoneName} to raw {@link VRMHumanBone}s.
*/
get rawHumanBones() {
return this._rawHumanBones.humanBones;
}
/**
* A map from {@link VRMHumanBoneName} to normalized {@link VRMHumanBone}s.
*/
get normalizedHumanBones() {
return this._normalizedHumanBones.humanBones;
}
/**
* The root of normalized {@link VRMHumanBone}s.
*/
get normalizedHumanBonesRoot() {
return this._normalizedHumanBones.root;
}
/**
* Create a new {@link VRMHumanoid}.
* @param humanBones A {@link VRMHumanBones} contains all the bones of the new humanoid
* @param autoUpdateHumanBones Whether it copies pose from normalizedHumanBones to rawHumanBones on {@link update}. `true` by default.
*/
constructor(humanBones, options) {
var _a;
this.autoUpdateHumanBones = (_a = options == null ? void 0 : options.autoUpdateHumanBones) != null ? _a : true;
this._rawHumanBones = new VRMRig(humanBones);
this._normalizedHumanBones = new VRMHumanoidRig(this._rawHumanBones);
}
/**
* Copy the given {@link VRMHumanoid} into this one.
* @param source The {@link VRMHumanoid} you want to copy
* @returns this
*/
copy(source) {
this.autoUpdateHumanBones = source.autoUpdateHumanBones;
this._rawHumanBones = new VRMRig(source.humanBones);
this._normalizedHumanBones = new VRMHumanoidRig(this._rawHumanBones);
return this;
}
/**
* Returns a clone of this {@link VRMHumanoid}.
* @returns Copied {@link VRMHumanoid}
*/
clone() {
return new _VRMHumanoid(this.humanBones, { autoUpdateHumanBones: this.autoUpdateHumanBones }).copy(this);
}
/**
* @deprecated Deprecated. Use either {@link getRawAbsolutePose} or {@link getNormalizedAbsolutePose} instead.
*/
getAbsolutePose() {
console.warn("VRMHumanoid: getAbsolutePose() is deprecated. Use either getRawAbsolutePose() or getNormalizedAbsolutePose() instead.");
return this.getRawAbsolutePose();
}
/**
* Return the current absolute pose of this raw human bones as a {@link VRMPose}.
* Note that the output result will contain initial state of the VRM and not compatible between different models.
* You might want to use {@link getRawPose} instead.
*/
getRawAbsolutePose() {
return this._rawHumanBones.getAbsolutePose();
}
/**
* Return the current absolute pose of this normalized human bones as a {@link VRMPose}.
* Note that the output result will contain initial state of the VRM and not compatible between different models.
* You might want to use {@link getNormalizedPose} instead.
*/
getNormalizedAbsolutePose() {
return this._normalizedHumanBones.getAbsolutePose();
}
/**
* @deprecated Deprecated. Use either {@link getRawPose} or {@link getNormalizedPose} instead.
*/
getPose() {
console.warn("VRMHumanoid: getPose() is deprecated. Use either getRawPose() or getNormalizedPose() instead.");
return this.getRawPose();
}
/**
* Return the current pose of raw human bones as a {@link VRMPose}.
*
* Each transform is a local transform relative from rest pose (T-pose).
*/
getRawPose() {
return this._rawHumanBones.getPose();
}
/**
* Return the current pose of normalized human bones as a {@link VRMPose}.
*
* Each transform is a local transform relative from rest pose (T-pose).
*/
getNormalizedPose() {
return this._normalizedHumanBones.getPose();
}
/**
* @deprecated Deprecated. Use either {@link setRawPose} or {@link setNormalizedPose} instead.
*/
setPose(poseObject) {
console.warn("VRMHumanoid: setPose() is deprecated. Use either setRawPose() or setNormalizedPose() instead.");
return this.setRawPose(poseObject);
}
/**
* Let the raw human bones do a specified pose.
*
* Each transform have to be a local transform relative from rest pose (T-pose).
* You can pass what you got from {@link getRawPose}.
*
* If you are using {@link autoUpdateHumanBones}, you might want to use {@link setNormalizedPose} instead.
*
* @param poseObject A {@link VRMPose} that represents a single pose
*/
setRawPose(poseObject) {
return this._rawHumanBones.setPose(poseObject);
}
/**
* Let the normalized human bones do a specified pose.
*
* Each transform have to be a local transform relative from rest pose (T-pose).
* You can pass what you got from {@link getNormalizedPose}.
*
* @param poseObject A {@link VRMPose} that represents a single pose
*/
setNormalizedPose(poseObject) {
return this._normalizedHumanBones.setPose(poseObject);
}
/**
* @deprecated Deprecated. Use either {@link resetRawPose} or {@link resetNormalizedPose} instead.
*/
resetPose() {
console.warn("VRMHumanoid: resetPose() is deprecated. Use either resetRawPose() or resetNormalizedPose() instead.");
return this.resetRawPose();
}
/**
* Reset the raw humanoid to its rest pose.
*
* If you are using {@link autoUpdateHumanBones}, you might want to use {@link resetNormalizedPose} instead.
*/
resetRawPose() {
return this._rawHumanBones.resetPose();
}
/**
* Reset the normalized humanoid to its rest pose.
*/
resetNormalizedPose() {
return this._normalizedHumanBones.resetPose();
}
/**
* @deprecated Deprecated. Use either {@link getRawBone} or {@link getNormalizedBone} instead.
*/
getBone(name) {
console.warn("VRMHumanoid: getBone() is deprecated. Use either getRawBone() or getNormalizedBone() instead.");
return this.getRawBone(name);
}
/**
* Return a raw {@link VRMHumanBone} bound to a specified {@link VRMHumanBoneName}.
*
* @param name Name of the bone you want
*/
getRawBone(name) {
return this._rawHumanBones.getBone(name);
}
/**
* Return a normalized {@link VRMHumanBone} bound to a specified {@link VRMHumanBoneName}.
*
* @param name Name of the bone you want
*/
getNormalizedBone(name) {
return this._normalizedHumanBones.getBone(name);
}
/**
* @deprecated Deprecated. Use either {@link getRawBoneNode} or {@link getNormalizedBoneNode} instead.
*/
getBoneNode(name) {
console.warn("VRMHumanoid: getBoneNode() is deprecated. Use either getRawBoneNode() or getNormalizedBoneNode() instead.");
return this.getRawBoneNode(name);
}
/**
* Return a raw bone as a `THREE.Object3D` bound to a specified {@link VRMHumanBoneName}.
*
* @param name Name of the bone you want
*/
getRawBoneNode(name) {
return this._rawHumanBones.getBoneNode(name);
}
/**
* Return a normalized bone as a `THREE.Object3D` bound to a specified {@link VRMHumanBoneName}.
*
* @param name Name of the bone you want
*/
getNormalizedBoneNode(name) {
return this._normalizedHumanBones.getBoneNode(name);
}
/**
* Update the humanoid component.
*
* If {@link autoUpdateHumanBones} is `true`, it transfers the pose of normalized human bones to raw human bones.
*/
update() {
if (this.autoUpdateHumanBones) this._normalizedHumanBones.update();
}
};
var VRMRequiredHumanBoneName = {
Hips: "hips",
Spine: "spine",
Head: "head",
LeftUpperLeg: "leftUpperLeg",
LeftLowerLeg: "leftLowerLeg",
LeftFoot: "leftFoot",
RightUpperLeg: "rightUpperLeg",
RightLowerLeg: "rightLowerLeg",
RightFoot: "rightFoot",
LeftUpperArm: "leftUpperArm",
LeftLowerArm: "leftLowerArm",
LeftHand: "leftHand",
RightUpperArm: "rightUpperArm",
RightLowerArm: "rightLowerArm",
RightHand: "rightHand"
};
var POSSIBLE_SPEC_VERSIONS3 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var thumbBoneNameMap = {
leftThumbProximal: "leftThumbMetacarpal",
leftThumbIntermediate: "leftThumbProximal",
rightThumbProximal: "rightThumbMetacarpal",
rightThumbIntermediate: "rightThumbProximal"
};
var VRMHumanoidLoaderPlugin = class {
get name() {
return "VRMHumanoidLoaderPlugin";
}
constructor(parser, options) {
this.parser = parser;
this.helperRoot = options == null ? void 0 : options.helperRoot;
this.autoUpdateHumanBones = options == null ? void 0 : options.autoUpdateHumanBones;
}
afterRoot(gltf) {
return __async2(this, null, function* () {
gltf.userData.vrmHumanoid = yield this._import(gltf);
});
}
/**
* Import a {@link VRMHumanoid} from a VRM.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
*/
_import(gltf) {
return __async2(this, null, function* () {
const v1Result = yield this._v1Import(gltf);
if (v1Result) return v1Result;
const v0Result = yield this._v0Import(gltf);
if (v0Result) return v0Result;
return null;
});
}
_v1Import(gltf) {
return __async2(this, null, function* () {
var _a, _b;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRMC_vrm")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRMC_vrm"];
if (!extension) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS3.has(specVersion)) {
console.warn(`VRMHumanoidLoaderPlugin: Unknown VRMC_vrm specVersion "${specVersion}"`);
return null;
}
const schemaHumanoid = extension.humanoid;
if (!schemaHumanoid) return null;
const existsPreviousThumbName = schemaHumanoid.humanBones.leftThumbIntermediate != null || schemaHumanoid.humanBones.rightThumbIntermediate != null;
const humanBones = {};
if (schemaHumanoid.humanBones != null) yield Promise.all(Object.entries(schemaHumanoid.humanBones).map((_0) => __async2(this, [_0], function* ([boneNameString, schemaHumanBone]) {
let boneName = boneNameString;
const index = schemaHumanBone.node;
if (existsPreviousThumbName) {
const thumbBoneName = thumbBoneNameMap[boneName];
if (thumbBoneName != null) boneName = thumbBoneName;
}
const node = yield this.parser.getDependency("node", index);
if (node == null) {
console.warn(`A glTF node bound to the humanoid bone ${boneName} (index = ${index}) does not exist`);
return;
}
humanBones[boneName] = { node };
})));
const humanoid = new VRMHumanoid(this._ensureRequiredBonesExist(humanBones), { autoUpdateHumanBones: this.autoUpdateHumanBones });
gltf.scene.add(humanoid.normalizedHumanBonesRoot);
if (this.helperRoot) {
const helper = new VRMHumanoidHelper(humanoid);
this.helperRoot.add(helper);
helper.renderOrder = this.helperRoot.renderOrder;
}
return humanoid;
});
}
_v0Import(gltf) {
return __async2(this, null, function* () {
var _a;
const vrmExt = (_a = this.parser.json.extensions) == null ? void 0 : _a.VRM;
if (!vrmExt) return null;
const schemaHumanoid = vrmExt.humanoid;
if (!schemaHumanoid) return null;
const humanBones = {};
if (schemaHumanoid.humanBones != null) yield Promise.all(schemaHumanoid.humanBones.map((bone) => __async2(this, null, function* () {
const boneName = bone.bone;
const index = bone.node;
if (boneName == null || index == null) return;
const node = yield this.parser.getDependency("node", index);
if (node == null) {
console.warn(`A glTF node bound to the humanoid bone ${boneName} (index = ${index}) does not exist`);
return;
}
const thumbBoneName = thumbBoneNameMap[boneName];
const newBoneName = thumbBoneName != null ? thumbBoneName : boneName;
if (humanBones[newBoneName] != null) {
console.warn(`Multiple bone entries for ${newBoneName} detected (index = ${index}), ignoring duplicated entries.`);
return;
}
humanBones[newBoneName] = { node };
})));
const humanoid = new VRMHumanoid(this._ensureRequiredBonesExist(humanBones), { autoUpdateHumanBones: this.autoUpdateHumanBones });
gltf.scene.add(humanoid.normalizedHumanBonesRoot);
if (this.helperRoot) {
const helper = new VRMHumanoidHelper(humanoid);
this.helperRoot.add(helper);
helper.renderOrder = this.helperRoot.renderOrder;
}
return humanoid;
});
}
/**
* Ensure required bones exist in given human bones.
* @param humanBones Human bones
* @returns Human bones, no longer partial!
*/
_ensureRequiredBonesExist(humanBones) {
const missingRequiredBones = Object.values(VRMRequiredHumanBoneName).filter((requiredBoneName) => humanBones[requiredBoneName] == null);
if (missingRequiredBones.length > 0) throw new Error(`VRMHumanoidLoaderPlugin: These humanoid bones are required but not exist: ${missingRequiredBones.join(", ")}`);
return humanBones;
}
};
var FanBufferGeometry = class extends BufferGeometry {
constructor() {
super();
this._currentTheta = 0;
this._currentRadius = 0;
this.theta = 0;
this.radius = 0;
this._currentTheta = 0;
this._currentRadius = 0;
this._attrPos = new BufferAttribute(new Float32Array(195), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(189), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
if (this._currentTheta !== this.theta) {
this._currentTheta = this.theta;
shouldUpdateGeometry = true;
}
if (this._currentRadius !== this.radius) {
this._currentRadius = this.radius;
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
this._attrPos.setXYZ(0, 0, 0, 0);
for (let i = 0; i < 64; i++) {
const t = i / 63 * this._currentTheta;
this._attrPos.setXYZ(i + 1, this._currentRadius * Math.sin(t), 0, this._currentRadius * Math.cos(t));
}
this._attrPos.needsUpdate = true;
}
_buildIndex() {
for (let i = 0; i < 63; i++) this._attrIndex.setXYZ(i * 3, 0, i + 1, i + 2);
this._attrIndex.needsUpdate = true;
}
};
var LineAndSphereBufferGeometry = class extends BufferGeometry {
constructor() {
super();
this.radius = 0;
this._currentRadius = 0;
this.tail = new Vector3();
this._currentTail = new Vector3();
this._attrPos = new BufferAttribute(new Float32Array(294), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(194), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
if (this._currentRadius !== this.radius) {
this._currentRadius = this.radius;
shouldUpdateGeometry = true;
}
if (!this._currentTail.equals(this.tail)) {
this._currentTail.copy(this.tail);
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
for (let i = 0; i < 32; i++) {
const t = i / 16 * Math.PI;
this._attrPos.setXYZ(i, Math.cos(t), Math.sin(t), 0);
this._attrPos.setXYZ(32 + i, 0, Math.cos(t), Math.sin(t));
this._attrPos.setXYZ(64 + i, Math.sin(t), 0, Math.cos(t));
}
this.scale(this._currentRadius, this._currentRadius, this._currentRadius);
this.translate(this._currentTail.x, this._currentTail.y, this._currentTail.z);
this._attrPos.setXYZ(96, 0, 0, 0);
this._attrPos.setXYZ(97, this._currentTail.x, this._currentTail.y, this._currentTail.z);
this._attrPos.needsUpdate = true;
}
_buildIndex() {
for (let i = 0; i < 32; i++) {
const i1 = (i + 1) % 32;
this._attrIndex.setXY(i * 2, i, i1);
this._attrIndex.setXY(64 + i * 2, 32 + i, 32 + i1);
this._attrIndex.setXY(128 + i * 2, 64 + i, 64 + i1);
}
this._attrIndex.setXY(192, 96, 97);
this._attrIndex.needsUpdate = true;
}
};
var _quatA4 = new Quaternion();
var _quatB = new Quaternion();
var _v3A4 = new Vector3();
var _v3B2 = new Vector3();
var SQRT_2_OVER_2 = Math.sqrt(2) / 2;
var QUAT_XY_CW90 = new Quaternion(0, 0, -SQRT_2_OVER_2, SQRT_2_OVER_2);
var VEC3_POSITIVE_Y = new Vector3(0, 1, 0);
var VRMLookAtHelper = class extends Group {
constructor(lookAt) {
super();
this.matrixAutoUpdate = false;
this.vrmLookAt = lookAt;
{
const geometry = new FanBufferGeometry();
geometry.radius = .5;
const material = new MeshBasicMaterial({
color: 65280,
transparent: true,
opacity: .5,
side: 2,
depthTest: false,
depthWrite: false
});
this._meshPitch = new Mesh(geometry, material);
this.add(this._meshPitch);
}
{
const geometry = new FanBufferGeometry();
geometry.radius = .5;
const material = new MeshBasicMaterial({
color: 16711680,
transparent: true,
opacity: .5,
side: 2,
depthTest: false,
depthWrite: false
});
this._meshYaw = new Mesh(geometry, material);
this.add(this._meshYaw);
}
{
const geometry = new LineAndSphereBufferGeometry();
geometry.radius = .1;
const material = new LineBasicMaterial({
color: 16777215,
depthTest: false,
depthWrite: false
});
this._lineTarget = new LineSegments(geometry, material);
this._lineTarget.frustumCulled = false;
this.add(this._lineTarget);
}
}
dispose() {
this._meshYaw.geometry.dispose();
this._meshYaw.material.dispose();
this._meshPitch.geometry.dispose();
this._meshPitch.material.dispose();
this._lineTarget.geometry.dispose();
this._lineTarget.material.dispose();
}
updateMatrixWorld(force) {
const yaw = MathUtils.DEG2RAD * this.vrmLookAt.yaw;
this._meshYaw.geometry.theta = yaw;
this._meshYaw.geometry.update();
const pitch = MathUtils.DEG2RAD * this.vrmLookAt.pitch;
this._meshPitch.geometry.theta = pitch;
this._meshPitch.geometry.update();
this.vrmLookAt.getLookAtWorldPosition(_v3A4);
this.vrmLookAt.getLookAtWorldQuaternion(_quatA4);
_quatA4.multiply(this.vrmLookAt.getFaceFrontQuaternion(_quatB));
this._meshYaw.position.copy(_v3A4);
this._meshYaw.quaternion.copy(_quatA4);
this._meshPitch.position.copy(_v3A4);
this._meshPitch.quaternion.copy(_quatA4);
this._meshPitch.quaternion.multiply(_quatB.setFromAxisAngle(VEC3_POSITIVE_Y, yaw));
this._meshPitch.quaternion.multiply(QUAT_XY_CW90);
const { target, autoUpdate } = this.vrmLookAt;
if (target != null && autoUpdate) {
target.getWorldPosition(_v3B2).sub(_v3A4);
this._lineTarget.geometry.tail.copy(_v3B2);
this._lineTarget.geometry.update();
this._lineTarget.position.copy(_v3A4);
}
super.updateMatrixWorld(force);
}
};
var _position = new Vector3();
var _scale = new Vector3();
function getWorldQuaternionLite(object, out) {
object.matrixWorld.decompose(_position, out, _scale);
return out;
}
function calcAzimuthAltitude(vector) {
return [Math.atan2(-vector.z, vector.x), Math.atan2(vector.y, Math.sqrt(vector.x * vector.x + vector.z * vector.z))];
}
function sanitizeAngle(angle) {
const roundTurn = Math.round(angle / 2 / Math.PI);
return angle - 2 * Math.PI * roundTurn;
}
var VEC3_POSITIVE_Z = new Vector3(0, 0, 1);
var _v3A5 = new Vector3();
var _v3B3 = new Vector3();
var _v3C = new Vector3();
var _quatA5 = new Quaternion();
var _quatB2 = new Quaternion();
var _quatC = new Quaternion();
var _quatD = new Quaternion();
var _eulerA = new Euler();
var _VRMLookAt = class _VRMLookAt2 {
/**
* Create a new {@link VRMLookAt}.
*
* @param humanoid A {@link VRMHumanoid}
* @param applier A {@link VRMLookAtApplier}
*/
constructor(humanoid, applier) {
this.offsetFromHeadBone = new Vector3();
this.autoUpdate = true;
this.faceFront = new Vector3(0, 0, 1);
this.humanoid = humanoid;
this.applier = applier;
this._yaw = 0;
this._pitch = 0;
this._needsUpdate = true;
this._restHeadWorldQuaternion = this.getLookAtWorldQuaternion(new Quaternion());
}
/**
* Its current angle around Y axis, in degree.
*/
get yaw() {
return this._yaw;
}
/**
* Its current angle around Y axis, in degree.
*/
set yaw(value) {
this._yaw = value;
this._needsUpdate = true;
}
/**
* Its current angle around X axis, in degree.
*/
get pitch() {
return this._pitch;
}
/**
* Its current angle around X axis, in degree.
*/
set pitch(value) {
this._pitch = value;
this._needsUpdate = true;
}
/**
* @deprecated Use {@link getEuler} instead.
*/
get euler() {
console.warn("VRMLookAt: euler is deprecated. use getEuler() instead.");
return this.getEuler(new Euler());
}
/**
* Get its yaw-pitch angles as an `Euler`.
* Does NOT consider {@link faceFront}; it returns `Euler(0, 0, 0; "YXZ")` by default regardless of the faceFront value.
*
* @param target The target euler
*/
getEuler(target) {
return target.set(MathUtils.DEG2RAD * this._pitch, MathUtils.DEG2RAD * this._yaw, 0, "YXZ");
}
/**
* Copy the given {@link VRMLookAt} into this one.
* {@link humanoid} must be same as the source one.
* {@link applier} will reference the same instance as the source one.
* @param source The {@link VRMLookAt} you want to copy
* @returns this
*/
copy(source) {
if (this.humanoid !== source.humanoid) throw new Error("VRMLookAt: humanoid must be same in order to copy");
this.offsetFromHeadBone.copy(source.offsetFromHeadBone);
this.applier = source.applier;
this.autoUpdate = source.autoUpdate;
this.target = source.target;
this.faceFront.copy(source.faceFront);
return this;
}
/**
* Returns a clone of this {@link VRMLookAt}.
* Note that {@link humanoid} and {@link applier} will reference the same instance as this one.
* @returns Copied {@link VRMLookAt}
*/
clone() {
return new _VRMLookAt2(this.humanoid, this.applier).copy(this);
}
/**
* Reset the lookAt direction (yaw and pitch) to the initial direction.
*/
reset() {
this._yaw = 0;
this._pitch = 0;
this._needsUpdate = true;
}
/**
* Get its lookAt position in world coordinate.
*
* @param target A target `THREE.Vector3`
*/
getLookAtWorldPosition(target) {
const head = this.humanoid.getRawBoneNode("head");
return target.copy(this.offsetFromHeadBone).applyMatrix4(head.matrixWorld);
}
/**
* Get its lookAt rotation in world coordinate.
* Does NOT consider {@link faceFront}.
*
* @param target A target `THREE.Quaternion`
*/
getLookAtWorldQuaternion(target) {
return getWorldQuaternionLite(this.humanoid.getRawBoneNode("head"), target);
}
/**
* Get a quaternion that rotates the +Z unit vector of the humanoid Head to the {@link faceFront} direction.
*
* @param target A target `THREE.Quaternion`
*/
getFaceFrontQuaternion(target) {
if (this.faceFront.distanceToSquared(VEC3_POSITIVE_Z) < .01) return target.copy(this._restHeadWorldQuaternion).invert();
const [faceFrontAzimuth, faceFrontAltitude] = calcAzimuthAltitude(this.faceFront);
_eulerA.set(0, .5 * Math.PI + faceFrontAzimuth, faceFrontAltitude, "YZX");
return target.setFromEuler(_eulerA).premultiply(_quatD.copy(this._restHeadWorldQuaternion).invert());
}
/**
* Get its LookAt direction in world coordinate.
*
* @param target A target `THREE.Vector3`
*/
getLookAtWorldDirection(target) {
this.getLookAtWorldQuaternion(_quatB2);
this.getFaceFrontQuaternion(_quatC);
return target.copy(VEC3_POSITIVE_Z).applyQuaternion(_quatB2).applyQuaternion(_quatC).applyEuler(this.getEuler(_eulerA));
}
/**
* Set its lookAt target position.
*
* Note that its result will be instantly overwritten if {@link VRMLookAtHead.autoUpdate} is enabled.
*
* If you want to track an object continuously, you might want to use {@link target} instead.
*
* @param position A target position, in world space
*/
lookAt(position) {
const headRotDiffInv = _quatA5.copy(this._restHeadWorldQuaternion).multiply(quatInvertCompat(this.getLookAtWorldQuaternion(_quatB2)));
const headPos = this.getLookAtWorldPosition(_v3B3);
const lookAtDir = _v3C.copy(position).sub(headPos).applyQuaternion(headRotDiffInv).normalize();
const [azimuthFrom, altitudeFrom] = calcAzimuthAltitude(this.faceFront);
const [azimuthTo, altitudeTo] = calcAzimuthAltitude(lookAtDir);
const yaw = sanitizeAngle(azimuthTo - azimuthFrom);
const pitch = sanitizeAngle(altitudeFrom - altitudeTo);
this._yaw = MathUtils.RAD2DEG * yaw;
this._pitch = MathUtils.RAD2DEG * pitch;
this._needsUpdate = true;
}
/**
* Update the VRMLookAtHead.
* If {@link autoUpdate} is enabled, this will make it look at the {@link target}.
*
* @param delta deltaTime, it isn't used though. You can use the parameter if you want to use this in your own extended {@link VRMLookAt}.
*/
update(delta) {
if (this.target != null && this.autoUpdate) this.lookAt(this.target.getWorldPosition(_v3A5));
if (this._needsUpdate) {
this._needsUpdate = false;
this.applier.applyYawPitch(this._yaw, this._pitch);
}
}
};
_VRMLookAt.EULER_ORDER = "YXZ";
var VRMLookAt = _VRMLookAt;
var VEC3_POSITIVE_Z2 = new Vector3(0, 0, 1);
var _quatA6 = new Quaternion();
var _quatB3 = new Quaternion();
var _eulerA2 = new Euler(0, 0, 0, "YXZ");
var VRMLookAtBoneApplier = class {
/**
* Create a new {@link VRMLookAtBoneApplier}.
*
* @param humanoid A {@link VRMHumanoid}
* @param rangeMapHorizontalInner A {@link VRMLookAtRangeMap} used for inner transverse direction
* @param rangeMapHorizontalOuter A {@link VRMLookAtRangeMap} used for outer transverse direction
* @param rangeMapVerticalDown A {@link VRMLookAtRangeMap} used for down direction
* @param rangeMapVerticalUp A {@link VRMLookAtRangeMap} used for up direction
*/
constructor(humanoid, rangeMapHorizontalInner, rangeMapHorizontalOuter, rangeMapVerticalDown, rangeMapVerticalUp) {
this.humanoid = humanoid;
this.rangeMapHorizontalInner = rangeMapHorizontalInner;
this.rangeMapHorizontalOuter = rangeMapHorizontalOuter;
this.rangeMapVerticalDown = rangeMapVerticalDown;
this.rangeMapVerticalUp = rangeMapVerticalUp;
this.faceFront = new Vector3(0, 0, 1);
this._restQuatLeftEye = new Quaternion();
this._restQuatRightEye = new Quaternion();
this._restLeftEyeParentWorldQuat = new Quaternion();
this._restRightEyeParentWorldQuat = new Quaternion();
const leftEye = this.humanoid.getRawBoneNode("leftEye");
const rightEye = this.humanoid.getRawBoneNode("rightEye");
if (leftEye) {
this._restQuatLeftEye.copy(leftEye.quaternion);
getWorldQuaternionLite(leftEye.parent, this._restLeftEyeParentWorldQuat);
}
if (rightEye) {
this._restQuatRightEye.copy(rightEye.quaternion);
getWorldQuaternionLite(rightEye.parent, this._restRightEyeParentWorldQuat);
}
}
/**
* Apply the input angle to its associated VRM model.
*
* @param yaw Rotation around Y axis, in degree
* @param pitch Rotation around X axis, in degree
*/
applyYawPitch(yaw, pitch) {
const leftEye = this.humanoid.getRawBoneNode("leftEye");
const rightEye = this.humanoid.getRawBoneNode("rightEye");
const leftEyeNormalized = this.humanoid.getNormalizedBoneNode("leftEye");
const rightEyeNormalized = this.humanoid.getNormalizedBoneNode("rightEye");
if (leftEye) {
if (pitch < 0) _eulerA2.x = -MathUtils.DEG2RAD * this.rangeMapVerticalDown.map(-pitch);
else _eulerA2.x = MathUtils.DEG2RAD * this.rangeMapVerticalUp.map(pitch);
if (yaw < 0) _eulerA2.y = -MathUtils.DEG2RAD * this.rangeMapHorizontalInner.map(-yaw);
else _eulerA2.y = MathUtils.DEG2RAD * this.rangeMapHorizontalOuter.map(yaw);
_quatA6.setFromEuler(_eulerA2);
this._getWorldFaceFrontQuat(_quatB3);
leftEyeNormalized.quaternion.copy(_quatB3).multiply(_quatA6).multiply(_quatB3.invert());
_quatA6.copy(this._restLeftEyeParentWorldQuat);
leftEye.quaternion.copy(leftEyeNormalized.quaternion).multiply(_quatA6).premultiply(_quatA6.invert()).multiply(this._restQuatLeftEye);
}
if (rightEye) {
if (pitch < 0) _eulerA2.x = -MathUtils.DEG2RAD * this.rangeMapVerticalDown.map(-pitch);
else _eulerA2.x = MathUtils.DEG2RAD * this.rangeMapVerticalUp.map(pitch);
if (yaw < 0) _eulerA2.y = -MathUtils.DEG2RAD * this.rangeMapHorizontalOuter.map(-yaw);
else _eulerA2.y = MathUtils.DEG2RAD * this.rangeMapHorizontalInner.map(yaw);
_quatA6.setFromEuler(_eulerA2);
this._getWorldFaceFrontQuat(_quatB3);
rightEyeNormalized.quaternion.copy(_quatB3).multiply(_quatA6).multiply(_quatB3.invert());
_quatA6.copy(this._restRightEyeParentWorldQuat);
rightEye.quaternion.copy(rightEyeNormalized.quaternion).multiply(_quatA6).premultiply(_quatA6.invert()).multiply(this._restQuatRightEye);
}
}
/**
* @deprecated Use {@link applyYawPitch} instead.
*/
lookAt(euler) {
console.warn("VRMLookAtBoneApplier: lookAt() is deprecated. use apply() instead.");
const yaw = MathUtils.RAD2DEG * euler.y;
const pitch = MathUtils.RAD2DEG * euler.x;
this.applyYawPitch(yaw, pitch);
}
/**
* Get a quaternion that rotates the world-space +Z unit vector to the {@link faceFront} direction.
*
* @param target A target `THREE.Quaternion`
*/
_getWorldFaceFrontQuat(target) {
if (this.faceFront.distanceToSquared(VEC3_POSITIVE_Z2) < .01) return target.identity();
const [faceFrontAzimuth, faceFrontAltitude] = calcAzimuthAltitude(this.faceFront);
_eulerA2.set(0, .5 * Math.PI + faceFrontAzimuth, faceFrontAltitude, "YZX");
return target.setFromEuler(_eulerA2);
}
};
VRMLookAtBoneApplier.type = "bone";
var VRMLookAtExpressionApplier = class {
/**
* Create a new {@link VRMLookAtExpressionApplier}.
*
* @param expressions A {@link VRMExpressionManager}
* @param rangeMapHorizontalInner A {@link VRMLookAtRangeMap} used for inner transverse direction
* @param rangeMapHorizontalOuter A {@link VRMLookAtRangeMap} used for outer transverse direction
* @param rangeMapVerticalDown A {@link VRMLookAtRangeMap} used for down direction
* @param rangeMapVerticalUp A {@link VRMLookAtRangeMap} used for up direction
*/
constructor(expressions, rangeMapHorizontalInner, rangeMapHorizontalOuter, rangeMapVerticalDown, rangeMapVerticalUp) {
this.expressions = expressions;
this.rangeMapHorizontalInner = rangeMapHorizontalInner;
this.rangeMapHorizontalOuter = rangeMapHorizontalOuter;
this.rangeMapVerticalDown = rangeMapVerticalDown;
this.rangeMapVerticalUp = rangeMapVerticalUp;
}
/**
* Apply the input angle to its associated VRM model.
*
* @param yaw Rotation around Y axis, in degree
* @param pitch Rotation around X axis, in degree
*/
applyYawPitch(yaw, pitch) {
if (pitch < 0) {
this.expressions.setValue("lookDown", 0);
this.expressions.setValue("lookUp", this.rangeMapVerticalUp.map(-pitch));
} else {
this.expressions.setValue("lookUp", 0);
this.expressions.setValue("lookDown", this.rangeMapVerticalDown.map(pitch));
}
if (yaw < 0) {
this.expressions.setValue("lookLeft", 0);
this.expressions.setValue("lookRight", this.rangeMapHorizontalOuter.map(-yaw));
} else {
this.expressions.setValue("lookRight", 0);
this.expressions.setValue("lookLeft", this.rangeMapHorizontalOuter.map(yaw));
}
}
/**
* @deprecated Use {@link applyYawPitch} instead.
*/
lookAt(euler) {
console.warn("VRMLookAtBoneApplier: lookAt() is deprecated. use apply() instead.");
const yaw = MathUtils.RAD2DEG * euler.y;
const pitch = MathUtils.RAD2DEG * euler.x;
this.applyYawPitch(yaw, pitch);
}
};
VRMLookAtExpressionApplier.type = "expression";
var VRMLookAtRangeMap = class {
/**
* Create a new {@link VRMLookAtRangeMap}.
*
* @param inputMaxValue The {@link inputMaxValue} of the map
* @param outputScale The {@link outputScale} of the map
*/
constructor(inputMaxValue, outputScale) {
this.inputMaxValue = inputMaxValue;
this.outputScale = outputScale;
}
/**
* Evaluate an input value and output a mapped value.
* @param src The input value
*/
map(src) {
return this.outputScale * saturate(src / this.inputMaxValue);
}
};
var POSSIBLE_SPEC_VERSIONS4 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var INPUT_MAX_VALUE_MINIMUM = .01;
var VRMLookAtLoaderPlugin = class {
get name() {
return "VRMLookAtLoaderPlugin";
}
constructor(parser, options) {
this.parser = parser;
this.helperRoot = options == null ? void 0 : options.helperRoot;
}
afterRoot(gltf) {
return __async2(this, null, function* () {
const vrmHumanoid = gltf.userData.vrmHumanoid;
if (vrmHumanoid === null) return;
else if (vrmHumanoid === void 0) throw new Error("VRMLookAtLoaderPlugin: vrmHumanoid is undefined. VRMHumanoidLoaderPlugin have to be used first");
const vrmExpressionManager = gltf.userData.vrmExpressionManager;
if (vrmExpressionManager === null) return;
else if (vrmExpressionManager === void 0) throw new Error("VRMLookAtLoaderPlugin: vrmExpressionManager is undefined. VRMExpressionLoaderPlugin have to be used first");
gltf.userData.vrmLookAt = yield this._import(gltf, vrmHumanoid, vrmExpressionManager);
});
}
/**
* Import a {@link VRMLookAt} from a VRM.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
* @param humanoid A {@link VRMHumanoid} instance that represents the VRM
* @param expressions A {@link VRMExpressionManager} instance that represents the VRM
*/
_import(gltf, humanoid, expressions) {
return __async2(this, null, function* () {
if (humanoid == null || expressions == null) return null;
const v1Result = yield this._v1Import(gltf, humanoid, expressions);
if (v1Result) return v1Result;
const v0Result = yield this._v0Import(gltf, humanoid, expressions);
if (v0Result) return v0Result;
return null;
});
}
_v1Import(gltf, humanoid, expressions) {
return __async2(this, null, function* () {
var _a, _b, _c;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRMC_vrm")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRMC_vrm"];
if (!extension) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS4.has(specVersion)) {
console.warn(`VRMLookAtLoaderPlugin: Unknown VRMC_vrm specVersion "${specVersion}"`);
return null;
}
const schemaLookAt = extension.lookAt;
if (!schemaLookAt) return null;
const defaultOutputScale = schemaLookAt.type === "expression" ? 1 : 10;
const mapHI = this._v1ImportRangeMap(schemaLookAt.rangeMapHorizontalInner, defaultOutputScale);
const mapHO = this._v1ImportRangeMap(schemaLookAt.rangeMapHorizontalOuter, defaultOutputScale);
const mapVD = this._v1ImportRangeMap(schemaLookAt.rangeMapVerticalDown, defaultOutputScale);
const mapVU = this._v1ImportRangeMap(schemaLookAt.rangeMapVerticalUp, defaultOutputScale);
let applier;
if (schemaLookAt.type === "expression") applier = new VRMLookAtExpressionApplier(expressions, mapHI, mapHO, mapVD, mapVU);
else applier = new VRMLookAtBoneApplier(humanoid, mapHI, mapHO, mapVD, mapVU);
const lookAt = this._importLookAt(humanoid, applier);
lookAt.offsetFromHeadBone.fromArray((_c = schemaLookAt.offsetFromHeadBone) != null ? _c : [
0,
.06,
0
]);
return lookAt;
});
}
_v1ImportRangeMap(schemaRangeMap, defaultOutputScale) {
var _a, _b;
let inputMaxValue = (_a = schemaRangeMap == null ? void 0 : schemaRangeMap.inputMaxValue) != null ? _a : 90;
const outputScale = (_b = schemaRangeMap == null ? void 0 : schemaRangeMap.outputScale) != null ? _b : defaultOutputScale;
if (inputMaxValue < INPUT_MAX_VALUE_MINIMUM) {
console.warn("VRMLookAtLoaderPlugin: inputMaxValue of a range map is too small. Consider reviewing the range map!");
inputMaxValue = INPUT_MAX_VALUE_MINIMUM;
}
return new VRMLookAtRangeMap(inputMaxValue, outputScale);
}
_v0Import(gltf, humanoid, expressions) {
return __async2(this, null, function* () {
var _a, _b, _c, _d;
const vrmExt = (_a = this.parser.json.extensions) == null ? void 0 : _a.VRM;
if (!vrmExt) return null;
const schemaFirstPerson = vrmExt.firstPerson;
if (!schemaFirstPerson) return null;
const defaultOutputScale = schemaFirstPerson.lookAtTypeName === "BlendShape" ? 1 : 10;
const mapHI = this._v0ImportDegreeMap(schemaFirstPerson.lookAtHorizontalInner, defaultOutputScale);
const mapHO = this._v0ImportDegreeMap(schemaFirstPerson.lookAtHorizontalOuter, defaultOutputScale);
const mapVD = this._v0ImportDegreeMap(schemaFirstPerson.lookAtVerticalDown, defaultOutputScale);
const mapVU = this._v0ImportDegreeMap(schemaFirstPerson.lookAtVerticalUp, defaultOutputScale);
let applier;
if (schemaFirstPerson.lookAtTypeName === "BlendShape") applier = new VRMLookAtExpressionApplier(expressions, mapHI, mapHO, mapVD, mapVU);
else applier = new VRMLookAtBoneApplier(humanoid, mapHI, mapHO, mapVD, mapVU);
const lookAt = this._importLookAt(humanoid, applier);
if (schemaFirstPerson.firstPersonBoneOffset) lookAt.offsetFromHeadBone.set((_b = schemaFirstPerson.firstPersonBoneOffset.x) != null ? _b : 0, (_c = schemaFirstPerson.firstPersonBoneOffset.y) != null ? _c : .06, -((_d = schemaFirstPerson.firstPersonBoneOffset.z) != null ? _d : 0));
else lookAt.offsetFromHeadBone.set(0, .06, 0);
lookAt.faceFront.set(0, 0, -1);
if (applier instanceof VRMLookAtBoneApplier) applier.faceFront.set(0, 0, -1);
return lookAt;
});
}
_v0ImportDegreeMap(schemaDegreeMap, defaultOutputScale) {
var _a, _b;
const curve = schemaDegreeMap == null ? void 0 : schemaDegreeMap.curve;
if (JSON.stringify(curve) !== "[0,0,0,1,1,1,1,0]") console.warn("Curves of LookAtDegreeMap defined in VRM 0.0 are not supported");
let xRange = (_a = schemaDegreeMap == null ? void 0 : schemaDegreeMap.xRange) != null ? _a : 90;
const yRange = (_b = schemaDegreeMap == null ? void 0 : schemaDegreeMap.yRange) != null ? _b : defaultOutputScale;
if (xRange < INPUT_MAX_VALUE_MINIMUM) {
console.warn("VRMLookAtLoaderPlugin: xRange of a degree map is too small. Consider reviewing the degree map!");
xRange = INPUT_MAX_VALUE_MINIMUM;
}
return new VRMLookAtRangeMap(xRange, yRange);
}
_importLookAt(humanoid, applier) {
const lookAt = new VRMLookAt(humanoid, applier);
if (this.helperRoot) {
const helper = new VRMLookAtHelper(lookAt);
this.helperRoot.add(helper);
helper.renderOrder = this.helperRoot.renderOrder;
}
return lookAt;
}
};
var VRMLookAtTypeName = {
Bone: "bone",
Expression: "expression"
};
function resolveURL(url, path) {
if (typeof url !== "string" || url === "") return "";
if (/^https?:\/\//i.test(path) && /^\//.test(url)) path = path.replace(/(^https?:\/\/[^/]+).*/i, "$1");
if (/^(https?:)?\/\//i.test(url)) return url;
if (/^data:.*,.*$/i.test(url)) return url;
if (/^blob:.*$/i.test(url)) return url;
return path + url;
}
var POSSIBLE_SPEC_VERSIONS5 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var VRMMetaLoaderPlugin = class {
get name() {
return "VRMMetaLoaderPlugin";
}
constructor(parser, options) {
var _a, _b, _c;
this.parser = parser;
this.needThumbnailImage = (_a = options == null ? void 0 : options.needThumbnailImage) != null ? _a : false;
this.acceptLicenseUrls = (_b = options == null ? void 0 : options.acceptLicenseUrls) != null ? _b : ["https://vrm.dev/licenses/1.0/"];
this.acceptV0Meta = (_c = options == null ? void 0 : options.acceptV0Meta) != null ? _c : true;
}
afterRoot(gltf) {
return __async2(this, null, function* () {
gltf.userData.vrmMeta = yield this._import(gltf);
});
}
_import(gltf) {
return __async2(this, null, function* () {
const v1Result = yield this._v1Import(gltf);
if (v1Result != null) return v1Result;
const v0Result = yield this._v0Import(gltf);
if (v0Result != null) return v0Result;
return null;
});
}
_v1Import(gltf) {
return __async2(this, null, function* () {
var _a, _b, _c;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRMC_vrm")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRMC_vrm"];
if (extension == null) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS5.has(specVersion)) {
console.warn(`VRMMetaLoaderPlugin: Unknown VRMC_vrm specVersion "${specVersion}"`);
return null;
}
const schemaMeta = extension.meta;
if (!schemaMeta) return null;
const licenseUrl = schemaMeta.licenseUrl;
if (!new Set(this.acceptLicenseUrls).has(licenseUrl)) throw new Error(`VRMMetaLoaderPlugin: The license url "${licenseUrl}" is not accepted`);
let thumbnailImage = void 0;
if (this.needThumbnailImage && schemaMeta.thumbnailImage != null) thumbnailImage = (_c = yield this._extractGLTFImage(schemaMeta.thumbnailImage)) != null ? _c : void 0;
return {
metaVersion: "1",
name: schemaMeta.name,
version: schemaMeta.version,
authors: schemaMeta.authors,
copyrightInformation: schemaMeta.copyrightInformation,
contactInformation: schemaMeta.contactInformation,
references: schemaMeta.references,
thirdPartyLicenses: schemaMeta.thirdPartyLicenses,
thumbnailImage,
licenseUrl: schemaMeta.licenseUrl,
avatarPermission: schemaMeta.avatarPermission,
allowExcessivelyViolentUsage: schemaMeta.allowExcessivelyViolentUsage,
allowExcessivelySexualUsage: schemaMeta.allowExcessivelySexualUsage,
commercialUsage: schemaMeta.commercialUsage,
allowPoliticalOrReligiousUsage: schemaMeta.allowPoliticalOrReligiousUsage,
allowAntisocialOrHateUsage: schemaMeta.allowAntisocialOrHateUsage,
creditNotation: schemaMeta.creditNotation,
allowRedistribution: schemaMeta.allowRedistribution,
modification: schemaMeta.modification,
otherLicenseUrl: schemaMeta.otherLicenseUrl
};
});
}
_v0Import(gltf) {
return __async2(this, null, function* () {
var _a;
const vrmExt = (_a = this.parser.json.extensions) == null ? void 0 : _a.VRM;
if (!vrmExt) return null;
const schemaMeta = vrmExt.meta;
if (!schemaMeta) return null;
if (!this.acceptV0Meta) throw new Error("VRMMetaLoaderPlugin: Attempted to load VRM0.0 meta but acceptV0Meta is false");
let texture;
if (this.needThumbnailImage && schemaMeta.texture != null && schemaMeta.texture !== -1) texture = yield this.parser.getDependency("texture", schemaMeta.texture);
return {
metaVersion: "0",
allowedUserName: schemaMeta.allowedUserName,
author: schemaMeta.author,
commercialUssageName: schemaMeta.commercialUssageName,
contactInformation: schemaMeta.contactInformation,
licenseName: schemaMeta.licenseName,
otherLicenseUrl: schemaMeta.otherLicenseUrl,
otherPermissionUrl: schemaMeta.otherPermissionUrl,
reference: schemaMeta.reference,
sexualUssageName: schemaMeta.sexualUssageName,
texture: texture != null ? texture : void 0,
title: schemaMeta.title,
version: schemaMeta.version,
violentUssageName: schemaMeta.violentUssageName
};
});
}
_extractGLTFImage(index) {
return __async2(this, null, function* () {
var _a;
const source = (_a = this.parser.json.images) == null ? void 0 : _a[index];
if (source == null) {
console.warn(`VRMMetaLoaderPlugin: Attempt to use images[${index}] of glTF as a thumbnail but the image doesn't exist`);
return null;
}
let sourceURI = source.uri;
if (source.bufferView != null) {
const bufferView = yield this.parser.getDependency("bufferView", source.bufferView);
const blob = new Blob([bufferView], { type: source.mimeType });
sourceURI = URL.createObjectURL(blob);
}
if (sourceURI == null) {
console.warn(`VRMMetaLoaderPlugin: Attempt to use images[${index}] of glTF as a thumbnail but the image couldn't load properly`);
return null;
}
return yield new ImageLoader().loadAsync(resolveURL(sourceURI, this.parser.options.path)).catch((error) => {
console.error(error);
console.warn("VRMMetaLoaderPlugin: Failed to load a thumbnail image");
return null;
});
});
}
};
var VRMCore = class {
/**
* Create a new VRM instance.
*
* @param params {@link VRMParameters} that represents components of the VRM
*/
constructor(params) {
this.scene = params.scene;
this.meta = params.meta;
this.humanoid = params.humanoid;
this.expressionManager = params.expressionManager;
this.firstPerson = params.firstPerson;
this.lookAt = params.lookAt;
}
/**
* **You need to call this on your update loop.**
*
* This function updates every VRM components.
*
* @param delta deltaTime
*/
update(delta) {
this.humanoid.update();
if (this.lookAt) this.lookAt.update(delta);
if (this.expressionManager) this.expressionManager.update();
}
};
var VRMCoreLoaderPlugin = class {
get name() {
return "VRMC_vrm";
}
constructor(parser, options) {
var _a, _b, _c, _d, _e;
this.parser = parser;
const helperRoot = options == null ? void 0 : options.helperRoot;
const autoUpdateHumanBones = options == null ? void 0 : options.autoUpdateHumanBones;
this.expressionPlugin = (_a = options == null ? void 0 : options.expressionPlugin) != null ? _a : new VRMExpressionLoaderPlugin(parser);
this.firstPersonPlugin = (_b = options == null ? void 0 : options.firstPersonPlugin) != null ? _b : new VRMFirstPersonLoaderPlugin(parser);
this.humanoidPlugin = (_c = options == null ? void 0 : options.humanoidPlugin) != null ? _c : new VRMHumanoidLoaderPlugin(parser, {
helperRoot,
autoUpdateHumanBones
});
this.lookAtPlugin = (_d = options == null ? void 0 : options.lookAtPlugin) != null ? _d : new VRMLookAtLoaderPlugin(parser, { helperRoot });
this.metaPlugin = (_e = options == null ? void 0 : options.metaPlugin) != null ? _e : new VRMMetaLoaderPlugin(parser);
}
afterRoot(gltf) {
return __async2(this, null, function* () {
yield this.metaPlugin.afterRoot(gltf);
yield this.humanoidPlugin.afterRoot(gltf);
yield this.expressionPlugin.afterRoot(gltf);
yield this.lookAtPlugin.afterRoot(gltf);
yield this.firstPersonPlugin.afterRoot(gltf);
const meta = gltf.userData.vrmMeta;
const humanoid = gltf.userData.vrmHumanoid;
if (meta && humanoid) {
const vrmCore = new VRMCore({
scene: gltf.scene,
expressionManager: gltf.userData.vrmExpressionManager,
firstPerson: gltf.userData.vrmFirstPerson,
humanoid,
lookAt: gltf.userData.vrmLookAt,
meta
});
gltf.userData.vrmCore = vrmCore;
}
});
}
};
var VRM = class extends VRMCore {
/**
* Create a new VRM instance.
*
* @param params {@link VRMParameters} that represents components of the VRM
*/
constructor(params) {
super(params);
this.materials = params.materials;
this.springBoneManager = params.springBoneManager;
this.nodeConstraintManager = params.nodeConstraintManager;
}
/**
* **You need to call this on your update loop.**
*
* This function updates every VRM components.
*
* @param delta deltaTime
*/
update(delta) {
super.update(delta);
if (this.nodeConstraintManager) this.nodeConstraintManager.update();
if (this.springBoneManager) this.springBoneManager.update(delta);
if (this.materials) this.materials.forEach((material) => {
if (material.update) material.update(delta);
});
}
};
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
enumerable: true,
configurable: true,
writable: true,
value
}) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols) {
for (var prop of __getOwnPropSymbols(b)) if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
}
return a;
};
var __async3 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var colorSpaceEncodingMap = {
"": 3e3,
srgb: 3001
};
function setTextureColorSpace(texture, colorSpace) {
if (parseInt("179", 10) >= 152) texture.colorSpace = colorSpace;
else texture.encoding = colorSpaceEncodingMap[colorSpace];
}
var GLTFMToonMaterialParamsAssignHelper = class {
get pending() {
return Promise.all(this._pendings);
}
constructor(parser, materialParams) {
this._parser = parser;
this._materialParams = materialParams;
this._pendings = [];
}
assignPrimitive(key, value) {
if (value != null) this._materialParams[key] = value;
}
assignColor(key, value, convertSRGBToLinear) {
if (value != null) {
this._materialParams[key] = new Color().fromArray(value);
if (convertSRGBToLinear) this._materialParams[key].convertSRGBToLinear();
}
}
assignTexture(key, texture, isColorTexture) {
return __async3(this, null, function* () {
const promise = __async3(this, null, function* () {
if (texture != null) {
yield this._parser.assignTexture(this._materialParams, key, texture);
if (isColorTexture) setTextureColorSpace(this._materialParams[key], "srgb");
}
});
this._pendings.push(promise);
return promise;
});
}
assignTextureByIndex(key, textureIndex, isColorTexture) {
return __async3(this, null, function* () {
return this.assignTexture(key, textureIndex != null ? { index: textureIndex } : void 0, isColorTexture);
});
}
};
var mtoon_default = "// #define PHONG\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n varying vec3 vNormal;\n#endif\n\n#include <common>\n\n// #include <uv_pars_vertex>\n#ifdef MTOON_USE_UV\n varying vec2 vUv;\n\n // COMPAT: pre-r151 uses a common uvTransform\n #if THREE_VRM_THREE_REVISION < 151\n uniform mat3 uvTransform;\n #endif\n#endif\n\n// #include <uv2_pars_vertex>\n// COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n#if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n attribute vec2 uv2;\n varying vec2 vUv2;\n uniform mat3 uv2Transform;\n #endif\n#endif\n\n// #include <displacementmap_pars_vertex>\n// #include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n\n#ifdef USE_OUTLINEWIDTHMULTIPLYTEXTURE\n uniform sampler2D outlineWidthMultiplyTexture;\n uniform mat3 outlineWidthMultiplyTextureUvTransform;\n#endif\n\nuniform float outlineWidthFactor;\n\nvoid main() {\n\n // #include <uv_vertex>\n #ifdef MTOON_USE_UV\n // COMPAT: pre-r151 uses a common uvTransform\n #if THREE_VRM_THREE_REVISION >= 151\n vUv = uv;\n #else\n vUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n #endif\n #endif\n\n // #include <uv2_vertex>\n // COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n #if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n vUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n #endif\n #endif\n\n #include <color_vertex>\n\n #include <beginnormal_vertex>\n #include <morphnormal_vertex>\n #include <skinbase_vertex>\n #include <skinnormal_vertex>\n\n // we need this to compute the outline properly\n objectNormal = normalize( objectNormal );\n\n #include <defaultnormal_vertex>\n\n #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\n vNormal = normalize( transformedNormal );\n #endif\n\n #include <begin_vertex>\n\n #include <morphtarget_vertex>\n #include <skinning_vertex>\n // #include <displacementmap_vertex>\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n\n vViewPosition = - mvPosition.xyz;\n\n #ifdef OUTLINE\n float worldNormalLength = length( transformedNormal );\n vec3 outlineOffset = outlineWidthFactor * worldNormalLength * objectNormal;\n\n #ifdef USE_OUTLINEWIDTHMULTIPLYTEXTURE\n vec2 outlineWidthMultiplyTextureUv = ( outlineWidthMultiplyTextureUvTransform * vec3( vUv, 1 ) ).xy;\n float outlineTex = texture2D( outlineWidthMultiplyTexture, outlineWidthMultiplyTextureUv ).g;\n outlineOffset *= outlineTex;\n #endif\n\n #ifdef OUTLINE_WIDTH_SCREEN\n outlineOffset *= vViewPosition.z / projectionMatrix[ 1 ].y;\n #endif\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( outlineOffset + transformed, 1.0 );\n\n gl_Position.z += 1E-6 * gl_Position.w; // anti-artifact magic\n #endif\n\n #include <worldpos_vertex>\n // #include <envmap_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n\n}";
var mtoon_default2 = "// #define PHONG\n\nuniform vec3 litFactor;\n\nuniform float opacity;\n\nuniform vec3 shadeColorFactor;\n#ifdef USE_SHADEMULTIPLYTEXTURE\n uniform sampler2D shadeMultiplyTexture;\n uniform mat3 shadeMultiplyTextureUvTransform;\n#endif\n\nuniform float shadingShiftFactor;\nuniform float shadingToonyFactor;\n\n#ifdef USE_SHADINGSHIFTTEXTURE\n uniform sampler2D shadingShiftTexture;\n uniform mat3 shadingShiftTextureUvTransform;\n uniform float shadingShiftTextureScale;\n#endif\n\nuniform float giEqualizationFactor;\n\nuniform vec3 parametricRimColorFactor;\n#ifdef USE_RIMMULTIPLYTEXTURE\n uniform sampler2D rimMultiplyTexture;\n uniform mat3 rimMultiplyTextureUvTransform;\n#endif\nuniform float rimLightingMixFactor;\nuniform float parametricRimFresnelPowerFactor;\nuniform float parametricRimLiftFactor;\n\n#ifdef USE_MATCAPTEXTURE\n uniform vec3 matcapFactor;\n uniform sampler2D matcapTexture;\n uniform mat3 matcapTextureUvTransform;\n#endif\n\nuniform vec3 emissive;\nuniform float emissiveIntensity;\n\nuniform vec3 outlineColorFactor;\nuniform float outlineLightingMixFactor;\n\n#ifdef USE_UVANIMATIONMASKTEXTURE\n uniform sampler2D uvAnimationMaskTexture;\n uniform mat3 uvAnimationMaskTextureUvTransform;\n#endif\n\nuniform float uvAnimationScrollXOffset;\nuniform float uvAnimationScrollYOffset;\nuniform float uvAnimationRotationPhase;\n\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n\n// #include <uv_pars_fragment>\n#if ( defined( MTOON_USE_UV ) && !defined( MTOON_UVS_VERTEX_ONLY ) )\n varying vec2 vUv;\n#endif\n\n// #include <uv2_pars_fragment>\n// COMAPT: pre-r151 uses uv2 for lightMap and aoMap\n#if THREE_VRM_THREE_REVISION < 151\n #if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n varying vec2 vUv2;\n #endif\n#endif\n\n#include <map_pars_fragment>\n\n#ifdef USE_MAP\n uniform mat3 mapUvTransform;\n#endif\n\n// #include <alphamap_pars_fragment>\n\n#include <alphatest_pars_fragment>\n\n#include <aomap_pars_fragment>\n// #include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n\n#ifdef USE_EMISSIVEMAP\n uniform mat3 emissiveMapUvTransform;\n#endif\n\n// #include <envmap_common_pars_fragment>\n// #include <envmap_pars_fragment>\n// #include <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n\n// #include <bsdfs>\n// COMPAT: pre-r151 doesn't have BRDF_Lambert in <common>\n#if THREE_VRM_THREE_REVISION < 151\n vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n return RECIPROCAL_PI * diffuseColor;\n }\n#endif\n\n#include <lights_pars_begin>\n\n#include <normal_pars_fragment>\n\n// #include <lights_phong_pars_fragment>\nvarying vec3 vViewPosition;\n\nstruct MToonMaterial {\n vec3 diffuseColor;\n vec3 shadeColor;\n float shadingShift;\n};\n\nfloat linearstep( float a, float b, float t ) {\n return clamp( ( t - a ) / ( b - a ), 0.0, 1.0 );\n}\n\n/**\n * Convert NdotL into toon shading factor using shadingShift and shadingToony\n */\nfloat getShading(\n const in float dotNL,\n const in float shadow,\n const in float shadingShift\n) {\n float shading = dotNL;\n shading = shading + shadingShift;\n shading = linearstep( -1.0 + shadingToonyFactor, 1.0 - shadingToonyFactor, shading );\n shading *= shadow;\n return shading;\n}\n\n/**\n * Mix diffuseColor and shadeColor using shading factor and light color\n */\nvec3 getDiffuse(\n const in MToonMaterial material,\n const in float shading,\n in vec3 lightColor\n) {\n #ifdef DEBUG_LITSHADERATE\n return vec3( BRDF_Lambert( shading * lightColor ) );\n #endif\n\n vec3 col = lightColor * BRDF_Lambert( mix( material.shadeColor, material.diffuseColor, shading ) );\n\n // The \"comment out if you want to PBR absolutely\" line\n #ifdef V0_COMPAT_SHADE\n col = min( col, material.diffuseColor );\n #endif\n\n return col;\n}\n\n// COMPAT: pre-r156 uses a struct GeometricContext\n#if THREE_VRM_THREE_REVISION >= 157\n void RE_Direct_MToon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const
var MToonMaterialDebugMode = {
/**
* Render normally.
*/
None: "none",
/**
* Visualize normals of the surface.
*/
Normal: "normal",
/**
* Visualize lit/shade of the surface.
*/
LitShadeRate: "litShadeRate",
/**
* Visualize UV of the surface.
*/
UV: "uv"
};
var MToonMaterialOutlineWidthMode = {
None: "none",
WorldCoordinates: "worldCoordinates",
ScreenCoordinates: "screenCoordinates"
};
var encodingColorSpaceMap = {
3e3: "",
3001: "srgb"
};
function getTextureColorSpace(texture) {
if (parseInt("179", 10) >= 152) return texture.colorSpace;
else return encodingColorSpaceMap[texture.encoding];
}
var MToonMaterial = class extends ShaderMaterial {
constructor(parameters = {}) {
var _a;
super({
vertexShader: mtoon_default,
fragmentShader: mtoon_default2
});
this.uvAnimationScrollXSpeedFactor = 0;
this.uvAnimationScrollYSpeedFactor = 0;
this.uvAnimationRotationSpeedFactor = 0;
this.fog = true;
this.normalMapType = 0;
this._ignoreVertexColor = true;
this._v0CompatShade = false;
this._debugMode = MToonMaterialDebugMode.None;
this._outlineWidthMode = MToonMaterialOutlineWidthMode.None;
this._isOutline = false;
if (parameters.transparentWithZWrite) parameters.depthWrite = true;
delete parameters.transparentWithZWrite;
parameters.fog = true;
parameters.lights = true;
parameters.clipping = true;
this.uniforms = UniformsUtils.merge([
UniformsLib.common,
UniformsLib.normalmap,
UniformsLib.emissivemap,
UniformsLib.fog,
UniformsLib.lights,
{
litFactor: { value: new Color(1, 1, 1) },
mapUvTransform: { value: new Matrix3() },
colorAlpha: { value: 1 },
normalMapUvTransform: { value: new Matrix3() },
shadeColorFactor: { value: new Color(0, 0, 0) },
shadeMultiplyTexture: { value: null },
shadeMultiplyTextureUvTransform: { value: new Matrix3() },
shadingShiftFactor: { value: 0 },
shadingShiftTexture: { value: null },
shadingShiftTextureUvTransform: { value: new Matrix3() },
shadingShiftTextureScale: { value: 1 },
shadingToonyFactor: { value: .9 },
giEqualizationFactor: { value: .9 },
matcapFactor: { value: new Color(1, 1, 1) },
matcapTexture: { value: null },
matcapTextureUvTransform: { value: new Matrix3() },
parametricRimColorFactor: { value: new Color(0, 0, 0) },
rimMultiplyTexture: { value: null },
rimMultiplyTextureUvTransform: { value: new Matrix3() },
rimLightingMixFactor: { value: 1 },
parametricRimFresnelPowerFactor: { value: 5 },
parametricRimLiftFactor: { value: 0 },
emissive: { value: new Color(0, 0, 0) },
emissiveIntensity: { value: 1 },
emissiveMapUvTransform: { value: new Matrix3() },
outlineWidthMultiplyTexture: { value: null },
outlineWidthMultiplyTextureUvTransform: { value: new Matrix3() },
outlineWidthFactor: { value: 0 },
outlineColorFactor: { value: new Color(0, 0, 0) },
outlineLightingMixFactor: { value: 1 },
uvAnimationMaskTexture: { value: null },
uvAnimationMaskTextureUvTransform: { value: new Matrix3() },
uvAnimationScrollXOffset: { value: 0 },
uvAnimationScrollYOffset: { value: 0 },
uvAnimationRotationPhase: { value: 0 }
},
(_a = parameters.uniforms) != null ? _a : {}
]);
this.setValues(parameters);
this._uploadUniformsWorkaround();
this.customProgramCacheKey = () => [
...Object.entries(this._generateDefines()).map(([token, macro]) => `${token}:${macro}`),
this.matcapTexture ? `matcapTextureColorSpace:${getTextureColorSpace(this.matcapTexture)}` : "",
this.shadeMultiplyTexture ? `shadeMultiplyTextureColorSpace:${getTextureColorSpace(this.shadeMultiplyTexture)}` : "",
this.rimMultiplyTexture ? `rimMultiplyTextureColorSpace:${getTextureColorSpace(this.rimMultiplyTexture)}` : ""
].join(",");
this.onBeforeCompile = (shader) => {
const defines = Object.entries(__spreadValues(__spreadValues({}, this._generateDefines()), this.defines)).filter(([token, macro]) => !!macro).map(([token, macro]) => `#define ${token} ${macro}`).join("\n") + "\n";
shader.vertexShader = defines + shader.vertexShader;
shader.fragmentShader = defines + shader.fragmentShader;
};
}
get color() {
return this.uniforms.litFactor.value;
}
set color(value) {
this.uniforms.litFactor.value = value;
}
get map() {
return this.uniforms.map.value;
}
set map(value) {
this.uniforms.map.value = value;
}
get normalMap() {
return this.uniforms.normalMap.value;
}
set normalMap(value) {
this.uniforms.normalMap.value = value;
}
get normalScale() {
return this.uniforms.normalScale.value;
}
set normalScale(value) {
this.uniforms.normalScale.value = value;
}
get emissive() {
return this.uniforms.emissive.value;
}
set emissive(value) {
this.uniforms.emissive.value = value;
}
get emissiveIntensity() {
return this.uniforms.emissiveIntensity.value;
}
set emissiveIntensity(value) {
this.uniforms.emissiveIntensity.value = value;
}
get emissiveMap() {
return this.uniforms.emissiveMap.value;
}
set emissiveMap(value) {
this.uniforms.emissiveMap.value = value;
}
get shadeColorFactor() {
return this.uniforms.shadeColorFactor.value;
}
set shadeColorFactor(value) {
this.uniforms.shadeColorFactor.value = value;
}
get shadeMultiplyTexture() {
return this.uniforms.shadeMultiplyTexture.value;
}
set shadeMultiplyTexture(value) {
this.uniforms.shadeMultiplyTexture.value = value;
}
get shadingShiftFactor() {
return this.uniforms.shadingShiftFactor.value;
}
set shadingShiftFactor(value) {
this.uniforms.shadingShiftFactor.value = value;
}
get shadingShiftTexture() {
return this.uniforms.shadingShiftTexture.value;
}
set shadingShiftTexture(value) {
this.uniforms.shadingShiftTexture.value = value;
}
get shadingShiftTextureScale() {
return this.uniforms.shadingShiftTextureScale.value;
}
set shadingShiftTextureScale(value) {
this.uniforms.shadingShiftTextureScale.value = value;
}
get shadingToonyFactor() {
return this.uniforms.shadingToonyFactor.value;
}
set shadingToonyFactor(value) {
this.uniforms.shadingToonyFactor.value = value;
}
get giEqualizationFactor() {
return this.uniforms.giEqualizationFactor.value;
}
set giEqualizationFactor(value) {
this.uniforms.giEqualizationFactor.value = value;
}
get matcapFactor() {
return this.uniforms.matcapFactor.value;
}
set matcapFactor(value) {
this.uniforms.matcapFactor.value = value;
}
get matcapTexture() {
return this.uniforms.matcapTexture.value;
}
set matcapTexture(value) {
this.uniforms.matcapTexture.value = value;
}
get parametricRimColorFactor() {
return this.uniforms.parametricRimColorFactor.value;
}
set parametricRimColorFactor(value) {
this.uniforms.parametricRimColorFactor.value = value;
}
get rimMultiplyTexture() {
return this.uniforms.rimMultiplyTexture.value;
}
set rimMultiplyTexture(value) {
this.uniforms.rimMultiplyTexture.value = value;
}
get rimLightingMixFactor() {
return this.uniforms.rimLightingMixFactor.value;
}
set rimLightingMixFactor(value) {
this.uniforms.rimLightingMixFactor.value = value;
}
get parametricRimFresnelPowerFactor() {
return this.uniforms.parametricRimFresnelPowerFactor.value;
}
set parametricRimFresnelPowerFactor(value) {
this.uniforms.parametricRimFresnelPowerFactor.value = value;
}
get parametricRimLiftFactor() {
return this.uniforms.parametricRimLiftFactor.value;
}
set parametricRimLiftFactor(value) {
this.uniforms.parametricRimLiftFactor.value = value;
}
get outlineWidthMultiplyTexture() {
return this.uniforms.outlineWidthMultiplyTexture.value;
}
set outlineWidthMultiplyTexture(value) {
this.uniforms.outlineWidthMultiplyTexture.value = value;
}
get outlineWidthFactor() {
return this.uniforms.outlineWidthFactor.value;
}
set outlineWidthFactor(value) {
this.uniforms.outlineWidthFactor.value = value;
}
get outlineColorFactor() {
return this.uniforms.outlineColorFactor.value;
}
set outlineColorFactor(value) {
this.uniforms.outlineColorFactor.value = value;
}
get outlineLightingMixFactor() {
return this.uniforms.outlineLightingMixFactor.value;
}
set outlineLightingMixFactor(value) {
this.uniforms.outlineLightingMixFactor.value = value;
}
get uvAnimationMaskTexture() {
return this.uniforms.uvAnimationMaskTexture.value;
}
set uvAnimationMaskTexture(value) {
this.uniforms.uvAnimationMaskTexture.value = value;
}
get uvAnimationScrollXOffset() {
return this.uniforms.uvAnimationScrollXOffset.value;
}
set uvAnimationScrollXOffset(value) {
this.uniforms.uvAnimationScrollXOffset.value = value;
}
get uvAnimationScrollYOffset() {
return this.uniforms.uvAnimationScrollYOffset.value;
}
set uvAnimationScrollYOffset(value) {
this.uniforms.uvAnimationScrollYOffset.value = value;
}
get uvAnimationRotationPhase() {
return this.uniforms.uvAnimationRotationPhase.value;
}
set uvAnimationRotationPhase(value) {
this.uniforms.uvAnimationRotationPhase.value = value;
}
/**
* When this is `true`, vertex colors will be ignored.
* `true` by default.
*/
get ignoreVertexColor() {
return this._ignoreVertexColor;
}
set ignoreVertexColor(value) {
this._ignoreVertexColor = value;
this.needsUpdate = true;
}
/**
* There is a line of the shader called "comment out if you want to PBR absolutely" in VRM0.0 MToon.
* When this is true, the material enables the line to make it compatible with the legacy rendering of VRM.
* Usually not recommended to turn this on.
* `false` by default.
*/
get v0CompatShade() {
return this._v0CompatShade;
}
/**
* There is a line of the shader called "comment out if you want to PBR absolutely" in VRM0.0 MToon.
* When this is true, the material enables the line to make it compatible with the legacy rendering of VRM.
* Usually not recommended to turn this on.
* `false` by default.
*/
set v0CompatShade(v) {
this._v0CompatShade = v;
this.needsUpdate = true;
}
/**
* Debug mode for the material.
* You can visualize several components for diagnosis using debug mode.
*
* See: {@link MToonMaterialDebugMode}
*/
get debugMode() {
return this._debugMode;
}
/**
* Debug mode for the material.
* You can visualize several components for diagnosis using debug mode.
*
* See: {@link MToonMaterialDebugMode}
*/
set debugMode(m) {
this._debugMode = m;
this.needsUpdate = true;
}
get outlineWidthMode() {
return this._outlineWidthMode;
}
set outlineWidthMode(m) {
this._outlineWidthMode = m;
this.needsUpdate = true;
}
get isOutline() {
return this._isOutline;
}
set isOutline(b) {
this._isOutline = b;
this.needsUpdate = true;
}
/**
* Readonly boolean that indicates this is a {@link MToonMaterial}.
*/
get isMToonMaterial() {
return true;
}
/**
* Update this material.
*
* @param delta deltaTime since last update
*/
update(delta) {
this._uploadUniformsWorkaround();
this._updateUVAnimation(delta);
}
copy(source) {
super.copy(source);
this.map = source.map;
this.normalMap = source.normalMap;
this.emissiveMap = source.emissiveMap;
this.shadeMultiplyTexture = source.shadeMultiplyTexture;
this.shadingShiftTexture = source.shadingShiftTexture;
this.matcapTexture = source.matcapTexture;
this.rimMultiplyTexture = source.rimMultiplyTexture;
this.outlineWidthMultiplyTexture = source.outlineWidthMultiplyTexture;
this.uvAnimationMaskTexture = source.uvAnimationMaskTexture;
this.normalMapType = source.normalMapType;
this.uvAnimationScrollXSpeedFactor = source.uvAnimationScrollXSpeedFactor;
this.uvAnimationScrollYSpeedFactor = source.uvAnimationScrollYSpeedFactor;
this.uvAnimationRotationSpeedFactor = source.uvAnimationRotationSpeedFactor;
this.ignoreVertexColor = source.ignoreVertexColor;
this.v0CompatShade = source.v0CompatShade;
this.debugMode = source.debugMode;
this.outlineWidthMode = source.outlineWidthMode;
this.isOutline = source.isOutline;
this.needsUpdate = true;
return this;
}
/**
* Update UV animation state.
* Intended to be called via {@link update}.
* @param delta deltaTime
*/
_updateUVAnimation(delta) {
this.uniforms.uvAnimationScrollXOffset.value += delta * this.uvAnimationScrollXSpeedFactor;
this.uniforms.uvAnimationScrollYOffset.value += delta * this.uvAnimationScrollYSpeedFactor;
this.uniforms.uvAnimationRotationPhase.value += delta * this.uvAnimationRotationSpeedFactor;
this.uniforms.alphaTest.value = this.alphaTest;
this.uniformsNeedUpdate = true;
}
/**
* Upload uniforms that need to upload but doesn't automatically because of reasons.
* Intended to be called via {@link constructor} and {@link update}.
*/
_uploadUniformsWorkaround() {
this.uniforms.opacity.value = this.opacity;
this._updateTextureMatrix(this.uniforms.map, this.uniforms.mapUvTransform);
this._updateTextureMatrix(this.uniforms.normalMap, this.uniforms.normalMapUvTransform);
this._updateTextureMatrix(this.uniforms.emissiveMap, this.uniforms.emissiveMapUvTransform);
this._updateTextureMatrix(this.uniforms.shadeMultiplyTexture, this.uniforms.shadeMultiplyTextureUvTransform);
this._updateTextureMatrix(this.uniforms.shadingShiftTexture, this.uniforms.shadingShiftTextureUvTransform);
this._updateTextureMatrix(this.uniforms.matcapTexture, this.uniforms.matcapTextureUvTransform);
this._updateTextureMatrix(this.uniforms.rimMultiplyTexture, this.uniforms.rimMultiplyTextureUvTransform);
this._updateTextureMatrix(this.uniforms.outlineWidthMultiplyTexture, this.uniforms.outlineWidthMultiplyTextureUvTransform);
this._updateTextureMatrix(this.uniforms.uvAnimationMaskTexture, this.uniforms.uvAnimationMaskTextureUvTransform);
this.uniformsNeedUpdate = true;
}
/**
* Returns a map object of preprocessor token and macro of the shader program.
*/
_generateDefines() {
const threeRevision = parseInt("179", 10);
const useUvInVert = this.outlineWidthMultiplyTexture !== null;
const useUvInFrag = this.map !== null || this.normalMap !== null || this.emissiveMap !== null || this.shadeMultiplyTexture !== null || this.shadingShiftTexture !== null || this.rimMultiplyTexture !== null || this.uvAnimationMaskTexture !== null;
return {
THREE_VRM_THREE_REVISION: threeRevision,
OUTLINE: this._isOutline,
MTOON_USE_UV: useUvInVert || useUvInFrag,
MTOON_UVS_VERTEX_ONLY: useUvInVert && !useUvInFrag,
V0_COMPAT_SHADE: this._v0CompatShade,
USE_SHADEMULTIPLYTEXTURE: this.shadeMultiplyTexture !== null,
USE_SHADINGSHIFTTEXTURE: this.shadingShiftTexture !== null,
USE_MATCAPTEXTURE: this.matcapTexture !== null,
USE_RIMMULTIPLYTEXTURE: this.rimMultiplyTexture !== null,
USE_OUTLINEWIDTHMULTIPLYTEXTURE: this._isOutline && this.outlineWidthMultiplyTexture !== null,
USE_UVANIMATIONMASKTEXTURE: this.uvAnimationMaskTexture !== null,
IGNORE_VERTEX_COLOR: this._ignoreVertexColor === true,
DEBUG_NORMAL: this._debugMode === "normal",
DEBUG_LITSHADERATE: this._debugMode === "litShadeRate",
DEBUG_UV: this._debugMode === "uv",
OUTLINE_WIDTH_SCREEN: this._isOutline && this._outlineWidthMode === MToonMaterialOutlineWidthMode.ScreenCoordinates
};
}
_updateTextureMatrix(src, dst) {
if (src.value) {
if (src.value.matrixAutoUpdate) src.value.updateMatrix();
dst.value.copy(src.value.matrix);
}
}
};
var POSSIBLE_SPEC_VERSIONS6 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var _MToonMaterialLoaderPlugin = class _MToonMaterialLoaderPlugin2 {
get name() {
return _MToonMaterialLoaderPlugin2.EXTENSION_NAME;
}
constructor(parser, options = {}) {
var _a, _b, _c, _d;
this.parser = parser;
this.materialType = (_a = options.materialType) != null ? _a : MToonMaterial;
this.renderOrderOffset = (_b = options.renderOrderOffset) != null ? _b : 0;
this.v0CompatShade = (_c = options.v0CompatShade) != null ? _c : false;
this.debugMode = (_d = options.debugMode) != null ? _d : "none";
this._mToonMaterialSet = /* @__PURE__ */ new Set();
}
beforeRoot() {
return __async3(this, null, function* () {
this._removeUnlitExtensionIfMToonExists();
});
}
afterRoot(gltf) {
return __async3(this, null, function* () {
gltf.userData.vrmMToonMaterials = Array.from(this._mToonMaterialSet);
});
}
getMaterialType(materialIndex) {
if (this._getMToonExtension(materialIndex)) return this.materialType;
return null;
}
extendMaterialParams(materialIndex, materialParams) {
const extension = this._getMToonExtension(materialIndex);
if (extension) return this._extendMaterialParams(extension, materialParams);
return null;
}
loadMesh(meshIndex) {
return __async3(this, null, function* () {
var _a;
const parser = this.parser;
const meshDef = (_a = parser.json.meshes) == null ? void 0 : _a[meshIndex];
if (meshDef == null) throw new Error(`MToonMaterialLoaderPlugin: Attempt to use meshes[${meshIndex}] of glTF but the mesh doesn't exist`);
const primitivesDef = meshDef.primitives;
const meshOrGroup = yield parser.loadMesh(meshIndex);
if (primitivesDef.length === 1) {
const mesh = meshOrGroup;
const materialIndex = primitivesDef[0].material;
if (materialIndex != null) this._setupPrimitive(mesh, materialIndex);
} else {
const group = meshOrGroup;
for (let i = 0; i < primitivesDef.length; i++) {
const mesh = group.children[i];
const materialIndex = primitivesDef[i].material;
if (materialIndex != null) this._setupPrimitive(mesh, materialIndex);
}
}
return meshOrGroup;
});
}
/**
* Delete use of `KHR_materials_unlit` from its `materials` if the material is using MToon.
*
* Since GLTFLoader have so many hardcoded procedure related to `KHR_materials_unlit`
* we have to delete the extension before we start to parse the glTF.
*/
_removeUnlitExtensionIfMToonExists() {
this.parser.json.materials?.map((materialDef, iMaterial) => {
var _a;
if (this._getMToonExtension(iMaterial) && ((_a = materialDef.extensions) == null ? void 0 : _a["KHR_materials_unlit"])) delete materialDef.extensions["KHR_materials_unlit"];
});
}
_getMToonExtension(materialIndex) {
var _a, _b;
const materialDef = (_a = this.parser.json.materials) == null ? void 0 : _a[materialIndex];
if (materialDef == null) {
console.warn(`MToonMaterialLoaderPlugin: Attempt to use materials[${materialIndex}] of glTF but the material doesn't exist`);
return;
}
const extension = (_b = materialDef.extensions) == null ? void 0 : _b[_MToonMaterialLoaderPlugin2.EXTENSION_NAME];
if (extension == null) return;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS6.has(specVersion)) {
console.warn(`MToonMaterialLoaderPlugin: Unknown ${_MToonMaterialLoaderPlugin2.EXTENSION_NAME} specVersion "${specVersion}"`);
return;
}
return extension;
}
_extendMaterialParams(extension, materialParams) {
return __async3(this, null, function* () {
var _a;
delete materialParams.metalness;
delete materialParams.roughness;
const assignHelper = new GLTFMToonMaterialParamsAssignHelper(this.parser, materialParams);
assignHelper.assignPrimitive("transparentWithZWrite", extension.transparentWithZWrite);
assignHelper.assignColor("shadeColorFactor", extension.shadeColorFactor);
assignHelper.assignTexture("shadeMultiplyTexture", extension.shadeMultiplyTexture, true);
assignHelper.assignPrimitive("shadingShiftFactor", extension.shadingShiftFactor);
assignHelper.assignTexture("shadingShiftTexture", extension.shadingShiftTexture, true);
assignHelper.assignPrimitive("shadingShiftTextureScale", (_a = extension.shadingShiftTexture) == null ? void 0 : _a.scale);
assignHelper.assignPrimitive("shadingToonyFactor", extension.shadingToonyFactor);
assignHelper.assignPrimitive("giEqualizationFactor", extension.giEqualizationFactor);
assignHelper.assignColor("matcapFactor", extension.matcapFactor);
assignHelper.assignTexture("matcapTexture", extension.matcapTexture, true);
assignHelper.assignColor("parametricRimColorFactor", extension.parametricRimColorFactor);
assignHelper.assignTexture("rimMultiplyTexture", extension.rimMultiplyTexture, true);
assignHelper.assignPrimitive("rimLightingMixFactor", extension.rimLightingMixFactor);
assignHelper.assignPrimitive("parametricRimFresnelPowerFactor", extension.parametricRimFresnelPowerFactor);
assignHelper.assignPrimitive("parametricRimLiftFactor", extension.parametricRimLiftFactor);
assignHelper.assignPrimitive("outlineWidthMode", extension.outlineWidthMode);
assignHelper.assignPrimitive("outlineWidthFactor", extension.outlineWidthFactor);
assignHelper.assignTexture("outlineWidthMultiplyTexture", extension.outlineWidthMultiplyTexture, false);
assignHelper.assignColor("outlineColorFactor", extension.outlineColorFactor);
assignHelper.assignPrimitive("outlineLightingMixFactor", extension.outlineLightingMixFactor);
assignHelper.assignTexture("uvAnimationMaskTexture", extension.uvAnimationMaskTexture, false);
assignHelper.assignPrimitive("uvAnimationScrollXSpeedFactor", extension.uvAnimationScrollXSpeedFactor);
assignHelper.assignPrimitive("uvAnimationScrollYSpeedFactor", extension.uvAnimationScrollYSpeedFactor);
assignHelper.assignPrimitive("uvAnimationRotationSpeedFactor", extension.uvAnimationRotationSpeedFactor);
assignHelper.assignPrimitive("v0CompatShade", this.v0CompatShade);
assignHelper.assignPrimitive("debugMode", this.debugMode);
yield assignHelper.pending;
});
}
/**
* This will do two processes that is required to render MToon properly.
*
* - Set render order
* - Generate outline
*
* @param mesh A target GLTF primitive
* @param materialIndex The material index of the primitive
*/
_setupPrimitive(mesh, materialIndex) {
const extension = this._getMToonExtension(materialIndex);
if (extension) {
mesh.renderOrder = this._parseRenderOrder(extension) + this.renderOrderOffset;
this._generateOutline(mesh);
this._addToMaterialSet(mesh);
return;
}
}
/**
* Check whether the material should generate outline or not.
* @param surfaceMaterial The material to check
* @returns True if the material should generate outline
*/
_shouldGenerateOutline(surfaceMaterial) {
return typeof surfaceMaterial.outlineWidthMode === "string" && surfaceMaterial.outlineWidthMode !== "none" && typeof surfaceMaterial.outlineWidthFactor === "number" && surfaceMaterial.outlineWidthFactor > 0;
}
/**
* Generate outline for the given mesh, if it needs.
*
* @param mesh The target mesh
*/
_generateOutline(mesh) {
const surfaceMaterial = mesh.material;
if (!(surfaceMaterial instanceof Material)) return;
if (!this._shouldGenerateOutline(surfaceMaterial)) return;
mesh.material = [surfaceMaterial];
const outlineMaterial = surfaceMaterial.clone();
outlineMaterial.name += " (Outline)";
outlineMaterial.isOutline = true;
outlineMaterial.side = 1;
mesh.material.push(outlineMaterial);
const geometry = mesh.geometry;
const primitiveVertices = geometry.index ? geometry.index.count : geometry.attributes.position.count / 3;
geometry.addGroup(0, primitiveVertices, 0);
geometry.addGroup(0, primitiveVertices, 1);
}
_addToMaterialSet(mesh) {
const materialOrMaterials = mesh.material;
const materialSet = /* @__PURE__ */ new Set();
if (Array.isArray(materialOrMaterials)) materialOrMaterials.forEach((material) => materialSet.add(material));
else materialSet.add(materialOrMaterials);
for (const material of materialSet) this._mToonMaterialSet.add(material);
}
_parseRenderOrder(extension) {
var _a;
return (extension.transparentWithZWrite ? 0 : 19) + ((_a = extension.renderQueueOffsetNumber) != null ? _a : 0);
}
};
_MToonMaterialLoaderPlugin.EXTENSION_NAME = "VRMC_materials_mtoon";
var MToonMaterialLoaderPlugin = _MToonMaterialLoaderPlugin;
var __async4 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var _VRMMaterialsHDREmissiveMultiplierLoaderPlugin = class _VRMMaterialsHDREmissiveMultiplierLoaderPlugin2 {
get name() {
return _VRMMaterialsHDREmissiveMultiplierLoaderPlugin2.EXTENSION_NAME;
}
constructor(parser) {
this.parser = parser;
}
extendMaterialParams(materialIndex, materialParams) {
return __async4(this, null, function* () {
const extension = this._getHDREmissiveMultiplierExtension(materialIndex);
if (extension == null) return;
console.warn("VRMMaterialsHDREmissiveMultiplierLoaderPlugin: `VRMC_materials_hdr_emissiveMultiplier` is archived. Use `KHR_materials_emissive_strength` instead.");
materialParams.emissiveIntensity = extension.emissiveMultiplier;
});
}
_getHDREmissiveMultiplierExtension(materialIndex) {
var _a, _b;
const materialDef = (_a = this.parser.json.materials) == null ? void 0 : _a[materialIndex];
if (materialDef == null) {
console.warn(`VRMMaterialsHDREmissiveMultiplierLoaderPlugin: Attempt to use materials[${materialIndex}] of glTF but the material doesn't exist`);
return;
}
const extension = (_b = materialDef.extensions) == null ? void 0 : _b[_VRMMaterialsHDREmissiveMultiplierLoaderPlugin2.EXTENSION_NAME];
if (extension == null) return;
return extension;
}
};
_VRMMaterialsHDREmissiveMultiplierLoaderPlugin.EXTENSION_NAME = "VRMC_materials_hdr_emissiveMultiplier";
var VRMMaterialsHDREmissiveMultiplierLoaderPlugin = _VRMMaterialsHDREmissiveMultiplierLoaderPlugin;
var __defProp2 = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols2 = Object.getOwnPropertySymbols;
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
var __propIsEnum2 = Object.prototype.propertyIsEnumerable;
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, {
enumerable: true,
configurable: true,
writable: true,
value
}) : obj[key] = value;
var __spreadValues2 = (a, b) => {
for (var prop in b || (b = {})) if (__hasOwnProp2.call(b, prop)) __defNormalProp2(a, prop, b[prop]);
if (__getOwnPropSymbols2) {
for (var prop of __getOwnPropSymbols2(b)) if (__propIsEnum2.call(b, prop)) __defNormalProp2(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __async5 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
function gammaEOTF(e) {
return Math.pow(e, 2.2);
}
var VRMMaterialsV0CompatPlugin = class {
get name() {
return "VRMMaterialsV0CompatPlugin";
}
constructor(parser) {
var _a;
this.parser = parser;
this._renderQueueMapTransparent = /* @__PURE__ */ new Map();
this._renderQueueMapTransparentZWrite = /* @__PURE__ */ new Map();
const json = this.parser.json;
json.extensionsUsed = (_a = json.extensionsUsed) != null ? _a : [];
if (json.extensionsUsed.indexOf("KHR_texture_transform") === -1) json.extensionsUsed.push("KHR_texture_transform");
}
beforeRoot() {
return __async5(this, null, function* () {
var _a;
const json = this.parser.json;
const v0VRMExtension = (_a = json.extensions) == null ? void 0 : _a["VRM"];
const v0MaterialProperties = v0VRMExtension == null ? void 0 : v0VRMExtension.materialProperties;
if (!v0MaterialProperties) return;
this._populateRenderQueueMap(v0MaterialProperties);
v0MaterialProperties.forEach((materialProperties, materialIndex) => {
var _a2, _b;
const materialDef = (_a2 = json.materials) == null ? void 0 : _a2[materialIndex];
if (materialDef == null) {
console.warn(`VRMMaterialsV0CompatPlugin: Attempt to use materials[${materialIndex}] of glTF but the material doesn't exist`);
return;
}
if (materialProperties.shader === "VRM/MToon") {
const material = this._parseV0MToonProperties(materialProperties, materialDef);
json.materials[materialIndex] = material;
} else if ((_b = materialProperties.shader) == null ? void 0 : _b.startsWith("VRM/Unlit")) {
const material = this._parseV0UnlitProperties(materialProperties, materialDef);
json.materials[materialIndex] = material;
} else if (materialProperties.shader === "VRM_USE_GLTFSHADER") {} else console.warn(`VRMMaterialsV0CompatPlugin: Unknown shader: ${materialProperties.shader}`);
});
});
}
_parseV0MToonProperties(materialProperties, schemaMaterial) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa;
const isTransparent = (_b = (_a = materialProperties.keywordMap) == null ? void 0 : _a["_ALPHABLEND_ON"]) != null ? _b : false;
const transparentWithZWrite = ((_c = materialProperties.floatProperties) == null ? void 0 : _c["_ZWrite"]) === 1 && isTransparent;
const renderQueueOffsetNumber = this._v0ParseRenderQueue(materialProperties);
const isCutoff = (_e = (_d = materialProperties.keywordMap) == null ? void 0 : _d["_ALPHATEST_ON"]) != null ? _e : false;
const alphaMode = isTransparent ? "BLEND" : isCutoff ? "MASK" : "OPAQUE";
const alphaCutoff = isCutoff ? (_g = (_f = materialProperties.floatProperties) == null ? void 0 : _f["_Cutoff"]) != null ? _g : .5 : void 0;
const doubleSided = ((_i = (_h = materialProperties.floatProperties) == null ? void 0 : _h["_CullMode"]) != null ? _i : 2) === 0;
const textureTransformExt = this._portTextureTransform(materialProperties);
const baseColorFactor = ((_k = (_j = materialProperties.vectorProperties) == null ? void 0 : _j["_Color"]) != null ? _k : [
1,
1,
1,
1
]).map((v, i) => i === 3 ? v : gammaEOTF(v));
const baseColorTextureIndex = (_l = materialProperties.textureProperties) == null ? void 0 : _l["_MainTex"];
const baseColorTexture = baseColorTextureIndex != null ? {
index: baseColorTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const normalTextureScale = (_n = (_m = materialProperties.floatProperties) == null ? void 0 : _m["_BumpScale"]) != null ? _n : 1;
const normalTextureIndex = (_o = materialProperties.textureProperties) == null ? void 0 : _o["_BumpMap"];
const normalTexture = normalTextureIndex != null ? {
index: normalTextureIndex,
scale: normalTextureScale,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const emissiveFactor = ((_q = (_p = materialProperties.vectorProperties) == null ? void 0 : _p["_EmissionColor"]) != null ? _q : [
0,
0,
0,
1
]).map(gammaEOTF);
const emissiveTextureIndex = (_r = materialProperties.textureProperties) == null ? void 0 : _r["_EmissionMap"];
const emissiveTexture = emissiveTextureIndex != null ? {
index: emissiveTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const shadeColorFactor = ((_t = (_s = materialProperties.vectorProperties) == null ? void 0 : _s["_ShadeColor"]) != null ? _t : [
.97,
.81,
.86,
1
]).map(gammaEOTF);
const shadeMultiplyTextureIndex = (_u = materialProperties.textureProperties) == null ? void 0 : _u["_ShadeTexture"];
const shadeMultiplyTexture = shadeMultiplyTextureIndex != null ? {
index: shadeMultiplyTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
let shadingShiftFactor = (_w = (_v = materialProperties.floatProperties) == null ? void 0 : _v["_ShadeShift"]) != null ? _w : 0;
let shadingToonyFactor = (_y = (_x = materialProperties.floatProperties) == null ? void 0 : _x["_ShadeToony"]) != null ? _y : .9;
shadingToonyFactor = MathUtils.lerp(shadingToonyFactor, 1, .5 + .5 * shadingShiftFactor);
shadingShiftFactor = -shadingShiftFactor - (1 - shadingToonyFactor);
const giIntensityFactor = (_A = (_z = materialProperties.floatProperties) == null ? void 0 : _z["_IndirectLightIntensity"]) != null ? _A : .1;
const giEqualizationFactor = giIntensityFactor ? 1 - giIntensityFactor : void 0;
const matcapTextureIndex = (_B = materialProperties.textureProperties) == null ? void 0 : _B["_SphereAdd"];
const matcapFactor = matcapTextureIndex != null ? [
1,
1,
1
] : void 0;
const matcapTexture = matcapTextureIndex != null ? { index: matcapTextureIndex } : void 0;
const rimLightingMixFactor = (_D = (_C = materialProperties.floatProperties) == null ? void 0 : _C["_RimLightingMix"]) != null ? _D : 0;
const rimMultiplyTextureIndex = (_E = materialProperties.textureProperties) == null ? void 0 : _E["_RimTexture"];
const rimMultiplyTexture = rimMultiplyTextureIndex != null ? {
index: rimMultiplyTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const parametricRimColorFactor = ((_G = (_F = materialProperties.vectorProperties) == null ? void 0 : _F["_RimColor"]) != null ? _G : [
0,
0,
0,
1
]).map(gammaEOTF);
const parametricRimFresnelPowerFactor = (_I = (_H = materialProperties.floatProperties) == null ? void 0 : _H["_RimFresnelPower"]) != null ? _I : 1;
const parametricRimLiftFactor = (_K = (_J = materialProperties.floatProperties) == null ? void 0 : _J["_RimLift"]) != null ? _K : 0;
const outlineWidthMode = [
"none",
"worldCoordinates",
"screenCoordinates"
][(_M = (_L = materialProperties.floatProperties) == null ? void 0 : _L["_OutlineWidthMode"]) != null ? _M : 0];
let outlineWidthFactor = (_O = (_N = materialProperties.floatProperties) == null ? void 0 : _N["_OutlineWidth"]) != null ? _O : 0;
outlineWidthFactor = .01 * outlineWidthFactor;
const outlineWidthMultiplyTextureIndex = (_P = materialProperties.textureProperties) == null ? void 0 : _P["_OutlineWidthTexture"];
const outlineWidthMultiplyTexture = outlineWidthMultiplyTextureIndex != null ? {
index: outlineWidthMultiplyTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const outlineColorFactor = ((_R = (_Q = materialProperties.vectorProperties) == null ? void 0 : _Q["_OutlineColor"]) != null ? _R : [
0,
0,
0
]).map(gammaEOTF);
const outlineLightingMixFactor = ((_T = (_S = materialProperties.floatProperties) == null ? void 0 : _S["_OutlineColorMode"]) != null ? _T : 0) === 1 ? (_V = (_U = materialProperties.floatProperties) == null ? void 0 : _U["_OutlineLightingMix"]) != null ? _V : 1 : 0;
const uvAnimationMaskTextureIndex = (_W = materialProperties.textureProperties) == null ? void 0 : _W["_UvAnimMaskTexture"];
const uvAnimationMaskTexture = uvAnimationMaskTextureIndex != null ? {
index: uvAnimationMaskTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const uvAnimationScrollXSpeedFactor = (_Y = (_X = materialProperties.floatProperties) == null ? void 0 : _X["_UvAnimScrollX"]) != null ? _Y : 0;
let uvAnimationScrollYSpeedFactor = (__ = (_Z = materialProperties.floatProperties) == null ? void 0 : _Z["_UvAnimScrollY"]) != null ? __ : 0;
if (uvAnimationScrollYSpeedFactor != null) uvAnimationScrollYSpeedFactor = -uvAnimationScrollYSpeedFactor;
const uvAnimationRotationSpeedFactor = (_aa = (_$ = materialProperties.floatProperties) == null ? void 0 : _$["_UvAnimRotation"]) != null ? _aa : 0;
const mtoonExtension = {
specVersion: "1.0",
transparentWithZWrite,
renderQueueOffsetNumber,
shadeColorFactor,
shadeMultiplyTexture,
shadingShiftFactor,
shadingToonyFactor,
giEqualizationFactor,
matcapFactor,
matcapTexture,
rimLightingMixFactor,
rimMultiplyTexture,
parametricRimColorFactor,
parametricRimFresnelPowerFactor,
parametricRimLiftFactor,
outlineWidthMode,
outlineWidthFactor,
outlineWidthMultiplyTexture,
outlineColorFactor,
outlineLightingMixFactor,
uvAnimationMaskTexture,
uvAnimationScrollXSpeedFactor,
uvAnimationScrollYSpeedFactor,
uvAnimationRotationSpeedFactor
};
return __spreadProps(__spreadValues2({}, schemaMaterial), {
pbrMetallicRoughness: {
baseColorFactor,
baseColorTexture
},
normalTexture,
emissiveTexture,
emissiveFactor,
alphaMode,
alphaCutoff,
doubleSided,
extensions: { VRMC_materials_mtoon: mtoonExtension }
});
}
_parseV0UnlitProperties(materialProperties, schemaMaterial) {
var _a, _b, _c, _d, _e;
const isTransparentZWrite = materialProperties.shader === "VRM/UnlitTransparentZWrite";
const isTransparent = materialProperties.shader === "VRM/UnlitTransparent" || isTransparentZWrite;
const renderQueueOffsetNumber = this._v0ParseRenderQueue(materialProperties);
const isCutoff = materialProperties.shader === "VRM/UnlitCutout";
const alphaMode = isTransparent ? "BLEND" : isCutoff ? "MASK" : "OPAQUE";
const alphaCutoff = isCutoff ? (_b = (_a = materialProperties.floatProperties) == null ? void 0 : _a["_Cutoff"]) != null ? _b : .5 : void 0;
const textureTransformExt = this._portTextureTransform(materialProperties);
const baseColorFactor = ((_d = (_c = materialProperties.vectorProperties) == null ? void 0 : _c["_Color"]) != null ? _d : [
1,
1,
1,
1
]).map(gammaEOTF);
const baseColorTextureIndex = (_e = materialProperties.textureProperties) == null ? void 0 : _e["_MainTex"];
const baseColorTexture = baseColorTextureIndex != null ? {
index: baseColorTextureIndex,
extensions: __spreadValues2({}, textureTransformExt)
} : void 0;
const mtoonExtension = {
specVersion: "1.0",
transparentWithZWrite: isTransparentZWrite,
renderQueueOffsetNumber,
shadeColorFactor: baseColorFactor,
shadeMultiplyTexture: baseColorTexture
};
return __spreadProps(__spreadValues2({}, schemaMaterial), {
pbrMetallicRoughness: {
baseColorFactor,
baseColorTexture
},
alphaMode,
alphaCutoff,
extensions: { VRMC_materials_mtoon: mtoonExtension }
});
}
/**
* Create a glTF `KHR_texture_transform` extension from v0 texture transform info.
*/
_portTextureTransform(materialProperties) {
var _a, _b, _c, _d, _e;
const textureTransform = (_a = materialProperties.vectorProperties) == null ? void 0 : _a["_MainTex"];
if (textureTransform == null) return {};
const offset = [(_b = textureTransform == null ? void 0 : textureTransform[0]) != null ? _b : 0, (_c = textureTransform == null ? void 0 : textureTransform[1]) != null ? _c : 0];
const scale = [(_d = textureTransform == null ? void 0 : textureTransform[2]) != null ? _d : 1, (_e = textureTransform == null ? void 0 : textureTransform[3]) != null ? _e : 1];
offset[1] = 1 - scale[1] - offset[1];
return { KHR_texture_transform: {
offset,
scale
} };
}
/**
* Convert v0 render order into v1 render order.
* This uses a map from v0 render queue to v1 compliant render queue offset which is generated in {@link _populateRenderQueueMap}.
*/
_v0ParseRenderQueue(materialProperties) {
var _a, _b;
const isTransparentZWrite = materialProperties.shader === "VRM/UnlitTransparentZWrite";
const isTransparent = ((_a = materialProperties.keywordMap) == null ? void 0 : _a["_ALPHABLEND_ON"]) != void 0 || materialProperties.shader === "VRM/UnlitTransparent" || isTransparentZWrite;
const enabledZWrite = ((_b = materialProperties.floatProperties) == null ? void 0 : _b["_ZWrite"]) === 1 || isTransparentZWrite;
let offset = 0;
if (isTransparent) {
const v0Queue = materialProperties.renderQueue;
if (v0Queue != null) if (enabledZWrite) offset = this._renderQueueMapTransparentZWrite.get(v0Queue);
else offset = this._renderQueueMapTransparent.get(v0Queue);
}
return offset;
}
/**
* Create a map which maps v0 render queue to v1 compliant render queue offset.
* This lists up all render queues the model use and creates a map to new render queue offsets in the same order.
*/
_populateRenderQueueMap(materialPropertiesList) {
const renderQueuesTransparent = /* @__PURE__ */ new Set();
const renderQueuesTransparentZWrite = /* @__PURE__ */ new Set();
materialPropertiesList.forEach((materialProperties) => {
var _a, _b;
const isTransparentZWrite = materialProperties.shader === "VRM/UnlitTransparentZWrite";
const isTransparent = ((_a = materialProperties.keywordMap) == null ? void 0 : _a["_ALPHABLEND_ON"]) != void 0 || materialProperties.shader === "VRM/UnlitTransparent" || isTransparentZWrite;
const enabledZWrite = ((_b = materialProperties.floatProperties) == null ? void 0 : _b["_ZWrite"]) === 1 || isTransparentZWrite;
if (isTransparent) {
const v0Queue = materialProperties.renderQueue;
if (v0Queue != null) if (enabledZWrite) renderQueuesTransparentZWrite.add(v0Queue);
else renderQueuesTransparent.add(v0Queue);
}
});
if (renderQueuesTransparent.size > 10) console.warn(`VRMMaterialsV0CompatPlugin: This VRM uses ${renderQueuesTransparent.size} render queues for Transparent materials while VRM 1.0 only supports up to 10 render queues. The model might not be rendered correctly.`);
if (renderQueuesTransparentZWrite.size > 10) console.warn(`VRMMaterialsV0CompatPlugin: This VRM uses ${renderQueuesTransparentZWrite.size} render queues for TransparentZWrite materials while VRM 1.0 only supports up to 10 render queues. The model might not be rendered correctly.`);
Array.from(renderQueuesTransparent).sort().forEach((queue, i) => {
const newQueueOffset = Math.min(Math.max(i - renderQueuesTransparent.size + 1, -9), 0);
this._renderQueueMapTransparent.set(queue, newQueueOffset);
});
Array.from(renderQueuesTransparentZWrite).sort().forEach((queue, i) => {
const newQueueOffset = Math.min(Math.max(i, 0), 9);
this._renderQueueMapTransparentZWrite.set(queue, newQueueOffset);
});
}
};
var __async6 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var _v3A6 = new Vector3();
var VRMNodeConstraintHelper = class extends Group {
constructor(constraint) {
super();
this._attrPosition = new BufferAttribute(new Float32Array([
0,
0,
0,
0,
0,
0
]), 3);
this._attrPosition.setUsage(DynamicDrawUsage);
const geometry = new BufferGeometry();
geometry.setAttribute("position", this._attrPosition);
const material = new LineBasicMaterial({
color: 16711935,
depthTest: false,
depthWrite: false
});
this._line = new Line(geometry, material);
this.add(this._line);
this.constraint = constraint;
}
updateMatrixWorld(force) {
_v3A6.setFromMatrixPosition(this.constraint.destination.matrixWorld);
this._attrPosition.setXYZ(0, _v3A6.x, _v3A6.y, _v3A6.z);
if (this.constraint.source) _v3A6.setFromMatrixPosition(this.constraint.source.matrixWorld);
this._attrPosition.setXYZ(1, _v3A6.x, _v3A6.y, _v3A6.z);
this._attrPosition.needsUpdate = true;
super.updateMatrixWorld(force);
}
};
function decomposePosition(matrix, target) {
return target.set(matrix.elements[12], matrix.elements[13], matrix.elements[14]);
}
var _v3A22 = new Vector3();
var _v3B4 = new Vector3();
function decomposeRotation(matrix, target) {
matrix.decompose(_v3A22, target, _v3B4);
return target;
}
function quatInvertCompat2(target) {
if (target.invert) target.invert();
else target.inverse();
return target;
}
var VRMNodeConstraint = class {
/**
* @param destination The destination object
* @param source The source object
*/
constructor(destination, source) {
this.destination = destination;
this.source = source;
this.weight = 1;
}
};
var _v3A32 = new Vector3();
var _v3B22 = new Vector3();
var _v3C2 = new Vector3();
var _quatA7 = new Quaternion();
var _quatB4 = new Quaternion();
var _quatC2 = new Quaternion();
var VRMAimConstraint = class extends VRMNodeConstraint {
/**
* The aim axis of the constraint.
*/
get aimAxis() {
return this._aimAxis;
}
/**
* The aim axis of the constraint.
*/
set aimAxis(aimAxis) {
this._aimAxis = aimAxis;
this._v3AimAxis.set(aimAxis === "PositiveX" ? 1 : aimAxis === "NegativeX" ? -1 : 0, aimAxis === "PositiveY" ? 1 : aimAxis === "NegativeY" ? -1 : 0, aimAxis === "PositiveZ" ? 1 : aimAxis === "NegativeZ" ? -1 : 0);
}
get dependencies() {
const set = /* @__PURE__ */ new Set([this.source]);
if (this.destination.parent) set.add(this.destination.parent);
return set;
}
constructor(destination, source) {
super(destination, source);
this._aimAxis = "PositiveX";
this._v3AimAxis = new Vector3(1, 0, 0);
this._dstRestQuat = new Quaternion();
}
setInitState() {
this._dstRestQuat.copy(this.destination.quaternion);
}
update() {
this.destination.updateWorldMatrix(true, false);
this.source.updateWorldMatrix(true, false);
const dstParentWorldQuat = _quatA7.identity();
const invDstParentWorldQuat = _quatB4.identity();
if (this.destination.parent) {
decomposeRotation(this.destination.parent.matrixWorld, dstParentWorldQuat);
quatInvertCompat2(invDstParentWorldQuat.copy(dstParentWorldQuat));
}
const a0 = _v3A32.copy(this._v3AimAxis).applyQuaternion(this._dstRestQuat).applyQuaternion(dstParentWorldQuat);
const a1 = decomposePosition(this.source.matrixWorld, _v3B22).sub(decomposePosition(this.destination.matrixWorld, _v3C2)).normalize();
const targetQuat = _quatC2.setFromUnitVectors(a0, a1).premultiply(invDstParentWorldQuat).multiply(dstParentWorldQuat).multiply(this._dstRestQuat);
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
}
};
function traverseAncestorsFromRoot(object, callback) {
const ancestors = [object];
let head = object.parent;
while (head !== null) {
ancestors.unshift(head);
head = head.parent;
}
ancestors.forEach((ancestor) => {
callback(ancestor);
});
}
var VRMNodeConstraintManager = class {
constructor() {
this._constraints = /* @__PURE__ */ new Set();
this._objectConstraintsMap = /* @__PURE__ */ new Map();
}
get constraints() {
return this._constraints;
}
addConstraint(constraint) {
this._constraints.add(constraint);
let objectSet = this._objectConstraintsMap.get(constraint.destination);
if (objectSet == null) {
objectSet = /* @__PURE__ */ new Set();
this._objectConstraintsMap.set(constraint.destination, objectSet);
}
objectSet.add(constraint);
}
deleteConstraint(constraint) {
this._constraints.delete(constraint);
this._objectConstraintsMap.get(constraint.destination).delete(constraint);
}
setInitState() {
const constraintsTried = /* @__PURE__ */ new Set();
const constraintsDone = /* @__PURE__ */ new Set();
for (const constraint of this._constraints) this._processConstraint(constraint, constraintsTried, constraintsDone, (constraint2) => constraint2.setInitState());
}
update() {
const constraintsTried = /* @__PURE__ */ new Set();
const constraintsDone = /* @__PURE__ */ new Set();
for (const constraint of this._constraints) this._processConstraint(constraint, constraintsTried, constraintsDone, (constraint2) => constraint2.update());
}
/**
* Update a constraint.
* If there are other constraints that are dependant, it will try to update them recursively.
* It might throw an error if there are circular dependencies.
*
* Intended to be used in {@link update} and {@link _processConstraint} itself recursively.
*
* @param constraint A constraint you want to update
* @param constraintsTried Set of constraints that are already tried to be updated
* @param constraintsDone Set of constraints that are already up to date
*/
_processConstraint(constraint, constraintsTried, constraintsDone, callback) {
if (constraintsDone.has(constraint)) return;
if (constraintsTried.has(constraint)) throw new Error("VRMNodeConstraintManager: Circular dependency detected while updating constraints");
constraintsTried.add(constraint);
const depObjects = constraint.dependencies;
for (const depObject of depObjects) traverseAncestorsFromRoot(depObject, (depObjectAncestor) => {
const objectSet = this._objectConstraintsMap.get(depObjectAncestor);
if (objectSet) for (const depConstraint of objectSet) this._processConstraint(depConstraint, constraintsTried, constraintsDone, callback);
});
callback(constraint);
constraintsDone.add(constraint);
}
};
var _quatA22 = new Quaternion();
var _quatB22 = new Quaternion();
var VRMRotationConstraint = class extends VRMNodeConstraint {
get dependencies() {
return /* @__PURE__ */ new Set([this.source]);
}
constructor(destination, source) {
super(destination, source);
this._dstRestQuat = new Quaternion();
this._invSrcRestQuat = new Quaternion();
}
setInitState() {
this._dstRestQuat.copy(this.destination.quaternion);
quatInvertCompat2(this._invSrcRestQuat.copy(this.source.quaternion));
}
update() {
const srcDeltaQuat = _quatA22.copy(this._invSrcRestQuat).multiply(this.source.quaternion);
const targetQuat = _quatB22.copy(this._dstRestQuat).multiply(srcDeltaQuat);
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
}
};
var _v3A42 = new Vector3();
var _quatA32 = new Quaternion();
var _quatB32 = new Quaternion();
var VRMRollConstraint = class extends VRMNodeConstraint {
/**
* The roll axis of the constraint.
*/
get rollAxis() {
return this._rollAxis;
}
/**
* The roll axis of the constraint.
*/
set rollAxis(rollAxis) {
this._rollAxis = rollAxis;
this._v3RollAxis.set(rollAxis === "X" ? 1 : 0, rollAxis === "Y" ? 1 : 0, rollAxis === "Z" ? 1 : 0);
}
get dependencies() {
return /* @__PURE__ */ new Set([this.source]);
}
constructor(destination, source) {
super(destination, source);
this._rollAxis = "X";
this._v3RollAxis = new Vector3(1, 0, 0);
this._dstRestQuat = new Quaternion();
this._invDstRestQuat = new Quaternion();
this._invSrcRestQuatMulDstRestQuat = new Quaternion();
}
setInitState() {
this._dstRestQuat.copy(this.destination.quaternion);
quatInvertCompat2(this._invDstRestQuat.copy(this._dstRestQuat));
quatInvertCompat2(this._invSrcRestQuatMulDstRestQuat.copy(this.source.quaternion)).multiply(this._dstRestQuat);
}
update() {
const quatDelta = _quatA32.copy(this._invDstRestQuat).multiply(this.source.quaternion).multiply(this._invSrcRestQuatMulDstRestQuat);
const n1 = _v3A42.copy(this._v3RollAxis).applyQuaternion(quatDelta);
const targetQuat = _quatB32.setFromUnitVectors(n1, this._v3RollAxis).premultiply(this._dstRestQuat).multiply(quatDelta);
this.destination.quaternion.copy(this._dstRestQuat).slerp(targetQuat, this.weight);
}
};
var POSSIBLE_SPEC_VERSIONS7 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var _VRMNodeConstraintLoaderPlugin = class _VRMNodeConstraintLoaderPlugin2 {
get name() {
return _VRMNodeConstraintLoaderPlugin2.EXTENSION_NAME;
}
constructor(parser, options) {
this.parser = parser;
this.helperRoot = options == null ? void 0 : options.helperRoot;
}
afterRoot(gltf) {
return __async6(this, null, function* () {
gltf.userData.vrmNodeConstraintManager = yield this._import(gltf);
});
}
/**
* Import constraints from a GLTF and returns a {@link VRMNodeConstraintManager}.
* It might return `null` instead when it does not need to be created or something go wrong.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
*/
_import(gltf) {
return __async6(this, null, function* () {
var _a;
const json = this.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf(_VRMNodeConstraintLoaderPlugin2.EXTENSION_NAME)) !== -1)) return null;
const manager = new VRMNodeConstraintManager();
const threeNodes = yield this.parser.getDependencies("node");
threeNodes.forEach((node, nodeIndex) => {
var _a2;
const schemaNode = json.nodes[nodeIndex];
const extension = (_a2 = schemaNode == null ? void 0 : schemaNode.extensions) == null ? void 0 : _a2[_VRMNodeConstraintLoaderPlugin2.EXTENSION_NAME];
if (extension == null) return;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS7.has(specVersion)) {
console.warn(`VRMNodeConstraintLoaderPlugin: Unknown ${_VRMNodeConstraintLoaderPlugin2.EXTENSION_NAME} specVersion "${specVersion}"`);
return;
}
const constraintDef = extension.constraint;
if (constraintDef.roll != null) {
const constraint = this._importRollConstraint(node, threeNodes, constraintDef.roll);
manager.addConstraint(constraint);
} else if (constraintDef.aim != null) {
const constraint = this._importAimConstraint(node, threeNodes, constraintDef.aim);
manager.addConstraint(constraint);
} else if (constraintDef.rotation != null) {
const constraint = this._importRotationConstraint(node, threeNodes, constraintDef.rotation);
manager.addConstraint(constraint);
}
});
gltf.scene.updateMatrixWorld();
manager.setInitState();
return manager;
});
}
_importRollConstraint(destination, nodes, rollConstraintDef) {
const { source: sourceIndex, rollAxis, weight } = rollConstraintDef;
const source = nodes[sourceIndex];
const constraint = new VRMRollConstraint(destination, source);
if (rollAxis != null) constraint.rollAxis = rollAxis;
if (weight != null) constraint.weight = weight;
if (this.helperRoot) {
const helper = new VRMNodeConstraintHelper(constraint);
this.helperRoot.add(helper);
}
return constraint;
}
_importAimConstraint(destination, nodes, aimConstraintDef) {
const { source: sourceIndex, aimAxis, weight } = aimConstraintDef;
const source = nodes[sourceIndex];
const constraint = new VRMAimConstraint(destination, source);
if (aimAxis != null) constraint.aimAxis = aimAxis;
if (weight != null) constraint.weight = weight;
if (this.helperRoot) {
const helper = new VRMNodeConstraintHelper(constraint);
this.helperRoot.add(helper);
}
return constraint;
}
_importRotationConstraint(destination, nodes, rotationConstraintDef) {
const { source: sourceIndex, weight } = rotationConstraintDef;
const source = nodes[sourceIndex];
const constraint = new VRMRotationConstraint(destination, source);
if (weight != null) constraint.weight = weight;
if (this.helperRoot) {
const helper = new VRMNodeConstraintHelper(constraint);
this.helperRoot.add(helper);
}
return constraint;
}
};
_VRMNodeConstraintLoaderPlugin.EXTENSION_NAME = "VRMC_node_constraint";
var VRMNodeConstraintLoaderPlugin = _VRMNodeConstraintLoaderPlugin;
var __async7 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var VRMSpringBoneColliderShape = class {};
var _v3A7 = new Vector3();
var _v3B5 = new Vector3();
var VRMSpringBoneColliderShapeCapsule = class extends VRMSpringBoneColliderShape {
get type() {
return "capsule";
}
constructor(params) {
var _a, _b, _c, _d;
super();
this.offset = (_a = params == null ? void 0 : params.offset) != null ? _a : new Vector3(0, 0, 0);
this.tail = (_b = params == null ? void 0 : params.tail) != null ? _b : new Vector3(0, 0, 0);
this.radius = (_c = params == null ? void 0 : params.radius) != null ? _c : 0;
this.inside = (_d = params == null ? void 0 : params.inside) != null ? _d : false;
}
calculateCollision(colliderMatrix, objectPosition, objectRadius, target) {
_v3A7.setFromMatrixPosition(colliderMatrix);
_v3B5.subVectors(this.tail, this.offset).applyMatrix4(colliderMatrix);
_v3B5.sub(_v3A7);
const lengthSqCapsule = _v3B5.lengthSq();
target.copy(objectPosition).sub(_v3A7);
const dot = _v3B5.dot(target);
if (dot <= 0) {} else if (lengthSqCapsule <= dot) target.sub(_v3B5);
else {
_v3B5.multiplyScalar(dot / lengthSqCapsule);
target.sub(_v3B5);
}
const length = target.length();
const distance = this.inside ? this.radius - objectRadius - length : length - objectRadius - this.radius;
if (distance < 0) {
target.multiplyScalar(1 / length);
if (this.inside) target.negate();
}
return distance;
}
};
var _v3A23 = new Vector3();
var _mat3A = new Matrix3();
var VRMSpringBoneColliderShapePlane = class extends VRMSpringBoneColliderShape {
get type() {
return "plane";
}
constructor(params) {
var _a, _b;
super();
this.offset = (_a = params == null ? void 0 : params.offset) != null ? _a : new Vector3(0, 0, 0);
this.normal = (_b = params == null ? void 0 : params.normal) != null ? _b : new Vector3(0, 0, 1);
}
calculateCollision(colliderMatrix, objectPosition, objectRadius, target) {
target.setFromMatrixPosition(colliderMatrix);
target.negate().add(objectPosition);
_mat3A.getNormalMatrix(colliderMatrix);
_v3A23.copy(this.normal).applyNormalMatrix(_mat3A).normalize();
const distance = target.dot(_v3A23) - objectRadius;
target.copy(_v3A23);
return distance;
}
};
var _v3A33 = new Vector3();
var VRMSpringBoneColliderShapeSphere = class extends VRMSpringBoneColliderShape {
get type() {
return "sphere";
}
constructor(params) {
var _a, _b, _c;
super();
this.offset = (_a = params == null ? void 0 : params.offset) != null ? _a : new Vector3(0, 0, 0);
this.radius = (_b = params == null ? void 0 : params.radius) != null ? _b : 0;
this.inside = (_c = params == null ? void 0 : params.inside) != null ? _c : false;
}
calculateCollision(colliderMatrix, objectPosition, objectRadius, target) {
target.subVectors(objectPosition, _v3A33.setFromMatrixPosition(colliderMatrix));
const length = target.length();
const distance = this.inside ? this.radius - objectRadius - length : length - objectRadius - this.radius;
if (distance < 0) {
target.multiplyScalar(1 / length);
if (this.inside) target.negate();
}
return distance;
}
};
var _v3A43 = new Vector3();
var ColliderShapeCapsuleBufferGeometry = class extends BufferGeometry {
constructor(shape) {
super();
this.worldScale = 1;
this._currentRadius = 0;
this._currentOffset = new Vector3();
this._currentTail = new Vector3();
this._shape = shape;
this._attrPos = new BufferAttribute(new Float32Array(396), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(264), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
const radius = this._shape.radius / this.worldScale;
if (this._currentRadius !== radius) {
this._currentRadius = radius;
shouldUpdateGeometry = true;
}
if (!this._currentOffset.equals(this._shape.offset)) {
this._currentOffset.copy(this._shape.offset);
shouldUpdateGeometry = true;
}
const tail = _v3A43.copy(this._shape.tail).divideScalar(this.worldScale);
if (this._currentTail.distanceToSquared(tail) > 1e-10) {
this._currentTail.copy(tail);
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
_v3A43.copy(this._currentTail).sub(this._currentOffset);
const l = _v3A43.length() / this._currentRadius;
for (let i = 0; i <= 16; i++) {
const t = i / 16 * Math.PI;
this._attrPos.setXYZ(i, -Math.sin(t), -Math.cos(t), 0);
this._attrPos.setXYZ(17 + i, l + Math.sin(t), Math.cos(t), 0);
this._attrPos.setXYZ(34 + i, -Math.sin(t), 0, -Math.cos(t));
this._attrPos.setXYZ(51 + i, l + Math.sin(t), 0, Math.cos(t));
}
for (let i = 0; i < 32; i++) {
const t = i / 16 * Math.PI;
this._attrPos.setXYZ(68 + i, 0, Math.sin(t), Math.cos(t));
this._attrPos.setXYZ(100 + i, l, Math.sin(t), Math.cos(t));
}
const theta = Math.atan2(_v3A43.y, Math.sqrt(_v3A43.x * _v3A43.x + _v3A43.z * _v3A43.z));
const phi = -Math.atan2(_v3A43.z, _v3A43.x);
this.rotateZ(theta);
this.rotateY(phi);
this.scale(this._currentRadius, this._currentRadius, this._currentRadius);
this.translate(this._currentOffset.x, this._currentOffset.y, this._currentOffset.z);
this._attrPos.needsUpdate = true;
}
_buildIndex() {
for (let i = 0; i < 34; i++) {
const i1 = (i + 1) % 34;
this._attrIndex.setXY(i * 2, i, i1);
this._attrIndex.setXY(68 + i * 2, 34 + i, 34 + i1);
}
for (let i = 0; i < 32; i++) {
const i1 = (i + 1) % 32;
this._attrIndex.setXY(136 + i * 2, 68 + i, 68 + i1);
this._attrIndex.setXY(200 + i * 2, 100 + i, 100 + i1);
}
this._attrIndex.needsUpdate = true;
}
};
var ColliderShapePlaneBufferGeometry = class extends BufferGeometry {
constructor(shape) {
super();
this.worldScale = 1;
this._currentOffset = new Vector3();
this._currentNormal = new Vector3();
this._shape = shape;
this._attrPos = new BufferAttribute(new Float32Array(18), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(10), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
if (!this._currentOffset.equals(this._shape.offset)) {
this._currentOffset.copy(this._shape.offset);
shouldUpdateGeometry = true;
}
if (!this._currentNormal.equals(this._shape.normal)) {
this._currentNormal.copy(this._shape.normal);
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
this._attrPos.setXYZ(0, -.5, -.5, 0);
this._attrPos.setXYZ(1, .5, -.5, 0);
this._attrPos.setXYZ(2, .5, .5, 0);
this._attrPos.setXYZ(3, -.5, .5, 0);
this._attrPos.setXYZ(4, 0, 0, 0);
this._attrPos.setXYZ(5, 0, 0, .25);
this.translate(this._currentOffset.x, this._currentOffset.y, this._currentOffset.z);
this.lookAt(this._currentNormal);
this._attrPos.needsUpdate = true;
}
_buildIndex() {
this._attrIndex.setXY(0, 0, 1);
this._attrIndex.setXY(2, 1, 2);
this._attrIndex.setXY(4, 2, 3);
this._attrIndex.setXY(6, 3, 0);
this._attrIndex.setXY(8, 4, 5);
this._attrIndex.needsUpdate = true;
}
};
var ColliderShapeSphereBufferGeometry = class extends BufferGeometry {
constructor(shape) {
super();
this.worldScale = 1;
this._currentRadius = 0;
this._currentOffset = new Vector3();
this._shape = shape;
this._attrPos = new BufferAttribute(new Float32Array(288), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(192), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
const radius = this._shape.radius / this.worldScale;
if (this._currentRadius !== radius) {
this._currentRadius = radius;
shouldUpdateGeometry = true;
}
if (!this._currentOffset.equals(this._shape.offset)) {
this._currentOffset.copy(this._shape.offset);
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
for (let i = 0; i < 32; i++) {
const t = i / 16 * Math.PI;
this._attrPos.setXYZ(i, Math.cos(t), Math.sin(t), 0);
this._attrPos.setXYZ(32 + i, 0, Math.cos(t), Math.sin(t));
this._attrPos.setXYZ(64 + i, Math.sin(t), 0, Math.cos(t));
}
this.scale(this._currentRadius, this._currentRadius, this._currentRadius);
this.translate(this._currentOffset.x, this._currentOffset.y, this._currentOffset.z);
this._attrPos.needsUpdate = true;
}
_buildIndex() {
for (let i = 0; i < 32; i++) {
const i1 = (i + 1) % 32;
this._attrIndex.setXY(i * 2, i, i1);
this._attrIndex.setXY(64 + i * 2, 32 + i, 32 + i1);
this._attrIndex.setXY(128 + i * 2, 64 + i, 64 + i1);
}
this._attrIndex.needsUpdate = true;
}
};
var _v3A52 = new Vector3();
var VRMSpringBoneColliderHelper = class extends Group {
constructor(collider) {
super();
this.matrixAutoUpdate = false;
this.collider = collider;
if (this.collider.shape instanceof VRMSpringBoneColliderShapeSphere) this._geometry = new ColliderShapeSphereBufferGeometry(this.collider.shape);
else if (this.collider.shape instanceof VRMSpringBoneColliderShapeCapsule) this._geometry = new ColliderShapeCapsuleBufferGeometry(this.collider.shape);
else if (this.collider.shape instanceof VRMSpringBoneColliderShapePlane) this._geometry = new ColliderShapePlaneBufferGeometry(this.collider.shape);
else throw new Error("VRMSpringBoneColliderHelper: Unknown collider shape type detected");
const material = new LineBasicMaterial({
color: 16711935,
depthTest: false,
depthWrite: false
});
this._line = new LineSegments(this._geometry, material);
this.add(this._line);
}
dispose() {
this._geometry.dispose();
}
updateMatrixWorld(force) {
this.collider.updateWorldMatrix(true, false);
this.matrix.copy(this.collider.matrixWorld);
const matrixWorldElements = this.matrix.elements;
this._geometry.worldScale = _v3A52.set(matrixWorldElements[0], matrixWorldElements[1], matrixWorldElements[2]).length();
this._geometry.update();
super.updateMatrixWorld(force);
}
};
var SpringBoneBufferGeometry = class extends BufferGeometry {
constructor(springBone) {
super();
this.worldScale = 1;
this._currentRadius = 0;
this._currentTail = new Vector3();
this._springBone = springBone;
this._attrPos = new BufferAttribute(new Float32Array(294), 3);
this.setAttribute("position", this._attrPos);
this._attrIndex = new BufferAttribute(new Uint16Array(194), 1);
this.setIndex(this._attrIndex);
this._buildIndex();
this.update();
}
update() {
let shouldUpdateGeometry = false;
const radius = this._springBone.settings.hitRadius / this.worldScale;
if (this._currentRadius !== radius) {
this._currentRadius = radius;
shouldUpdateGeometry = true;
}
if (!this._currentTail.equals(this._springBone.initialLocalChildPosition)) {
this._currentTail.copy(this._springBone.initialLocalChildPosition);
shouldUpdateGeometry = true;
}
if (shouldUpdateGeometry) this._buildPosition();
}
_buildPosition() {
for (let i = 0; i < 32; i++) {
const t = i / 16 * Math.PI;
this._attrPos.setXYZ(i, Math.cos(t), Math.sin(t), 0);
this._attrPos.setXYZ(32 + i, 0, Math.cos(t), Math.sin(t));
this._attrPos.setXYZ(64 + i, Math.sin(t), 0, Math.cos(t));
}
this.scale(this._currentRadius, this._currentRadius, this._currentRadius);
this.translate(this._currentTail.x, this._currentTail.y, this._currentTail.z);
this._attrPos.setXYZ(96, 0, 0, 0);
this._attrPos.setXYZ(97, this._currentTail.x, this._currentTail.y, this._currentTail.z);
this._attrPos.needsUpdate = true;
}
_buildIndex() {
for (let i = 0; i < 32; i++) {
const i1 = (i + 1) % 32;
this._attrIndex.setXY(i * 2, i, i1);
this._attrIndex.setXY(64 + i * 2, 32 + i, 32 + i1);
this._attrIndex.setXY(128 + i * 2, 64 + i, 64 + i1);
}
this._attrIndex.setXY(192, 96, 97);
this._attrIndex.needsUpdate = true;
}
};
var _v3A62 = new Vector3();
var VRMSpringBoneJointHelper = class extends Group {
constructor(springBone) {
super();
this.matrixAutoUpdate = false;
this.springBone = springBone;
this._geometry = new SpringBoneBufferGeometry(this.springBone);
const material = new LineBasicMaterial({
color: 16776960,
depthTest: false,
depthWrite: false
});
this._line = new LineSegments(this._geometry, material);
this.add(this._line);
}
dispose() {
this._geometry.dispose();
}
updateMatrixWorld(force) {
this.springBone.bone.updateWorldMatrix(true, false);
this.matrix.copy(this.springBone.bone.matrixWorld);
const matrixWorldElements = this.matrix.elements;
this._geometry.worldScale = _v3A62.set(matrixWorldElements[0], matrixWorldElements[1], matrixWorldElements[2]).length();
this._geometry.update();
super.updateMatrixWorld(force);
}
};
var VRMSpringBoneCollider = class extends Object3D {
constructor(shape) {
super();
this.colliderMatrix = new Matrix4();
this.shape = shape;
}
updateWorldMatrix(updateParents, updateChildren) {
super.updateWorldMatrix(updateParents, updateChildren);
updateColliderMatrix(this.colliderMatrix, this.matrixWorld, this.shape.offset);
}
};
function updateColliderMatrix(colliderMatrix, matrixWorld, offset) {
const me = matrixWorld.elements;
colliderMatrix.copy(matrixWorld);
if (offset) {
colliderMatrix.elements[12] = me[0] * offset.x + me[4] * offset.y + me[8] * offset.z + me[12];
colliderMatrix.elements[13] = me[1] * offset.x + me[5] * offset.y + me[9] * offset.z + me[13];
colliderMatrix.elements[14] = me[2] * offset.x + me[6] * offset.y + me[10] * offset.z + me[14];
}
}
var _matA = new Matrix4();
function mat4InvertCompat(target) {
if (target.invert) target.invert();
else target.getInverse(_matA.copy(target));
return target;
}
var Matrix4InverseCache = class {
constructor(matrix) {
this._inverseCache = new Matrix4();
this._shouldUpdateInverse = true;
this.matrix = matrix;
const handler = { set: (obj, prop, newVal) => {
this._shouldUpdateInverse = true;
obj[prop] = newVal;
return true;
} };
this._originalElements = matrix.elements;
matrix.elements = new Proxy(matrix.elements, handler);
}
/**
* Inverse of given matrix.
* Note that it will return its internal private instance.
* Make sure copying this before mutate this.
*/
get inverse() {
if (this._shouldUpdateInverse) {
mat4InvertCompat(this._inverseCache.copy(this.matrix));
this._shouldUpdateInverse = false;
}
return this._inverseCache;
}
revert() {
this.matrix.elements = this._originalElements;
}
};
var IDENTITY_MATRIX4 = new Matrix4();
var _v3A72 = new Vector3();
var _v3B23 = new Vector3();
var _worldSpacePosition = new Vector3();
var _nextTail = new Vector3();
var _matA2 = new Matrix4();
var VRMSpringBoneJoint = class {
/**
* Create a new VRMSpringBone.
*
* @param bone An Object3D that will be attached to this bone
* @param child An Object3D that will be used as a tail of this spring bone. It can be null when the spring bone is imported from VRM 0.0
* @param settings Several parameters related to behavior of the spring bone
* @param colliderGroups Collider groups that will be collided with this spring bone
*/
constructor(bone, child, settings = {}, colliderGroups = []) {
this._currentTail = new Vector3();
this._prevTail = new Vector3();
this._boneAxis = new Vector3();
this._worldSpaceBoneLength = 0;
this._center = null;
this._initialLocalMatrix = new Matrix4();
this._initialLocalRotation = new Quaternion();
this._initialLocalChildPosition = new Vector3();
var _a, _b, _c, _d, _e, _f;
this.bone = bone;
this.bone.matrixAutoUpdate = false;
this.child = child;
this.settings = {
hitRadius: (_a = settings.hitRadius) != null ? _a : 0,
stiffness: (_b = settings.stiffness) != null ? _b : 1,
gravityPower: (_c = settings.gravityPower) != null ? _c : 0,
gravityDir: (_e = (_d = settings.gravityDir) == null ? void 0 : _d.clone()) != null ? _e : new Vector3(0, -1, 0),
dragForce: (_f = settings.dragForce) != null ? _f : .4
};
this.colliderGroups = colliderGroups;
}
/**
* Set of dependencies that need to be updated before this joint.
*/
get dependencies() {
const set = /* @__PURE__ */ new Set();
const parent = this.bone.parent;
if (parent) set.add(parent);
for (let cg = 0; cg < this.colliderGroups.length; cg++) for (let c = 0; c < this.colliderGroups[cg].colliders.length; c++) set.add(this.colliderGroups[cg].colliders[c]);
return set;
}
get center() {
return this._center;
}
set center(center) {
var _a;
if ((_a = this._center) == null ? void 0 : _a.userData.inverseCacheProxy) {
this._center.userData.inverseCacheProxy.revert();
delete this._center.userData.inverseCacheProxy;
}
this._center = center;
if (this._center) {
if (!this._center.userData.inverseCacheProxy) this._center.userData.inverseCacheProxy = new Matrix4InverseCache(this._center.matrixWorld);
}
}
get initialLocalChildPosition() {
return this._initialLocalChildPosition;
}
/**
* Returns the world matrix of its parent object.
* Note that it returns a reference to the matrix. Don't mutate this directly!
*/
get _parentMatrixWorld() {
return this.bone.parent ? this.bone.parent.matrixWorld : IDENTITY_MATRIX4;
}
/**
* Set the initial state of this spring bone.
* You might want to call {@link VRMSpringBoneManager.setInitState} instead.
*/
setInitState() {
this._initialLocalMatrix.copy(this.bone.matrix);
this._initialLocalRotation.copy(this.bone.quaternion);
if (this.child) this._initialLocalChildPosition.copy(this.child.position);
else this._initialLocalChildPosition.copy(this.bone.position).normalize().multiplyScalar(.07);
const matrixWorldToCenter = this._getMatrixWorldToCenter();
this.bone.localToWorld(this._currentTail.copy(this._initialLocalChildPosition)).applyMatrix4(matrixWorldToCenter);
this._prevTail.copy(this._currentTail);
this._boneAxis.copy(this._initialLocalChildPosition).normalize();
}
/**
* Reset the state of this bone.
* You might want to call {@link VRMSpringBoneManager.reset} instead.
*/
reset() {
this.bone.quaternion.copy(this._initialLocalRotation);
this.bone.updateMatrix();
this.bone.matrixWorld.multiplyMatrices(this._parentMatrixWorld, this.bone.matrix);
const matrixWorldToCenter = this._getMatrixWorldToCenter();
this.bone.localToWorld(this._currentTail.copy(this._initialLocalChildPosition)).applyMatrix4(matrixWorldToCenter);
this._prevTail.copy(this._currentTail);
}
/**
* Update the state of this bone.
* You might want to call {@link VRMSpringBoneManager.update} instead.
*
* @param delta deltaTime
*/
update(delta) {
if (delta <= 0) return;
this._calcWorldSpaceBoneLength();
const worldSpaceBoneAxis = _v3B23.copy(this._boneAxis).transformDirection(this._initialLocalMatrix).transformDirection(this._parentMatrixWorld);
_nextTail.copy(this._currentTail).add(_v3A72.subVectors(this._currentTail, this._prevTail).multiplyScalar(1 - this.settings.dragForce)).applyMatrix4(this._getMatrixCenterToWorld()).addScaledVector(worldSpaceBoneAxis, this.settings.stiffness * delta).addScaledVector(this.settings.gravityDir, this.settings.gravityPower * delta);
_worldSpacePosition.setFromMatrixPosition(this.bone.matrixWorld);
_nextTail.sub(_worldSpacePosition).normalize().multiplyScalar(this._worldSpaceBoneLength).add(_worldSpacePosition);
this._collision(_nextTail);
this._prevTail.copy(this._currentTail);
this._currentTail.copy(_nextTail).applyMatrix4(this._getMatrixWorldToCenter());
const worldSpaceInitialMatrixInv = _matA2.multiplyMatrices(this._parentMatrixWorld, this._initialLocalMatrix).invert();
this.bone.quaternion.setFromUnitVectors(this._boneAxis, _v3A72.copy(_nextTail).applyMatrix4(worldSpaceInitialMatrixInv).normalize()).premultiply(this._initialLocalRotation);
this.bone.updateMatrix();
this.bone.matrixWorld.multiplyMatrices(this._parentMatrixWorld, this.bone.matrix);
}
/**
* Do collision math against every colliders attached to this bone.
*
* @param tail The tail you want to process
*/
_collision(tail) {
for (let cg = 0; cg < this.colliderGroups.length; cg++) for (let c = 0; c < this.colliderGroups[cg].colliders.length; c++) {
const collider = this.colliderGroups[cg].colliders[c];
const dist = collider.shape.calculateCollision(collider.colliderMatrix, tail, this.settings.hitRadius, _v3A72);
if (dist < 0) {
tail.addScaledVector(_v3A72, -dist);
tail.sub(_worldSpacePosition);
const length = tail.length();
tail.multiplyScalar(this._worldSpaceBoneLength / length).add(_worldSpacePosition);
}
}
}
/**
* Calculate the {@link _worldSpaceBoneLength}.
* Intended to be used in {@link update}.
*/
_calcWorldSpaceBoneLength() {
_v3A72.setFromMatrixPosition(this.bone.matrixWorld);
if (this.child) _v3B23.setFromMatrixPosition(this.child.matrixWorld);
else {
_v3B23.copy(this._initialLocalChildPosition);
_v3B23.applyMatrix4(this.bone.matrixWorld);
}
this._worldSpaceBoneLength = _v3A72.sub(_v3B23).length();
}
/**
* Create a matrix that converts center space into world space.
*/
_getMatrixCenterToWorld() {
return this._center ? this._center.matrixWorld : IDENTITY_MATRIX4;
}
/**
* Create a matrix that converts world space into center space.
*/
_getMatrixWorldToCenter() {
return this._center ? this._center.userData.inverseCacheProxy.inverse : IDENTITY_MATRIX4;
}
};
function traverseAncestorsFromRoot2(object, callback) {
const ancestors = [];
let head = object;
while (head !== null) {
ancestors.unshift(head);
head = head.parent;
}
ancestors.forEach((ancestor) => {
callback(ancestor);
});
}
function traverseChildrenUntilConditionMet(object, callback) {
object.children.forEach((child) => {
if (!callback(child)) traverseChildrenUntilConditionMet(child, callback);
});
}
function lowestCommonAncestor(objects) {
var _a;
const sharedAncestors = /* @__PURE__ */ new Map();
for (const object of objects) {
let current = object;
do {
const newValue = ((_a = sharedAncestors.get(current)) != null ? _a : 0) + 1;
if (newValue === objects.size) return current;
sharedAncestors.set(current, newValue);
current = current.parent;
} while (current !== null);
}
return null;
}
var VRMSpringBoneManager = class {
constructor() {
this._joints = /* @__PURE__ */ new Set();
this._sortedJoints = [];
this._hasWarnedCircularDependency = false;
this._ancestors = [];
this._objectSpringBonesMap = /* @__PURE__ */ new Map();
this._isSortedJointsDirty = false;
this._relevantChildrenUpdated = this._relevantChildrenUpdated.bind(this);
}
get joints() {
return this._joints;
}
/**
* @deprecated Use {@link joints} instead.
*/
get springBones() {
console.warn("VRMSpringBoneManager: springBones is deprecated. use joints instead.");
return this._joints;
}
get colliderGroups() {
const set = /* @__PURE__ */ new Set();
this._joints.forEach((springBone) => {
springBone.colliderGroups.forEach((colliderGroup) => {
set.add(colliderGroup);
});
});
return Array.from(set);
}
get colliders() {
const set = /* @__PURE__ */ new Set();
this.colliderGroups.forEach((colliderGroup) => {
colliderGroup.colliders.forEach((collider) => {
set.add(collider);
});
});
return Array.from(set);
}
addJoint(joint) {
this._joints.add(joint);
let objectSet = this._objectSpringBonesMap.get(joint.bone);
if (objectSet == null) {
objectSet = /* @__PURE__ */ new Set();
this._objectSpringBonesMap.set(joint.bone, objectSet);
}
objectSet.add(joint);
this._isSortedJointsDirty = true;
}
/**
* @deprecated Use {@link addJoint} instead.
*/
addSpringBone(joint) {
console.warn("VRMSpringBoneManager: addSpringBone() is deprecated. use addJoint() instead.");
this.addJoint(joint);
}
deleteJoint(joint) {
this._joints.delete(joint);
this._objectSpringBonesMap.get(joint.bone).delete(joint);
this._isSortedJointsDirty = true;
}
/**
* @deprecated Use {@link deleteJoint} instead.
*/
deleteSpringBone(joint) {
console.warn("VRMSpringBoneManager: deleteSpringBone() is deprecated. use deleteJoint() instead.");
this.deleteJoint(joint);
}
setInitState() {
this._sortJoints();
for (let i = 0; i < this._sortedJoints.length; i++) {
const springBone = this._sortedJoints[i];
springBone.bone.updateMatrix();
springBone.bone.updateWorldMatrix(false, false);
springBone.setInitState();
}
}
reset() {
this._sortJoints();
for (let i = 0; i < this._sortedJoints.length; i++) {
const springBone = this._sortedJoints[i];
springBone.bone.updateMatrix();
springBone.bone.updateWorldMatrix(false, false);
springBone.reset();
}
}
update(delta) {
this._sortJoints();
for (let i = 0; i < this._ancestors.length; i++) this._ancestors[i].updateWorldMatrix(i === 0, false);
for (let i = 0; i < this._sortedJoints.length; i++) {
const springBone = this._sortedJoints[i];
springBone.bone.updateMatrix();
springBone.bone.updateWorldMatrix(false, false);
springBone.update(delta);
traverseChildrenUntilConditionMet(springBone.bone, this._relevantChildrenUpdated);
}
}
/**
* Sorts the joints ensuring they are updated in the correct order taking dependencies into account.
*
* This method updates {@link _sortedJoints} and {@link _ancestors}.
* Make sure to call this before using them.
*/
_sortJoints() {
if (!this._isSortedJointsDirty) return;
const springBoneOrder = [];
const springBonesTried = /* @__PURE__ */ new Set();
const springBonesDone = /* @__PURE__ */ new Set();
const ancestors = /* @__PURE__ */ new Set();
for (const springBone of this._joints) this._insertJointSort(springBone, springBonesTried, springBonesDone, springBoneOrder, ancestors);
this._sortedJoints = springBoneOrder;
const lca = lowestCommonAncestor(ancestors);
this._ancestors = [];
if (lca) {
this._ancestors.push(lca);
traverseChildrenUntilConditionMet(lca, (object) => {
var _a, _b;
if (((_b = (_a = this._objectSpringBonesMap.get(object)) == null ? void 0 : _a.size) != null ? _b : 0) > 0) return true;
this._ancestors.push(object);
return false;
});
}
this._isSortedJointsDirty = false;
}
_insertJointSort(springBone, springBonesTried, springBonesDone, springBoneOrder, ancestors) {
if (springBonesDone.has(springBone)) return;
if (springBonesTried.has(springBone)) {
if (!this._hasWarnedCircularDependency) {
console.warn("VRMSpringBoneManager: Circular dependency detected");
this._hasWarnedCircularDependency = true;
}
return;
}
springBonesTried.add(springBone);
const depObjects = springBone.dependencies;
for (const depObject of depObjects) {
let encounteredSpringBone = false;
let ancestor = null;
traverseAncestorsFromRoot2(depObject, (depObjectAncestor) => {
const objectSet = this._objectSpringBonesMap.get(depObjectAncestor);
if (objectSet) for (const depSpringBone of objectSet) {
encounteredSpringBone = true;
this._insertJointSort(depSpringBone, springBonesTried, springBonesDone, springBoneOrder, ancestors);
}
else if (!encounteredSpringBone) ancestor = depObjectAncestor;
});
if (ancestor) ancestors.add(ancestor);
}
springBoneOrder.push(springBone);
springBonesDone.add(springBone);
}
_relevantChildrenUpdated(object) {
var _a, _b;
if (((_b = (_a = this._objectSpringBonesMap.get(object)) == null ? void 0 : _a.size) != null ? _b : 0) > 0) return true;
object.updateWorldMatrix(false, false);
return false;
}
};
var EXTENSION_NAME_EXTENDED_COLLIDER = "VRMC_springBone_extended_collider";
var POSSIBLE_SPEC_VERSIONS8 = /* @__PURE__ */ new Set(["1.0", "1.0-beta"]);
var POSSIBLE_SPEC_VERSIONS_EXTENDED_COLLIDERS = /* @__PURE__ */ new Set(["1.0"]);
var _VRMSpringBoneLoaderPlugin = class _VRMSpringBoneLoaderPlugin2 {
get name() {
return _VRMSpringBoneLoaderPlugin2.EXTENSION_NAME;
}
constructor(parser, options) {
var _a;
this.parser = parser;
this.jointHelperRoot = options == null ? void 0 : options.jointHelperRoot;
this.colliderHelperRoot = options == null ? void 0 : options.colliderHelperRoot;
this.useExtendedColliders = (_a = options == null ? void 0 : options.useExtendedColliders) != null ? _a : true;
}
afterRoot(gltf) {
return __async7(this, null, function* () {
gltf.userData.vrmSpringBoneManager = yield this._import(gltf);
});
}
/**
* Import spring bones from a GLTF and return a {@link VRMSpringBoneManager}.
* It might return `null` instead when it does not need to be created or something go wrong.
*
* @param gltf A parsed result of GLTF taken from GLTFLoader
*/
_import(gltf) {
return __async7(this, null, function* () {
const v1Result = yield this._v1Import(gltf);
if (v1Result != null) return v1Result;
const v0Result = yield this._v0Import(gltf);
if (v0Result != null) return v0Result;
return null;
});
}
_v1Import(gltf) {
return __async7(this, null, function* () {
var _a, _b, _c, _d, _e;
const json = gltf.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf(_VRMSpringBoneLoaderPlugin2.EXTENSION_NAME)) !== -1)) return null;
const manager = new VRMSpringBoneManager();
const threeNodes = yield gltf.parser.getDependencies("node");
const extension = (_b = json.extensions) == null ? void 0 : _b[_VRMSpringBoneLoaderPlugin2.EXTENSION_NAME];
if (!extension) return null;
const specVersion = extension.specVersion;
if (!POSSIBLE_SPEC_VERSIONS8.has(specVersion)) {
console.warn(`VRMSpringBoneLoaderPlugin: Unknown ${_VRMSpringBoneLoaderPlugin2.EXTENSION_NAME} specVersion "${specVersion}"`);
return null;
}
const colliders = (_c = extension.colliders) == null ? void 0 : _c.map((schemaCollider, iCollider) => {
var _a2, _b2, _c2, _d2, _e2, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
const node = threeNodes[schemaCollider.node];
if (node == null) {
console.warn(`VRMSpringBoneLoaderPlugin: The collider #${iCollider} attempted to use the node #${schemaCollider.node} but not found`);
return null;
}
const schemaShape = schemaCollider.shape;
const schemaExCollider = (_a2 = schemaCollider.extensions) == null ? void 0 : _a2[EXTENSION_NAME_EXTENDED_COLLIDER];
if (this.useExtendedColliders && schemaExCollider != null) {
const specVersionExCollider = schemaExCollider.specVersion;
if (!POSSIBLE_SPEC_VERSIONS_EXTENDED_COLLIDERS.has(specVersionExCollider)) console.warn(`VRMSpringBoneLoaderPlugin: Unknown ${EXTENSION_NAME_EXTENDED_COLLIDER} specVersion "${specVersionExCollider}". Fallbacking to the ${_VRMSpringBoneLoaderPlugin2.EXTENSION_NAME} definition`);
else {
const schemaExShape = schemaExCollider.shape;
if (schemaExShape.sphere) return this._importSphereCollider(node, {
offset: new Vector3().fromArray((_b2 = schemaExShape.sphere.offset) != null ? _b2 : [
0,
0,
0
]),
radius: (_c2 = schemaExShape.sphere.radius) != null ? _c2 : 0,
inside: (_d2 = schemaExShape.sphere.inside) != null ? _d2 : false
});
else if (schemaExShape.capsule) return this._importCapsuleCollider(node, {
offset: new Vector3().fromArray((_e2 = schemaExShape.capsule.offset) != null ? _e2 : [
0,
0,
0
]),
radius: (_f = schemaExShape.capsule.radius) != null ? _f : 0,
tail: new Vector3().fromArray((_g = schemaExShape.capsule.tail) != null ? _g : [
0,
0,
0
]),
inside: (_h = schemaExShape.capsule.inside) != null ? _h : false
});
else if (schemaExShape.plane) return this._importPlaneCollider(node, {
offset: new Vector3().fromArray((_i = schemaExShape.plane.offset) != null ? _i : [
0,
0,
0
]),
normal: new Vector3().fromArray((_j = schemaExShape.plane.normal) != null ? _j : [
0,
0,
1
])
});
}
}
if (schemaShape.sphere) return this._importSphereCollider(node, {
offset: new Vector3().fromArray((_k = schemaShape.sphere.offset) != null ? _k : [
0,
0,
0
]),
radius: (_l = schemaShape.sphere.radius) != null ? _l : 0,
inside: false
});
else if (schemaShape.capsule) return this._importCapsuleCollider(node, {
offset: new Vector3().fromArray((_m = schemaShape.capsule.offset) != null ? _m : [
0,
0,
0
]),
radius: (_n = schemaShape.capsule.radius) != null ? _n : 0,
tail: new Vector3().fromArray((_o = schemaShape.capsule.tail) != null ? _o : [
0,
0,
0
]),
inside: false
});
throw new Error(`VRMSpringBoneLoaderPlugin: The collider #${iCollider} has no valid shape`);
});
const colliderGroups = (_d = extension.colliderGroups) == null ? void 0 : _d.map((schemaColliderGroup, iColliderGroup) => {
var _a2;
return {
colliders: ((_a2 = schemaColliderGroup.colliders) != null ? _a2 : []).flatMap((iCollider) => {
const col = colliders == null ? void 0 : colliders[iCollider];
if (col == null) {
console.warn(`VRMSpringBoneLoaderPlugin: The colliderGroup #${iColliderGroup} attempted to use a collider #${iCollider} but not found`);
return [];
}
return col;
}),
name: schemaColliderGroup.name
};
});
(_e = extension.springs) == null || _e.forEach((schemaSpring, iSpring) => {
var _a2;
const schemaJoints = schemaSpring.joints;
const colliderGroupsForSpring = (_a2 = schemaSpring.colliderGroups) == null ? void 0 : _a2.map((iColliderGroup) => {
const group = colliderGroups == null ? void 0 : colliderGroups[iColliderGroup];
if (group == null) throw new Error(`VRMSpringBoneLoaderPlugin: The spring #${iSpring} attempted to use a colliderGroup ${iColliderGroup} but not found`);
return group;
});
const center = schemaSpring.center != null ? threeNodes[schemaSpring.center] : void 0;
let prevSchemaJoint;
schemaJoints.forEach((schemaJoint) => {
if (prevSchemaJoint) {
const node = threeNodes[prevSchemaJoint.node];
const child = threeNodes[schemaJoint.node];
const setting = {
hitRadius: prevSchemaJoint.hitRadius,
dragForce: prevSchemaJoint.dragForce,
gravityPower: prevSchemaJoint.gravityPower,
stiffness: prevSchemaJoint.stiffness,
gravityDir: prevSchemaJoint.gravityDir != null ? new Vector3().fromArray(prevSchemaJoint.gravityDir) : void 0
};
const joint = this._importJoint(node, child, setting, colliderGroupsForSpring);
if (center) joint.center = center;
manager.addJoint(joint);
}
prevSchemaJoint = schemaJoint;
});
});
manager.setInitState();
return manager;
});
}
_v0Import(gltf) {
return __async7(this, null, function* () {
var _a, _b, _c;
const json = gltf.parser.json;
if (!(((_a = json.extensionsUsed) == null ? void 0 : _a.indexOf("VRM")) !== -1)) return null;
const extension = (_b = json.extensions) == null ? void 0 : _b["VRM"];
const schemaSecondaryAnimation = extension == null ? void 0 : extension.secondaryAnimation;
if (!schemaSecondaryAnimation) return null;
const schemaBoneGroups = schemaSecondaryAnimation == null ? void 0 : schemaSecondaryAnimation.boneGroups;
if (!schemaBoneGroups) return null;
const manager = new VRMSpringBoneManager();
const threeNodes = yield gltf.parser.getDependencies("node");
const colliderGroups = (_c = schemaSecondaryAnimation.colliderGroups) == null ? void 0 : _c.map((schemaColliderGroup) => {
var _a2;
const node = threeNodes[schemaColliderGroup.node];
return { colliders: ((_a2 = schemaColliderGroup.colliders) != null ? _a2 : []).map((schemaCollider, iCollider) => {
var _a3, _b2, _c2;
const offset = new Vector3(0, 0, 0);
if (schemaCollider.offset) offset.set((_a3 = schemaCollider.offset.x) != null ? _a3 : 0, (_b2 = schemaCollider.offset.y) != null ? _b2 : 0, schemaCollider.offset.z ? -schemaCollider.offset.z : 0);
return this._importSphereCollider(node, {
offset,
radius: (_c2 = schemaCollider.radius) != null ? _c2 : 0,
inside: false
});
}) };
});
schemaBoneGroups?.forEach((schemaBoneGroup, iBoneGroup) => {
const rootIndices = schemaBoneGroup.bones;
if (!rootIndices) return;
rootIndices.forEach((rootIndex) => {
var _a2, _b2, _c2, _d;
const root = threeNodes[rootIndex];
const gravityDir = new Vector3();
if (schemaBoneGroup.gravityDir) gravityDir.set((_a2 = schemaBoneGroup.gravityDir.x) != null ? _a2 : 0, (_b2 = schemaBoneGroup.gravityDir.y) != null ? _b2 : 0, (_c2 = schemaBoneGroup.gravityDir.z) != null ? _c2 : 0);
else gravityDir.set(0, -1, 0);
const center = schemaBoneGroup.center != null ? threeNodes[schemaBoneGroup.center] : void 0;
const setting = {
hitRadius: schemaBoneGroup.hitRadius,
dragForce: schemaBoneGroup.dragForce,
gravityPower: schemaBoneGroup.gravityPower,
stiffness: schemaBoneGroup.stiffiness,
gravityDir
};
const colliderGroupsForSpring = (_d = schemaBoneGroup.colliderGroups) == null ? void 0 : _d.map((iColliderGroup) => {
const group = colliderGroups == null ? void 0 : colliderGroups[iColliderGroup];
if (group == null) throw new Error(`VRMSpringBoneLoaderPlugin: The spring #${iBoneGroup} attempted to use a colliderGroup ${iColliderGroup} but not found`);
return group;
});
root.traverse((node) => {
var _a3;
const child = (_a3 = node.children[0]) != null ? _a3 : null;
const joint = this._importJoint(node, child, setting, colliderGroupsForSpring);
if (center) joint.center = center;
manager.addJoint(joint);
});
});
});
gltf.scene.updateMatrixWorld();
manager.setInitState();
return manager;
});
}
_importJoint(node, child, setting, colliderGroupsForSpring) {
const springBone = new VRMSpringBoneJoint(node, child, setting, colliderGroupsForSpring);
if (this.jointHelperRoot) {
const helper = new VRMSpringBoneJointHelper(springBone);
this.jointHelperRoot.add(helper);
helper.renderOrder = this.jointHelperRoot.renderOrder;
}
return springBone;
}
_importSphereCollider(destination, params) {
const collider = new VRMSpringBoneCollider(new VRMSpringBoneColliderShapeSphere(params));
destination.add(collider);
if (this.colliderHelperRoot) {
const helper = new VRMSpringBoneColliderHelper(collider);
this.colliderHelperRoot.add(helper);
helper.renderOrder = this.colliderHelperRoot.renderOrder;
}
return collider;
}
_importCapsuleCollider(destination, params) {
const collider = new VRMSpringBoneCollider(new VRMSpringBoneColliderShapeCapsule(params));
destination.add(collider);
if (this.colliderHelperRoot) {
const helper = new VRMSpringBoneColliderHelper(collider);
this.colliderHelperRoot.add(helper);
helper.renderOrder = this.colliderHelperRoot.renderOrder;
}
return collider;
}
_importPlaneCollider(destination, params) {
const collider = new VRMSpringBoneCollider(new VRMSpringBoneColliderShapePlane(params));
destination.add(collider);
if (this.colliderHelperRoot) {
const helper = new VRMSpringBoneColliderHelper(collider);
this.colliderHelperRoot.add(helper);
helper.renderOrder = this.colliderHelperRoot.renderOrder;
}
return collider;
}
};
_VRMSpringBoneLoaderPlugin.EXTENSION_NAME = "VRMC_springBone";
var VRMSpringBoneLoaderPlugin = _VRMSpringBoneLoaderPlugin;
var VRMLoaderPlugin = class {
get name() {
return "VRMLoaderPlugin";
}
constructor(parser, options) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
this.parser = parser;
const helperRoot = options == null ? void 0 : options.helperRoot;
const autoUpdateHumanBones = options == null ? void 0 : options.autoUpdateHumanBones;
this.expressionPlugin = (_a = options == null ? void 0 : options.expressionPlugin) != null ? _a : new VRMExpressionLoaderPlugin(parser);
this.firstPersonPlugin = (_b = options == null ? void 0 : options.firstPersonPlugin) != null ? _b : new VRMFirstPersonLoaderPlugin(parser);
this.humanoidPlugin = (_c = options == null ? void 0 : options.humanoidPlugin) != null ? _c : new VRMHumanoidLoaderPlugin(parser, {
helperRoot,
autoUpdateHumanBones
});
this.lookAtPlugin = (_d = options == null ? void 0 : options.lookAtPlugin) != null ? _d : new VRMLookAtLoaderPlugin(parser, { helperRoot });
this.metaPlugin = (_e = options == null ? void 0 : options.metaPlugin) != null ? _e : new VRMMetaLoaderPlugin(parser);
this.mtoonMaterialPlugin = (_f = options == null ? void 0 : options.mtoonMaterialPlugin) != null ? _f : new MToonMaterialLoaderPlugin(parser);
this.materialsHDREmissiveMultiplierPlugin = (_g = options == null ? void 0 : options.materialsHDREmissiveMultiplierPlugin) != null ? _g : new VRMMaterialsHDREmissiveMultiplierLoaderPlugin(parser);
this.materialsV0CompatPlugin = (_h = options == null ? void 0 : options.materialsV0CompatPlugin) != null ? _h : new VRMMaterialsV0CompatPlugin(parser);
this.springBonePlugin = (_i = options == null ? void 0 : options.springBonePlugin) != null ? _i : new VRMSpringBoneLoaderPlugin(parser, {
colliderHelperRoot: helperRoot,
jointHelperRoot: helperRoot
});
this.nodeConstraintPlugin = (_j = options == null ? void 0 : options.nodeConstraintPlugin) != null ? _j : new VRMNodeConstraintLoaderPlugin(parser, { helperRoot });
}
beforeRoot() {
return __async(this, null, function* () {
yield this.materialsV0CompatPlugin.beforeRoot();
yield this.mtoonMaterialPlugin.beforeRoot();
});
}
loadMesh(meshIndex) {
return __async(this, null, function* () {
return yield this.mtoonMaterialPlugin.loadMesh(meshIndex);
});
}
getMaterialType(materialIndex) {
const mtoonType = this.mtoonMaterialPlugin.getMaterialType(materialIndex);
if (mtoonType != null) return mtoonType;
return null;
}
extendMaterialParams(materialIndex, materialParams) {
return __async(this, null, function* () {
yield this.materialsHDREmissiveMultiplierPlugin.extendMaterialParams(materialIndex, materialParams);
yield this.mtoonMaterialPlugin.extendMaterialParams(materialIndex, materialParams);
});
}
afterRoot(gltf) {
return __async(this, null, function* () {
yield this.metaPlugin.afterRoot(gltf);
yield this.humanoidPlugin.afterRoot(gltf);
yield this.expressionPlugin.afterRoot(gltf);
yield this.lookAtPlugin.afterRoot(gltf);
yield this.firstPersonPlugin.afterRoot(gltf);
yield this.springBonePlugin.afterRoot(gltf);
yield this.nodeConstraintPlugin.afterRoot(gltf);
yield this.mtoonMaterialPlugin.afterRoot(gltf);
const meta = gltf.userData.vrmMeta;
const humanoid = gltf.userData.vrmHumanoid;
if (meta && humanoid) {
const vrm = new VRM({
scene: gltf.scene,
expressionManager: gltf.userData.vrmExpressionManager,
firstPerson: gltf.userData.vrmFirstPerson,
humanoid,
lookAt: gltf.userData.vrmLookAt,
meta,
materials: gltf.userData.vrmMToonMaterials,
springBoneManager: gltf.userData.vrmSpringBoneManager,
nodeConstraintManager: gltf.userData.vrmNodeConstraintManager
});
gltf.userData.vrm = vrm;
}
});
}
};
function collectMeshes(scene) {
const meshes = /* @__PURE__ */ new Set();
scene.traverse((obj) => {
if (!obj.isMesh) return;
const mesh = obj;
meshes.add(mesh);
});
return meshes;
}
function combineMorph(positionAttributes, binds, morphTargetsRelative) {
if (binds.size === 1) {
const bind = binds.values().next().value;
if (bind.weight === 1) return positionAttributes[bind.index];
}
const newArray = new Float32Array(positionAttributes[0].count * 3);
let weightSum = 0;
if (morphTargetsRelative) weightSum = 1;
else for (const bind of binds) weightSum += bind.weight;
for (const bind of binds) {
const src = positionAttributes[bind.index];
const weight = bind.weight / weightSum;
for (let i = 0; i < src.count; i++) {
newArray[i * 3 + 0] += src.getX(i) * weight;
newArray[i * 3 + 1] += src.getY(i) * weight;
newArray[i * 3 + 2] += src.getZ(i) * weight;
}
}
return new BufferAttribute(newArray, 3);
}
function combineMorphs(vrm) {
var _a;
const meshes = collectMeshes(vrm.scene);
const meshNameBindSetMapMap = /* @__PURE__ */ new Map();
const expressionMap = (_a = vrm.expressionManager) == null ? void 0 : _a.expressionMap;
if (expressionMap != null) for (const [expressionName, expression] of Object.entries(expressionMap)) {
const bindsToDeleteSet = /* @__PURE__ */ new Set();
for (const bind of expression.binds) if (bind instanceof VRMExpressionMorphTargetBind) {
if (bind.weight !== 0) for (const mesh of bind.primitives) {
let nameBindSetMap = meshNameBindSetMapMap.get(mesh);
if (nameBindSetMap == null) {
nameBindSetMap = /* @__PURE__ */ new Map();
meshNameBindSetMapMap.set(mesh, nameBindSetMap);
}
let bindSet = nameBindSetMap.get(expressionName);
if (bindSet == null) {
bindSet = /* @__PURE__ */ new Set();
nameBindSetMap.set(expressionName, bindSet);
}
bindSet.add(bind);
}
bindsToDeleteSet.add(bind);
}
for (const bind of bindsToDeleteSet) expression.deleteBind(bind);
}
for (const mesh of meshes) {
const nameBindSetMap = meshNameBindSetMapMap.get(mesh);
if (nameBindSetMap == null) continue;
const originalMorphAttributes = mesh.geometry.morphAttributes;
mesh.geometry.morphAttributes = {};
const geometry = mesh.geometry.clone();
mesh.geometry = geometry;
const morphTargetsRelative = geometry.morphTargetsRelative;
const hasPMorph = originalMorphAttributes.position != null;
const hasNMorph = originalMorphAttributes.normal != null;
const morphAttributes = {};
const morphTargetDictionary = {};
const morphTargetInfluences = [];
if (hasPMorph || hasNMorph) {
if (hasPMorph) morphAttributes.position = [];
if (hasNMorph) morphAttributes.normal = [];
let i = 0;
for (const [name, bindSet] of nameBindSetMap) {
if (hasPMorph) morphAttributes.position[i] = combineMorph(originalMorphAttributes.position, bindSet, morphTargetsRelative);
if (hasNMorph) morphAttributes.normal[i] = combineMorph(originalMorphAttributes.normal, bindSet, morphTargetsRelative);
expressionMap?.[name].addBind(new VRMExpressionMorphTargetBind({
index: i,
weight: 1,
primitives: [mesh]
}));
morphTargetDictionary[name] = i;
morphTargetInfluences.push(0);
i++;
}
}
geometry.morphAttributes = morphAttributes;
mesh.morphTargetDictionary = morphTargetDictionary;
mesh.morphTargetInfluences = morphTargetInfluences;
}
}
function attributeGetComponentCompat(attribute, index, component) {
if (attribute.getComponent) return attribute.getComponent(index, component);
else {
let value = attribute.array[index * attribute.itemSize + component];
if (attribute.normalized) value = MathUtils.denormalize(value, attribute.array);
return value;
}
}
function attributeSetComponentCompat(attribute, index, component, value) {
if (attribute.setComponent) attribute.setComponent(index, component, value);
else {
if (attribute.normalized) value = MathUtils.normalize(value, attribute.array);
attribute.array[index * attribute.itemSize + component] = value;
}
}
function combineSkeletons(root) {
var _a;
const skinnedMeshes = collectSkinnedMeshes(root);
const geometries = /* @__PURE__ */ new Set();
for (const mesh of skinnedMeshes) {
if (geometries.has(mesh.geometry)) mesh.geometry = shallowCloneBufferGeometry(mesh.geometry);
geometries.add(mesh.geometry);
}
const attributeUsedIndexSetMap = /* @__PURE__ */ new Map();
for (const geometry of geometries) {
const skinIndexAttr = geometry.getAttribute("skinIndex");
const skinIndexMap = (_a = attributeUsedIndexSetMap.get(skinIndexAttr)) != null ? _a : /* @__PURE__ */ new Map();
attributeUsedIndexSetMap.set(skinIndexAttr, skinIndexMap);
const skinWeightAttr = geometry.getAttribute("skinWeight");
const usedIndicesSet = listUsedIndices(skinIndexAttr, skinWeightAttr);
skinIndexMap.set(skinWeightAttr, usedIndicesSet);
}
const meshBoneInverseMapMap = /* @__PURE__ */ new Map();
for (const mesh of skinnedMeshes) {
const boneInverseMap = listUsedBones(mesh, attributeUsedIndexSetMap);
meshBoneInverseMapMap.set(mesh, boneInverseMap);
}
const groups = [];
for (const [mesh, boneInverseMap] of meshBoneInverseMapMap) {
let foundMergeableGroup = false;
for (const candidate of groups) if (boneInverseMapIsMergeable(boneInverseMap, candidate.boneInverseMap)) {
foundMergeableGroup = true;
candidate.meshes.add(mesh);
for (const [bone, boneInverse] of boneInverseMap) candidate.boneInverseMap.set(bone, boneInverse);
break;
}
if (!foundMergeableGroup) groups.push({
boneInverseMap,
meshes: /* @__PURE__ */ new Set([mesh])
});
}
const cache = /* @__PURE__ */ new Map();
const skinIndexDispatcher = new ObjectIndexDispatcher();
const skeletonDispatcher = new ObjectIndexDispatcher();
const boneDispatcher = new ObjectIndexDispatcher();
for (const group of groups) {
const { boneInverseMap, meshes } = group;
const newBones = Array.from(boneInverseMap.keys());
const newSkeleton = new Skeleton(newBones, Array.from(boneInverseMap.values()));
const skeletonKey = skeletonDispatcher.getOrCreate(newSkeleton);
for (const mesh of meshes) {
const skinIndexAttr = mesh.geometry.getAttribute("skinIndex");
const skinIndexKey = skinIndexDispatcher.getOrCreate(skinIndexAttr);
const bones = mesh.skeleton.bones;
const key = `${skinIndexKey};${skeletonKey};${bones.map((bone) => boneDispatcher.getOrCreate(bone)).join(",")}`;
let newSkinIndexAttr = cache.get(key);
if (newSkinIndexAttr == null) {
newSkinIndexAttr = skinIndexAttr.clone();
remapSkinIndexAttribute(newSkinIndexAttr, bones, newBones);
cache.set(key, newSkinIndexAttr);
}
mesh.geometry.setAttribute("skinIndex", newSkinIndexAttr);
}
for (const mesh of meshes) mesh.bind(newSkeleton, new Matrix4());
}
}
function collectSkinnedMeshes(scene) {
const skinnedMeshes = /* @__PURE__ */ new Set();
scene.traverse((obj) => {
if (!obj.isSkinnedMesh) return;
const skinnedMesh = obj;
skinnedMeshes.add(skinnedMesh);
});
return skinnedMeshes;
}
function listUsedIndices(skinIndexAttr, skinWeightAttr) {
const usedIndices = /* @__PURE__ */ new Set();
for (let i = 0; i < skinIndexAttr.count; i++) for (let j = 0; j < skinIndexAttr.itemSize; j++) {
const index = attributeGetComponentCompat(skinIndexAttr, i, j);
if (attributeGetComponentCompat(skinWeightAttr, i, j) !== 0) usedIndices.add(index);
}
return usedIndices;
}
function listUsedBones(mesh, attributeUsedIndexSetMap) {
const boneInverseMap = /* @__PURE__ */ new Map();
const skeleton = mesh.skeleton;
const geometry = mesh.geometry;
const skinIndexAttr = geometry.getAttribute("skinIndex");
const skinWeightAttr = geometry.getAttribute("skinWeight");
const skinIndexMap = attributeUsedIndexSetMap.get(skinIndexAttr);
const usedIndicesSet = skinIndexMap == null ? void 0 : skinIndexMap.get(skinWeightAttr);
if (!usedIndicesSet) throw new Error("Unreachable. attributeUsedIndexSetMap does not know the skin index attribute or the skin weight attribute.");
for (const index of usedIndicesSet) boneInverseMap.set(skeleton.bones[index], skeleton.boneInverses[index]);
return boneInverseMap;
}
function boneInverseMapIsMergeable(toCheck, candidate) {
for (const [bone, boneInverse] of toCheck.entries()) {
const candidateBoneInverse = candidate.get(bone);
if (candidateBoneInverse != null) {
if (!matrixEquals(boneInverse, candidateBoneInverse)) return false;
}
}
return true;
}
function remapSkinIndexAttribute(attribute, oldBones, newBones) {
const boneOldIndexMap = /* @__PURE__ */ new Map();
for (const bone of oldBones) boneOldIndexMap.set(bone, boneOldIndexMap.size);
const oldToNew = /* @__PURE__ */ new Map();
for (const [i, bone] of newBones.entries()) {
const oldIndex = boneOldIndexMap.get(bone);
oldToNew.set(oldIndex, i);
}
for (let i = 0; i < attribute.count; i++) for (let j = 0; j < attribute.itemSize; j++) {
const oldIndex = attributeGetComponentCompat(attribute, i, j);
const newIndex = oldToNew.get(oldIndex);
attributeSetComponentCompat(attribute, i, j, newIndex);
}
attribute.needsUpdate = true;
}
function matrixEquals(a, b, tolerance) {
tolerance = tolerance || 1e-4;
if (a.elements.length != b.elements.length) return false;
for (let i = 0, il = a.elements.length; i < il; i++) if (Math.abs(a.elements[i] - b.elements[i]) > tolerance) return false;
return true;
}
var ObjectIndexDispatcher = class {
constructor() {
this._objectIndexMap = /* @__PURE__ */ new Map();
this._index = 0;
}
get(obj) {
return this._objectIndexMap.get(obj);
}
getOrCreate(obj) {
let index = this._objectIndexMap.get(obj);
if (index == null) {
index = this._index;
this._objectIndexMap.set(obj, index);
this._index++;
}
return index;
}
};
function shallowCloneBufferGeometry(geometry) {
var _a, _b, _c, _d;
const clone = new BufferGeometry();
clone.name = geometry.name;
clone.setIndex(geometry.index);
for (const [name, attribute] of Object.entries(geometry.attributes)) clone.setAttribute(name, attribute);
for (const [key, morphAttributes] of Object.entries(geometry.morphAttributes)) {
const attributeName = key;
clone.morphAttributes[attributeName] = morphAttributes.concat();
}
clone.morphTargetsRelative = geometry.morphTargetsRelative;
clone.groups = [];
for (const group of geometry.groups) clone.addGroup(group.start, group.count, group.materialIndex);
clone.boundingSphere = (_b = (_a = geometry.boundingSphere) == null ? void 0 : _a.clone()) != null ? _b : null;
clone.boundingBox = (_d = (_c = geometry.boundingBox) == null ? void 0 : _c.clone()) != null ? _d : null;
clone.drawRange.start = geometry.drawRange.start;
clone.drawRange.count = geometry.drawRange.count;
clone.userData = geometry.userData;
return clone;
}
function disposeMaterial(material) {
Object.values(material).forEach((value) => {
if (value == null ? void 0 : value.isTexture) value.dispose();
});
if (material.isShaderMaterial) {
const uniforms = material.uniforms;
if (uniforms) Object.values(uniforms).forEach((uniform) => {
const value = uniform.value;
if (value == null ? void 0 : value.isTexture) value.dispose();
});
}
material.dispose();
}
function dispose(object3D) {
const geometry = object3D.geometry;
if (geometry) geometry.dispose();
const skeleton = object3D.skeleton;
if (skeleton) skeleton.dispose();
const material = object3D.material;
if (material) {
if (Array.isArray(material)) material.forEach((material2) => disposeMaterial(material2));
else if (material) disposeMaterial(material);
}
}
function deepDispose(object3D) {
object3D.traverse(dispose);
}
function removeUnnecessaryJoints(root, options) {
var _a, _b;
console.warn("VRMUtils.removeUnnecessaryJoints: removeUnnecessaryJoints is deprecated. Use combineSkeletons instead. combineSkeletons contributes more to the performance improvement. This function will be removed in the next major version.");
const experimentalSameBoneCounts = (_a = options == null ? void 0 : options.experimentalSameBoneCounts) != null ? _a : false;
const skinnedMeshes = [];
root.traverse((obj) => {
if (obj.type !== "SkinnedMesh") return;
skinnedMeshes.push(obj);
});
const attributeToBoneIndexMapMap = /* @__PURE__ */ new Map();
let maxBones = 0;
for (const mesh of skinnedMeshes) {
const attribute = mesh.geometry.getAttribute("skinIndex");
if (attributeToBoneIndexMapMap.has(attribute)) continue;
const oldToNew = /* @__PURE__ */ new Map();
const newToOld = /* @__PURE__ */ new Map();
for (let i = 0; i < attribute.count; i++) for (let j = 0; j < attribute.itemSize; j++) {
const oldIndex = attributeGetComponentCompat(attribute, i, j);
let newIndex = oldToNew.get(oldIndex);
if (newIndex == null) {
newIndex = oldToNew.size;
oldToNew.set(oldIndex, newIndex);
newToOld.set(newIndex, oldIndex);
}
attributeSetComponentCompat(attribute, i, j, newIndex);
}
attribute.needsUpdate = true;
attributeToBoneIndexMapMap.set(attribute, newToOld);
maxBones = Math.max(maxBones, oldToNew.size);
}
for (const mesh of skinnedMeshes) {
const attribute = mesh.geometry.getAttribute("skinIndex");
const newToOld = attributeToBoneIndexMapMap.get(attribute);
const bones = [];
const boneInverses = [];
const nBones = experimentalSameBoneCounts ? maxBones : newToOld.size;
for (let newIndex = 0; newIndex < nBones; newIndex++) {
const oldIndex = (_b = newToOld.get(newIndex)) != null ? _b : 0;
bones.push(mesh.skeleton.bones[oldIndex]);
boneInverses.push(mesh.skeleton.boneInverses[oldIndex]);
}
const skeleton = new Skeleton(bones, boneInverses);
mesh.bind(skeleton, new Matrix4());
}
}
function removeUnnecessaryVertices(root) {
const geometryMap = /* @__PURE__ */ new Map();
root.traverse((obj) => {
var _a, _b, _c, _d;
if (!obj.isMesh) return;
const mesh = obj;
const geometry = mesh.geometry;
const originalIndex = geometry.index;
if (originalIndex == null) return;
const newGeometryAlreadyExisted = geometryMap.get(geometry);
if (newGeometryAlreadyExisted != null) {
mesh.geometry = newGeometryAlreadyExisted;
return;
}
const vertexCount = Object.values(geometry.attributes)[0].count;
const vertexInUse = new Array(vertexCount);
let verticesUsed = 0;
const originalIndexArray = originalIndex.array;
for (let i = 0; i < originalIndexArray.length; i++) {
const index = originalIndexArray[i];
if (!vertexInUse[index]) {
vertexInUse[index] = true;
verticesUsed++;
}
}
if (verticesUsed === vertexCount) return;
const originalIndexNewIndexMap = [];
const newIndexOriginalIndexMap = [];
let indexHead = 0;
for (let i = 0; i < vertexInUse.length; i++) if (vertexInUse[i]) {
const newIndex = indexHead++;
originalIndexNewIndexMap[i] = newIndex;
newIndexOriginalIndexMap[newIndex] = i;
}
const newGeometry = new BufferGeometry();
newGeometry.name = geometry.name;
newGeometry.morphTargetsRelative = geometry.morphTargetsRelative;
geometry.groups.forEach((group) => {
newGeometry.addGroup(group.start, group.count, group.materialIndex);
});
newGeometry.boundingBox = (_b = (_a = geometry.boundingBox) == null ? void 0 : _a.clone()) != null ? _b : null;
newGeometry.boundingSphere = (_d = (_c = geometry.boundingSphere) == null ? void 0 : _c.clone()) != null ? _d : null;
newGeometry.setDrawRange(geometry.drawRange.start, geometry.drawRange.count);
newGeometry.userData = geometry.userData;
geometryMap.set(geometry, newGeometry);
{
const originalIndexArray2 = originalIndex.array;
const newIndexArray = new originalIndexArray2.constructor(originalIndexArray2.length);
for (let i = 0; i < originalIndexArray2.length; i++) newIndexArray[i] = originalIndexNewIndexMap[originalIndexArray2[i]];
newGeometry.setIndex(new BufferAttribute(newIndexArray, 1, false));
}
Object.keys(geometry.attributes).forEach((attributeName) => {
const originalAttribute = geometry.attributes[attributeName];
if (originalAttribute.isInterleavedBufferAttribute) throw new Error("removeUnnecessaryVertices: InterleavedBufferAttribute is not supported");
const originalAttributeArray = originalAttribute.array;
const { itemSize, normalized } = originalAttribute;
const newAttributeArray = new originalAttributeArray.constructor(newIndexOriginalIndexMap.length * itemSize);
newIndexOriginalIndexMap.forEach((originalIndex2, i) => {
for (let j = 0; j < itemSize; j++) newAttributeArray[i * itemSize + j] = originalAttributeArray[originalIndex2 * itemSize + j];
});
newGeometry.setAttribute(attributeName, new BufferAttribute(newAttributeArray, itemSize, normalized));
});
let isNullMorph = true;
for (const [key, morphAttributes] of Object.entries(geometry.morphAttributes)) {
const attributeName = key;
newGeometry.morphAttributes[attributeName] = [];
for (let iMorph = 0; iMorph < morphAttributes.length; iMorph++) {
const originalAttribute = morphAttributes[iMorph];
if (originalAttribute.isInterleavedBufferAttribute) throw new Error("removeUnnecessaryVertices: InterleavedBufferAttribute is not supported");
const originalAttributeArray = originalAttribute.array;
const { itemSize, normalized } = originalAttribute;
const newAttributeArray = new originalAttributeArray.constructor(newIndexOriginalIndexMap.length * itemSize);
newIndexOriginalIndexMap.forEach((originalIndex2, i) => {
for (let j = 0; j < itemSize; j++) newAttributeArray[i * itemSize + j] = originalAttributeArray[originalIndex2 * itemSize + j];
});
isNullMorph = isNullMorph && newAttributeArray.every((v) => v === 0);
newGeometry.morphAttributes[attributeName][iMorph] = new BufferAttribute(newAttributeArray, itemSize, normalized);
}
}
if (isNullMorph) newGeometry.morphAttributes = {};
mesh.geometry = newGeometry;
});
Array.from(geometryMap.keys()).forEach((originalGeometry) => {
originalGeometry.dispose();
});
}
function rotateVRM0(vrm) {
var _a;
if (((_a = vrm.meta) == null ? void 0 : _a.metaVersion) === "0") vrm.scene.rotation.y = Math.PI;
}
var VRMUtils = class {
constructor() {}
};
VRMUtils.combineMorphs = combineMorphs;
VRMUtils.combineSkeletons = combineSkeletons;
VRMUtils.deepDispose = deepDispose;
VRMUtils.removeUnnecessaryJoints = removeUnnecessaryJoints;
VRMUtils.removeUnnecessaryVertices = removeUnnecessaryVertices;
VRMUtils.rotateVRM0 = rotateVRM0;
/*!
* @pixiv/three-vrm-core v3.4.1
* The implementation of core features of VRM, for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-core is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
/*!
* @pixiv/three-vrm-materials-mtoon v3.4.1
* MToon (toon material) module for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-materials-mtoon is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
/*!
* @pixiv/three-vrm-materials-hdr-emissive-multiplier v3.4.1
* Support VRMC_hdr_emissiveMultiplier for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-materials-hdr-emissive-multiplier is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
/*!
* @pixiv/three-vrm-materials-v0compat v3.4.1
* VRM0.0 materials compatibility layer plugin for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-materials-v0compat is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
/*!
* @pixiv/three-vrm-node-constraint v3.4.1
* Node constraint module for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-node-constraint is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
/*!
* @pixiv/three-vrm-springbone v3.4.1
* Spring bone module for @pixiv/three-vrm
*
* Copyright (c) 2019-2025 pixiv Inc.
* @pixiv/three-vrm-springbone is distributed under MIT License
* https://github.com/pixiv/three-vrm/blob/release/LICENSE
*/
//#endregion
export { MToonMaterial, MToonMaterialDebugMode, MToonMaterialLoaderPlugin, MToonMaterialOutlineWidthMode, VRM, VRMAimConstraint, VRMCore, VRMCoreLoaderPlugin, VRMExpression, VRMExpressionLoaderPlugin, VRMExpressionManager, VRMExpressionMaterialColorBind, VRMExpressionMaterialColorType, VRMExpressionMorphTargetBind, VRMExpressionOverrideType, VRMExpressionPresetName, VRMExpressionTextureTransformBind, VRMFirstPerson, VRMFirstPersonLoaderPlugin, VRMFirstPersonMeshAnnotationType, VRMHumanBoneList, VRMHumanBoneName, VRMHumanBoneParentMap, VRMHumanoid, VRMHumanoidHelper, VRMHumanoidLoaderPlugin, VRMLoaderPlugin, VRMLookAt, VRMLookAtBoneApplier, VRMLookAtExpressionApplier, VRMLookAtHelper, VRMLookAtLoaderPlugin, VRMLookAtRangeMap, VRMLookAtTypeName, VRMMetaLoaderPlugin, VRMNodeConstraint, VRMNodeConstraintHelper, VRMNodeConstraintLoaderPlugin, VRMNodeConstraintManager, VRMRequiredHumanBoneName, VRMRollConstraint, VRMRotationConstraint, VRMSpringBoneCollider, VRMSpringBoneColliderHelper, VRMSpringBoneColliderShape, VRMSpringBoneColliderShapeCapsule, VRMSpringBoneColliderShapePlane, VRMSpringBoneColliderShapeSphere, VRMSpringBoneJoint, VRMSpringBoneJointHelper, VRMSpringBoneLoaderPlugin, VRMSpringBoneManager, VRMUtils };
//# sourceMappingURL=@pixiv_three-vrm.js.map