Skip to content

Commit 54e11d4

Browse files
author
FMS_Cat
committed
Merge branch 'dev' into master
2 parents 6a5d4dc + 2f464b2 commit 54e11d4

29 files changed

+886
-556
lines changed

examples/meta.html

+14
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@
1919
position: absolute;
2020
background: #fff;
2121
}
22+
#thumbnail {
23+
position: absolute;
24+
top: 0;
25+
right: 0;
26+
}
2227
</style>
2328
</head>
2429

2530
<body>
2631
<span id="meta"></span>
32+
<img id="thumbnail" alt="thumbnail" />
2733
<script src="https://unpkg.com/three@0.118.3/build/three.js"></script>
2834
<script src="https://unpkg.com/three@0.118.3/examples/js/loaders/GLTFLoader.js"></script>
2935
<script src="https://unpkg.com/three@0.118.3/examples/js/controls/OrbitControls.js"></script>
@@ -81,6 +87,14 @@
8187

8288
} );
8389

90+
// show thumbnail
91+
THREE.VRMUtils.extractThumbnailBlob( renderer, vrm, 256 ).then( ( blob ) => {
92+
93+
const url = URL.createObjectURL( blob );
94+
document.getElementById( 'thumbnail' ).src = url;
95+
96+
} );
97+
8498
} );
8599

86100
},

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@
7070
"eslint-plugin-prettier": "^3.1.0",
7171
"fork-ts-checker-webpack-plugin": "^4.1.4",
7272
"gh-pages": "^3.1.0",
73-
"husky": "^3.0.5",
74-
"lint-staged": "10.0.8",
73+
"husky": "^4.3.0",
74+
"lint-staged": "10.3.0",
7575
"prettier": "^1.18.2",
7676
"quicktype": "^15.0.199",
7777
"raw-loader": "^4.0.1",

src/vrm/VRM.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { VRMBlendShapeProxy } from './blendshape';
44
import { VRMFirstPerson } from './firstperson';
55
import { VRMHumanoid } from './humanoid';
66
import { VRMLookAtHead } from './lookat';
7+
import { VRMMeta } from './meta/VRMMeta';
78
import { VRMSpringBoneManager } from './springbone';
8-
import { VRMSchema } from './types';
99
import { deepDispose } from './utils/disposer';
1010
import { VRMImporter, VRMImporterOptions } from './VRMImporter';
1111

@@ -20,7 +20,7 @@ export interface VRMParameters {
2020
lookAt?: VRMLookAtHead;
2121
materials?: THREE.Material[];
2222
springBoneManager?: VRMSpringBoneManager;
23-
meta?: VRMSchema.Meta;
23+
meta?: VRMMeta;
2424
}
2525

2626
/**
@@ -95,7 +95,7 @@ export class VRM {
9595
* Contains meta fields of the VRM.
9696
* You might want to refer these license fields before use your VRMs.
9797
*/
98-
public readonly meta?: VRMSchema.Meta;
98+
public readonly meta?: VRMMeta;
9999

