Skip to content

Commit c0e7a95

Browse files
authored
Merge pull request #1553 from pixiv/improve-combinemorphs
Improve performance of combineMorphs
2 parents 81b6991 + 2dfda5c commit c0e7a95

File tree

1 file changed

+19
-7
lines changed

1 file changed

+19
-7
lines changed

packages/three-vrm/src/VRMUtils/combineMorphs.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,17 @@ function collectMeshes(scene: THREE.Group): Set<THREE.Mesh> {
2121

2222
function combineMorph(
2323
positionAttributes: (THREE.BufferAttribute | THREE.InterleavedBufferAttribute)[],
24-
binds: Iterable<VRMExpressionMorphTargetBind>,
24+
binds: Set<VRMExpressionMorphTargetBind>,
2525
morphTargetsRelative: boolean,
26-
): THREE.BufferAttribute {
26+
): THREE.BufferAttribute | THREE.InterleavedBufferAttribute {
27+
// if there is only one morph target and the weight is 1.0, we can use the original as-is
28+
if (binds.size === 1) {
29+
const bind = binds.values().next().value!;
30+
if (bind.weight === 1.0) {
31+
return positionAttributes[bind.index];
32+
}
33+
}
34+
2735
const newArray = new Float32Array(positionAttributes[0].count * 3);
2836
let weightSum = 0.0;
2937

@@ -108,14 +116,18 @@ export function combineMorphs(vrm: VRMCore): void {
108116
continue;
109117
}
110118

119+
// prevent cloning morph attributes
120+
const originalMorphAttributes = mesh.geometry.morphAttributes;
121+
mesh.geometry.morphAttributes = {};
122+
111123
const geometry = mesh.geometry.clone();
112124
mesh.geometry = geometry;
113125
const morphTargetsRelative = geometry.morphTargetsRelative;
114126

115-
const hasPMorph = geometry.morphAttributes.position != null;
116-
const hasNMorph = geometry.morphAttributes.normal != null;
127+
const hasPMorph = originalMorphAttributes.position != null;
128+
const hasNMorph = originalMorphAttributes.normal != null;
117129

118-
const morphAttributes: typeof geometry.morphAttributes = {};
130+
const morphAttributes: typeof originalMorphAttributes = {};
119131
const morphTargetDictionary: typeof mesh.morphTargetDictionary = {};
120132
const morphTargetInfluences: typeof mesh.morphTargetInfluences = [];
121133

@@ -130,10 +142,10 @@ export function combineMorphs(vrm: VRMCore): void {
130142
let i = 0;
131143
for (const [name, bindSet] of nameBindSetMap) {
132144
if (hasPMorph) {
133-
morphAttributes.position[i] = combineMorph(geometry.morphAttributes.position, bindSet, morphTargetsRelative);
145+
morphAttributes.position[i] = combineMorph(originalMorphAttributes.position, bindSet, morphTargetsRelative);
134146
}
135147
if (hasNMorph) {
136-
morphAttributes.normal[i] = combineMorph(geometry.morphAttributes.normal, bindSet, morphTargetsRelative);
148+
morphAttributes.normal[i] = combineMorph(originalMorphAttributes.normal, bindSet, morphTargetsRelative);
137149
}
138150

139151
expressionMap?.[name].addBind(

0 commit comments

Comments
 (0)