Ai_Assistant/client/node_modules/.vite/deps/@pixiv_three-vrm.js
2026-05-24 13:31:30 +02:00

5844 lines
248 KiB
JavaScript

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 in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in MToonMaterial material, const in float shadow, inout ReflectedLight reflectedLight ) {\n float dotNL = clamp( dot( geometryNormal, directLight.direction ), -1.0, 1.0 );\n vec3 irradiance = directLight.color;\n\n // directSpecular will be used for rim lighting, not an actual specular\n reflectedLight.directSpecular += irradiance;\n\n irradiance *= dotNL;\n\n float shading = getShading( dotNL, shadow, material.shadingShift );\n\n // toon shaded diffuse\n reflectedLight.directDiffuse += getDiffuse( material, shading, directLight.color );\n }\n\n void RE_IndirectDiffuse_MToon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in MToonMaterial material, inout ReflectedLight reflectedLight ) {\n // indirect diffuse will use diffuseColor, no shadeColor involved\n reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\n // directSpecular will be used for rim lighting, not an actual specular\n reflectedLight.directSpecular += irradiance;\n }\n#else\n void RE_Direct_MToon( const in IncidentLight directLight, const in GeometricContext geometry, const in MToonMaterial material, const in float shadow, inout ReflectedLight reflectedLight ) {\n float dotNL = clamp( dot( geometry.normal, directLight.direction ), -1.0, 1.0 );\n vec3 irradiance = directLight.color;\n\n // directSpecular will be used for rim lighting, not an actual specular\n reflectedLight.directSpecular += irradiance;\n\n irradiance *= dotNL;\n\n float shading = getShading( dotNL, shadow, material.shadingShift );\n\n // toon shaded diffuse\n reflectedLight.directDiffuse += getDiffuse( material, shading, directLight.color );\n }\n\n void RE_IndirectDiffuse_MToon( const in vec3 irradiance, const in GeometricContext geometry, const in MToonMaterial material, inout ReflectedLight reflectedLight ) {\n // indirect diffuse will use diffuseColor, no shadeColor involved\n reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\n // directSpecular will be used for rim lighting, not an actual specular\n reflectedLight.directSpecular += irradiance;\n }\n#endif\n\n#define RE_Direct RE_Direct_MToon\n#define RE_IndirectDiffuse RE_IndirectDiffuse_MToon\n#define Material_LightProbeLOD( material ) (0)\n\n#include <shadowmap_pars_fragment>\n// #include <bumpmap_pars_fragment>\n\n// #include <normalmap_pars_fragment>\n#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform mat3 normalMapUvTransform;\n uniform vec2 normalScale;\n\n#endif\n\n// COMPAT: pre-r151\n// USE_NORMALMAP_OBJECTSPACE used to be OBJECTSPACE_NORMALMAP in pre-r151\n#if defined( USE_NORMALMAP_OBJECTSPACE ) || defined( OBJECTSPACE_NORMALMAP )\n\n uniform mat3 normalMatrix;\n\n#endif\n\n// COMPAT: pre-r151\n// USE_NORMALMAP_TANGENTSPACE used to be TANGENTSPACE_NORMALMAP in pre-r151\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( TANGENTSPACE_NORMALMAP ) )\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n // three-vrm specific change: it requires `uv` as an input in order to support uv scrolls\n\n // Temporary compat against shader change @ Three.js r126, r151\n #if THREE_VRM_THREE_REVISION >= 151\n\n mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( uv.st );\n vec2 st1 = dFdy( uv.st );\n\n vec3 N = surf_norm;\n\n vec3 q1perp = cross( q1, N );\n vec3 q0perp = cross( N, q0 );\n\n vec3 T = q1perp * st0.x + q0perp * st1.x;\n vec3 B = q1perp * st0.y + q0perp * st1.y;\n\n float det = max( dot( T, T ), dot( B, B ) );\n float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\n return mat3( T * scale, B * scale, N );\n\n }\n\n #else\n\n vec3 perturbNormal2Arb( vec2 uv, vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\n vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n vec2 st0 = dFdx( uv.st );\n vec2 st1 = dFdy( uv.st );\n\n vec3 N = normalize( surf_norm );\n\n vec3 q1perp = cross( q1, N );\n vec3 q0perp = cross( N, q0 );\n\n vec3 T = q1perp * st0.x + q0perp * st1.x;\n vec3 B = q1perp * st0.y + q0perp * st1.y;\n\n // three-vrm specific change: Workaround for the issue that happens when delta of uv = 0.0\n // TODO: Is this still required? Or shall I make a PR about it?\n if ( length( T ) == 0.0 || length( B ) == 0.0 ) {\n return surf_norm;\n }\n\n float det = max( dot( T, T ), dot( B, B ) );\n float scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\n return normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\n }\n\n #endif\n\n#endif\n\n// #include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\n\n// == post correction ==========================================================\nvoid postCorrection() {\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n #include <fog_fragment>\n #include <premultiplied_alpha_fragment>\n #include <dithering_fragment>\n}\n\n// == main procedure ===========================================================\nvoid main() {\n #include <clipping_planes_fragment>\n\n vec2 uv = vec2(0.5, 0.5);\n\n #if ( defined( MTOON_USE_UV ) && !defined( MTOON_UVS_VERTEX_ONLY ) )\n uv = vUv;\n\n float uvAnimMask = 1.0;\n #ifdef USE_UVANIMATIONMASKTEXTURE\n vec2 uvAnimationMaskTextureUv = ( uvAnimationMaskTextureUvTransform * vec3( uv, 1 ) ).xy;\n uvAnimMask = texture2D( uvAnimationMaskTexture, uvAnimationMaskTextureUv ).b;\n #endif\n\n float uvRotCos = cos( uvAnimationRotationPhase * uvAnimMask );\n float uvRotSin = sin( uvAnimationRotationPhase * uvAnimMask );\n uv = mat2( uvRotCos, -uvRotSin, uvRotSin, uvRotCos ) * ( uv - 0.5 ) + 0.5;\n uv = uv + vec2( uvAnimationScrollXOffset, uvAnimationScrollYOffset ) * uvAnimMask;\n #endif\n\n #ifdef DEBUG_UV\n gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n #if ( defined( MTOON_USE_UV ) && !defined( MTOON_UVS_VERTEX_ONLY ) )\n gl_FragColor = vec4( uv, 0.0, 1.0 );\n #endif\n return;\n #endif\n\n vec4 diffuseColor = vec4( litFactor, opacity );\n ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n vec3 totalEmissiveRadiance = emissive * emissiveIntensity;\n\n #include <logdepthbuf_fragment>\n\n // #include <map_fragment>\n #ifdef USE_MAP\n vec2 mapUv = ( mapUvTransform * vec3( uv, 1 ) ).xy;\n vec4 sampledDiffuseColor = texture2D( map, mapUv );\n #ifdef DECODE_VIDEO_TEXTURE\n sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n #endif\n diffuseColor *= sampledDiffuseColor;\n #endif\n\n // #include <color_fragment>\n #if ( defined( USE_COLOR ) && !defined( IGNORE_VERTEX_COLOR ) )\n diffuseColor.rgb *= vColor;\n #endif\n\n // #include <alphamap_fragment>\n\n #include <alphatest_fragment>\n\n // #include <specularmap_fragment>\n\n // #include <normal_fragment_begin>\n float faceDirection = gl_FrontFacing ? 1.0 : -1.0;\n\n #ifdef FLAT_SHADED\n\n vec3 fdx = dFdx( vViewPosition );\n vec3 fdy = dFdy( vViewPosition );\n vec3 normal = normalize( cross( fdx, fdy ) );\n\n #else\n\n vec3 normal = normalize( vNormal );\n\n #ifdef DOUBLE_SIDED\n\n normal *= faceDirection;\n\n #endif\n\n #endif\n\n #ifdef USE_NORMALMAP\n\n vec2 normalMapUv = ( normalMapUvTransform * vec3( uv, 1 ) ).xy;\n\n #endif\n\n #ifdef USE_NORMALMAP_TANGENTSPACE\n\n #ifdef USE_TANGENT\n\n mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\n #else\n\n mat3 tbn = getTangentFrame( - vViewPosition, normal, normalMapUv );\n\n #endif\n\n #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\n tbn[0] *= faceDirection;\n tbn[1] *= faceDirection;\n\n #endif\n\n #endif\n\n #ifdef USE_CLEARCOAT_NORMALMAP\n\n #ifdef USE_TANGENT\n\n mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\n #else\n\n mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\n #endif\n\n #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\n tbn2[0] *= faceDirection;\n tbn2[1] *= faceDirection;\n\n #endif\n\n #endif\n\n // non perturbed normal for clearcoat among others\n\n vec3 nonPerturbedNormal = normal;\n\n #ifdef OUTLINE\n normal *= -1.0;\n #endif\n\n // #include <normal_fragment_maps>\n\n // COMPAT: pre-r151\n // USE_NORMALMAP_OBJECTSPACE used to be OBJECTSPACE_NORMALMAP in pre-r151\n #if defined( USE_NORMALMAP_OBJECTSPACE ) || defined( OBJECTSPACE_NORMALMAP )\n\n normal = texture2D( normalMap, normalMapUv ).xyz * 2.0 - 1.0; // overrides both flatShading and attribute normals\n\n #ifdef FLIP_SIDED\n\n normal = - normal;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n\n normal = normal * faceDirection;\n\n #endif\n\n normal = normalize( normalMatrix * normal );\n\n // COMPAT: pre-r151\n // USE_NORMALMAP_TANGENTSPACE used to be TANGENTSPACE_NORMALMAP in pre-r151\n #elif defined( USE_NORMALMAP_TANGENTSPACE ) || defined( TANGENTSPACE_NORMALMAP )\n\n vec3 mapN = texture2D( normalMap, normalMapUv ).xyz * 2.0 - 1.0;\n mapN.xy *= normalScale;\n\n // COMPAT: pre-r151\n #if THREE_VRM_THREE_REVISION >= 151 || defined( USE_TANGENT )\n\n normal = normalize( tbn * mapN );\n\n #else\n\n normal = perturbNormal2Arb( uv, -vViewPosition, normal, mapN, faceDirection );\n\n #endif\n\n #endif\n\n // #include <emissivemap_fragment>\n #ifdef USE_EMISSIVEMAP\n vec2 emissiveMapUv = ( emissiveMapUvTransform * vec3( uv, 1 ) ).xy;\n totalEmissiveRadiance *= texture2D( emissiveMap, emissiveMapUv ).rgb;\n #endif\n\n #ifdef DEBUG_NORMAL\n gl_FragColor = vec4( 0.5 + 0.5 * normal, 1.0 );\n return;\n #endif\n\n // -- MToon: lighting --------------------------------------------------------\n // accumulation\n // #include <lights_phong_fragment>\n MToonMaterial material;\n\n material.diffuseColor = diffuseColor.rgb;\n\n material.shadeColor = shadeColorFactor;\n #ifdef USE_SHADEMULTIPLYTEXTURE\n vec2 shadeMultiplyTextureUv = ( shadeMultiplyTextureUvTransform * vec3( uv, 1 ) ).xy;\n material.shadeColor *= texture2D( shadeMultiplyTexture, shadeMultiplyTextureUv ).rgb;\n #endif\n\n #if ( defined( USE_COLOR ) && !defined( IGNORE_VERTEX_COLOR ) )\n material.shadeColor.rgb *= vColor;\n #endif\n\n material.shadingShift = shadingShiftFactor;\n #ifdef USE_SHADINGSHIFTTEXTURE\n vec2 shadingShiftTextureUv = ( shadingShiftTextureUvTransform * vec3( uv, 1 ) ).xy;\n material.shadingShift += texture2D( shadingShiftTexture, shadingShiftTextureUv ).r * shadingShiftTextureScale;\n #endif\n\n // #include <lights_fragment_begin>\n\n // MToon Specific changes:\n // Since we want to take shadows into account of shading instead of irradiance,\n // we had to modify the codes that multiplies the results of shadowmap into color of direct lights.\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n vec3 geometryPosition = - vViewPosition;\n vec3 geometryNormal = normal;\n vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n\n vec3 geometryClearcoatNormal;\n\n #ifdef USE_CLEARCOAT\n\n geometryClearcoatNormal = clearcoatNormal;\n\n #endif\n #else\n GeometricContext geometry;\n\n geometry.position = - vViewPosition;\n geometry.normal = normal;\n geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n\n #ifdef USE_CLEARCOAT\n\n geometry.clearcoatNormal = clearcoatNormal;\n\n #endif\n #endif\n\n IncidentLight directLight;\n\n // since these variables will be used in unrolled loop, we have to define in prior\n float shadow;\n\n #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\n PointLight pointLight;\n #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n PointLightShadow pointLightShadow;\n #endif\n\n #pragma unroll_loop_start\n for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\n pointLight = pointLights[ i ];\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n getPointLightInfo( pointLight, geometryPosition, directLight );\n #else\n getPointLightInfo( pointLight, geometry, directLight );\n #endif\n\n shadow = 1.0;\n #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n pointLightShadow = pointLightShadows[ i ];\n // COMPAT: pre-r166\n // r166 introduced shadowIntensity\n #if THREE_VRM_THREE_REVISION >= 166\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n #else\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n #endif\n #endif\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, shadow, reflectedLight );\n #else\n RE_Direct( directLight, geometry, material, shadow, reflectedLight );\n #endif\n\n }\n #pragma unroll_loop_end\n\n #endif\n\n #if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\n SpotLight spotLight;\n #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n SpotLightShadow spotLightShadow;\n #endif\n\n #pragma unroll_loop_start\n for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\n spotLight = spotLights[ i ];\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n getSpotLightInfo( spotLight, geometryPosition, directLight );\n #else\n getSpotLightInfo( spotLight, geometry, directLight );\n #endif\n\n shadow = 1.0;\n #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n spotLightShadow = spotLightShadows[ i ];\n // COMPAT: pre-r166\n // r166 introduced shadowIntensity\n #if THREE_VRM_THREE_REVISION >= 166\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n #else\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n #endif\n #endif\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, shadow, reflectedLight );\n #else\n RE_Direct( directLight, geometry, material, shadow, reflectedLight );\n #endif\n\n }\n #pragma unroll_loop_end\n\n #endif\n\n #if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\n DirectionalLight directionalLight;\n #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n DirectionalLightShadow directionalLightShadow;\n #endif\n\n #pragma unroll_loop_start\n for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\n directionalLight = directionalLights[ i ];\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n getDirectionalLightInfo( directionalLight, directLight );\n #else\n getDirectionalLightInfo( directionalLight, geometry, directLight );\n #endif\n\n shadow = 1.0;\n #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n directionalLightShadow = directionalLightShadows[ i ];\n // COMPAT: pre-r166\n // r166 introduced shadowIntensity\n #if THREE_VRM_THREE_REVISION >= 166\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n #else\n shadow = all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n #endif\n #endif\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, shadow, reflectedLight );\n #else\n RE_Direct( directLight, geometry, material, shadow, reflectedLight );\n #endif\n\n }\n #pragma unroll_loop_end\n\n #endif\n\n // #if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\n // RectAreaLight rectAreaLight;\n\n // #pragma unroll_loop_start\n // for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\n // rectAreaLight = rectAreaLights[ i ];\n // RE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\n // }\n // #pragma unroll_loop_end\n\n // #endif\n\n #if defined( RE_IndirectDiffuse )\n\n vec3 iblIrradiance = vec3( 0.0 );\n\n vec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n // COMPAT: pre-r156 doesn't have a define USE_LIGHT_PROBES\n #if THREE_VRM_THREE_REVISION >= 157\n #if defined( USE_LIGHT_PROBES )\n irradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n #endif\n #else\n irradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n #endif\n\n #if ( NUM_HEMI_LIGHTS > 0 )\n\n #pragma unroll_loop_start\n for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\n // COMPAT: pre-r156 uses a struct GeometricContext\n #if THREE_VRM_THREE_REVISION >= 157\n irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n #else\n irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n #endif\n\n }\n #pragma unroll_loop_end\n\n #endif\n\n #endif\n\n // #if defined( RE_IndirectSpecular )\n\n // vec3 radiance = vec3( 0.0 );\n // vec3 clearcoatRadiance = vec3( 0.0 );\n\n // #endif\n\n #include <lights_fragment_maps>\n #include <lights_fragment_end>\n\n // modulation\n #include <aomap_fragment>\n\n vec3 col = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\n #ifdef DEBUG_LITSHADERATE\n gl_FragColor = vec4( col, diffuseColor.a );\n postCorrection();\n return;\n #endif\n\n // -- MToon: rim lighting -----------------------------------------\n vec3 viewDir = normalize( vViewPosition );\n\n #ifndef PHYSICALLY_CORRECT_LIGHTS\n reflectedLight.directSpecular /= PI;\n #endif\n vec3 rimMix = mix( vec3( 1.0 ), reflectedLight.directSpecular, 1.0 );\n\n vec3 rim = parametricRimColorFactor * pow( saturate( 1.0 - dot( viewDir, normal ) + parametricRimLiftFactor ), parametricRimFresnelPowerFactor );\n\n #ifdef USE_MATCAPTEXTURE\n {\n vec3 x = normalize( vec3( viewDir.z, 0.0, -viewDir.x ) );\n vec3 y = cross( viewDir, x ); // guaranteed to be normalized\n vec2 sphereUv = 0.5 + 0.5 * vec2( dot( x, normal ), -dot( y, normal ) );\n sphereUv = ( matcapTextureUvTransform * vec3( sphereUv, 1 ) ).xy;\n vec3 matcap = texture2D( matcapTexture, sphereUv ).rgb;\n rim += matcapFactor * matcap;\n }\n #endif\n\n #ifdef USE_RIMMULTIPLYTEXTURE\n vec2 rimMultiplyTextureUv = ( rimMultiplyTextureUvTransform * vec3( uv, 1 ) ).xy;\n rim *= texture2D( rimMultiplyTexture, rimMultiplyTextureUv ).rgb;\n #endif\n\n col += rimMix * rim;\n\n // -- MToon: Emission --------------------------------------------------------\n col += totalEmissiveRadiance;\n\n // #include <envmap_fragment>\n\n // -- Almost done! -----------------------------------------------------------\n #if defined( OUTLINE )\n col = outlineColorFactor.rgb * mix( vec3( 1.0 ), col, outlineLightingMixFactor );\n #endif\n\n #ifdef OPAQUE\n diffuseColor.a = 1.0;\n #endif\n\n gl_FragColor = vec4( col, diffuseColor.a );\n postCorrection();\n}\n";
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