100100
/**
101101
* A [[VRMSpringBoneManager]] manipulates all spring bones attached on the VRM.
@@ -156,5 +156,7 @@ export class VRM {
156156
if (scene) {
157157
deepDispose(scene);
158158
}
159+
160+
this.meta?.texture?.dispose();
159161
}
160162
}

src/vrm/VRMImporter.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import { VRMFirstPersonImporter } from './firstperson';
44
import { VRMHumanoidImporter } from './humanoid/VRMHumanoidImporter';
55
import { VRMLookAtImporter } from './lookat/VRMLookAtImporter';
66
import { VRMMaterialImporter } from './material';
7+
import { VRMMetaImporter } from './meta/VRMMetaImporter';
78
import { VRMSpringBoneImporter } from './springbone/VRMSpringBoneImporter';
8-
import { VRMSchema } from './types';
99
import { VRM } from './VRM';
1010

1111
export interface VRMImporterOptions {
12+
metaImporter?: VRMMetaImporter;
1213
lookAtImporter?: VRMLookAtImporter;
1314
humanoidImporter?: VRMHumanoidImporter;
1415
blendShapeImporter?: VRMBlendShapeImporter;
@@ -21,6 +22,7 @@ export interface VRMImporterOptions {
2122
* An importer that imports a [[VRM]] from a VRM extension of a GLTF.
2223
*/
2324
export class VRMImporter {
25+
protected readonly _metaImporter: VRMMetaImporter;
2426
protected readonly _blendShapeImporter: VRMBlendShapeImporter;
2527
protected readonly _lookAtImporter: VRMLookAtImporter;
2628
protected readonly _humanoidImporter: VRMHumanoidImporter;
@@ -34,6 +36,7 @@ export class VRMImporter {
3436
* @param options [[VRMImporterOptions]], optionally contains importers for each component
3537
*/
3638
public constructor(options: VRMImporterOptions = {}) {
39+
this._metaImporter = options.metaImporter || new VRMMetaImporter();
3740
this._blendShapeImporter = options.blendShapeImporter || new VRMBlendShapeImporter();
3841
this._lookAtImporter = options.lookAtImporter || new VRMLookAtImporter();
3942
this._humanoidImporter = options.humanoidImporter || new VRMHumanoidImporter();
@@ -51,8 +54,6 @@ export class VRMImporter {
5154
if (gltf.parser.json.extensions === undefined || gltf.parser.json.extensions.VRM === undefined) {
5255
throw new Error('Could not find VRM extension on the GLTF');
5356
}
54-
const vrmExt: VRMSchema.VRM = gltf.parser.json.extensions.VRM;
55-
5657
const scene = gltf.scene;
5758

5859
scene.updateMatrixWorld(false);
@@ -65,6 +66,8 @@ export class VRMImporter {
6566
}
6667
});
6768

69+
const meta = (await this._metaImporter.import(gltf)) || undefined;
70+
6871
const materials = (await this._materialImporter.convertGLTFMaterials(gltf)) || undefined;
6972

7073
const humanoid = (await this._humanoidImporter.import(gltf)) || undefined;
@@ -82,7 +85,7 @@ export class VRMImporter {
8285

8386
return new VRM({
8487
scene: gltf.scene,
85-
meta: vrmExt.meta,
88+
meta,
8689
materials,
8790
humanoid,
8891
firstPerson,
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as THREE from 'three';
2+
import { VRM } from '../VRM';
3+
4+
const _v2A = new THREE.Vector2();
5+
6+
const _camera = new THREE.OrthographicCamera(-1, 1, -1, 1, -1, 1);
7+
const _plane = new THREE.Mesh(
8+
new THREE.PlaneBufferGeometry(2, 2),
9+
new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide }),
10+
);
11+
const _scene = new THREE.Scene();
12+
_scene.add(_plane);
13+
14+
/**
15+
* Extract a thumbnail image blob from a {@link VRM}.
16+
* If the vrm does not have a thumbnail, it will throw an error.
17+
* @param renderer Renderer
18+
* @param vrm VRM with a thumbnail
19+
* @param size width / height of the image
20+
*/
21+
export function extractThumbnailBlob(renderer: THREE.WebGLRenderer, vrm: VRM, size = 512): Promise<Blob> {
22+
// get the texture
23+
const texture = vrm.meta?.texture;
24+
if (!texture) {
25+
throw new Error('extractThumbnailBlob: This VRM does not have a thumbnail');
26+
}
27+
28+
// store the current resolution
29+
renderer.getSize(_v2A);
30+
const prevWidth = _v2A.x;
31+
const prevHeight = _v2A.y;
32+
33+
// overwrite the resolution
34+
renderer.setSize(size, size);
35+
36+
// assign the texture to plane
37+
_plane.material.map = texture;
38+
39+
// render
40+
renderer.render(_scene, _camera);
41+
42+
// unassign the texture
43+
_plane.material.map = null;
44+
45+
// get blob
46+
return new Promise((resolve, reject) => {
47+
(renderer.getContext().canvas as HTMLCanvasElement).toBlob((blob) => {
48+
// revert to previous resolution
49+
renderer.setSize(prevWidth, prevHeight);
50+
51+
if (blob == null) {
52+
reject('extractThumbnailBlob: Failed to create a blob');
53+
} else {
54+
resolve(blob);
55+
}
56+
});
57+
});
58+
}

src/vrm/VRMUtils/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { extractThumbnailBlob } from './extractThumbnailBlob';
12
import { removeUnnecessaryJoints } from './removeUnnecessaryJoints';
23

34
export class VRMUtils {
45
private constructor() {
56
// this class is not meant to be instantiated
67
}
78

9+
public static extractThumbnailBlob = extractThumbnailBlob;
810
public static removeUnnecessaryJoints = removeUnnecessaryJoints;
911
}

src/vrm/blendshape/VRMBlendShapeImporter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class VRMBlendShapeImporter {
1515
* @param gltf A parsed result of GLTF taken from GLTFLoader
1616
*/
1717
public async import(gltf: GLTF): Promise<VRMBlendShapeProxy | null> {
18-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
18+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
1919
if (!vrmExt) {
2020
return null;
2121
}

src/vrm/blendshape/VRMBlendShapeProxy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class VRMBlendShapeProxy {
6666
*/
6767
public getValue(name: VRMSchema.BlendShapePresetName | string): number | null {
6868
const controller = this.getBlendShapeGroup(name);
69-
return (controller && controller.weight) || null;
69+
return controller?.weight ?? null;
7070
}
7171

7272
/**

src/vrm/debug/VRMLookAtImporterDebug.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export class VRMLookAtImporterDebug extends VRMLookAtImporter {
1414
blendShapeProxy: VRMBlendShapeProxy,
1515
humanoid: VRMHumanoid,
1616
): VRMLookAtHead | null {
17-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
17+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
1818
if (!vrmExt) {
1919
return null;
2020
}

src/vrm/debug/VRMSpringBoneDebug.ts

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import * as THREE from 'three';
22
import { VRMSpringBone } from '../springbone';
33
import { VRM_GIZMO_RENDER_ORDER } from './VRMDebug';
4+
import { VRMSpringBoneParameters } from '../springbone/VRMSpringBoneParameters';
45

56
const _v3A = new THREE.Vector3();
67

78
export class VRMSpringBoneDebug extends VRMSpringBone {
89
private _gizmo?: THREE.ArrowHelper;
910

10-
constructor(
11-
bone: THREE.Object3D,
12-
radius: number,
13-
stiffiness: number,
14-
gravityDir: THREE.Vector3,
15-
gravityPower: number,
16-
dragForce: number,
17-
colliders: THREE.Mesh[] = [],
18-
) {
19-
super(bone, radius, stiffiness, gravityDir, gravityPower, dragForce, colliders);
11+
constructor(bone: THREE.Object3D, params: VRMSpringBoneParameters) {
12+
super(bone, params);
2013
}
2114

2215
/**
@@ -29,12 +22,12 @@ export class VRMSpringBoneDebug extends VRMSpringBone {
2922
return this._gizmo;
3023
}
3124

32-
const nextTailRelative = _v3A.copy(this._nextTail).sub(this._worldPosition);
25+
const nextTailRelative = _v3A.copy(this._nextTail).sub(this._centerSpacePosition);
3326
const nextTailRelativeLength = nextTailRelative.length();
3427

3528
this._gizmo = new THREE.ArrowHelper(
3629
nextTailRelative.normalize(),
37-
this._worldPosition,
30+
this._centerSpacePosition,
3831
nextTailRelativeLength,
3932
0xffff00,
4033
this.radius,
@@ -63,11 +56,11 @@ export class VRMSpringBoneDebug extends VRMSpringBone {
6356
return;
6457
}
6558

66-
const nextTailRelative = _v3A.copy(this._currentTail).sub(this._worldPosition);
59+
const nextTailRelative = _v3A.copy(this._currentTail).sub(this._centerSpacePosition);
6760
const nextTailRelativeLength = nextTailRelative.length();
6861

6962
this._gizmo.setDirection(nextTailRelative.normalize());
7063
this._gizmo.setLength(nextTailRelativeLength, this.radius, this.radius);
71-
this._gizmo.position.copy(this._worldPosition);
64+
this._gizmo.position.copy(this._centerSpacePosition);
7265
}
7366
}

src/vrm/debug/VRMSpringBoneImporterDebug.ts

+4-11
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { VRMSpringBoneImporter } from '../springbone/VRMSpringBoneImporter';
44
import { VRMSpringBoneManagerDebug } from './VRMSpringBoneManagerDebug';
55
import { VRMSchema } from '../types';
66
import { VRMSpringBoneDebug } from './VRMSpringBoneDebug';
7+
import { VRMSpringBoneParameters } from '../springbone/VRMSpringBoneParameters';
78

89
export class VRMSpringBoneImporterDebug extends VRMSpringBoneImporter {
910
public async import(gltf: GLTF): Promise<VRMSpringBoneManagerDebug | null> {
10-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
11+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
1112
if (!vrmExt) return null;
1213

1314
const schemaSecondaryAnimation: VRMSchema.SecondaryAnimation | undefined = vrmExt.secondaryAnimation;
@@ -23,15 +24,7 @@ export class VRMSpringBoneImporterDebug extends VRMSpringBoneImporter {
2324
return new VRMSpringBoneManagerDebug(colliderGroups, springBoneGroupList);
2425
}
2526

26-
protected _createSpringBone(
27-
bone: THREE.Object3D,
28-
hitRadius: number,
29-
stiffiness: number,
30-
gravityDir: THREE.Vector3,
31-
gravityPower: number,
32-
dragForce: number,
33-
colliders: THREE.Mesh[] = [],
34-
): VRMSpringBoneDebug {
35-
return new VRMSpringBoneDebug(bone, hitRadius, stiffiness, gravityDir, gravityPower, dragForce, colliders);
27+
protected _createSpringBone(bone: THREE.Object3D, params: VRMSpringBoneParameters): VRMSpringBoneDebug {
28+
return new VRMSpringBoneDebug(bone, params);
3629
}
3730
}

src/vrm/firstperson/VRMFirstPersonImporter.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class VRMFirstPersonImporter {
1515
* @param humanoid A [[VRMHumanoid]] instance that represents the VRM
1616
*/
1717
public async import(gltf: GLTF, humanoid: VRMHumanoid): Promise<VRMFirstPerson | null> {
18-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
18+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
1919
if (!vrmExt) {
2020
return null;
2121
}
@@ -53,7 +53,7 @@ export class VRMFirstPersonImporter {
5353
const flag = schemaFirstPerson.meshAnnotations
5454
? schemaFirstPerson.meshAnnotations.find((a) => a.mesh === meshIndex)
5555
: undefined;
56-
meshAnnotations.push(new VRMRendererFirstPersonFlags(flag && flag.firstPersonFlag, mesh));
56+
meshAnnotations.push(new VRMRendererFirstPersonFlags(flag?.firstPersonFlag, mesh));
5757
});
5858

5959
return new VRMFirstPerson(firstPersonBone, firstPersonBoneOffset, meshAnnotations);

src/vrm/humanoid/VRMHumanoid.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class VRMHumanoid {
127127
* @param name Name of the bone you want
128128
*/
129129
public getBoneNode(name: VRMSchema.HumanoidBoneName): GLTFNode | null {
130-
return (this.humanBones[name][0] && this.humanBones[name][0].node) || null;
130+
return this.humanBones[name][0]?.node ?? null;
131131
}
132132

133133
/**

src/vrm/humanoid/VRMHumanoidImporter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class VRMHumanoidImporter {
1616
* @param gltf A parsed result of GLTF taken from GLTFLoader
1717
*/
1818
public async import(gltf: GLTF): Promise<VRMHumanoid | null> {
19-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
19+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
2020
if (!vrmExt) {
2121
return null;
2222
}

src/vrm/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export * from './lookat';
99
export * from './springbone';
1010
export * from './types';
1111
export * from './material';
12+
export * from './meta';

src/vrm/lookat/VRMLookAtImporter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class VRMLookAtImporter {
3131
blendShapeProxy: VRMBlendShapeProxy,
3232
humanoid: VRMHumanoid,
3333
): VRMLookAtHead | null {
34-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
34+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
3535
if (!vrmExt) {
3636
return null;
3737
}

src/vrm/material/VRMMaterialImporter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class VRMMaterialImporter {
5656
* @param gltf A parsed result of GLTF taken from GLTFLoader
5757
*/
5858
public async convertGLTFMaterials(gltf: GLTF): Promise<THREE.Material[] | null> {
59-
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions && gltf.parser.json.extensions.VRM;
59+
const vrmExt: VRMSchema.VRM | undefined = gltf.parser.json.extensions?.VRM;
6060
if (!vrmExt) {
6161
return null;
6262
}

0 commit comments

Comments
 (0)