metamaker-for-three 0.1.8-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.dev +1 -0
- package/.env.mlib +1 -0
- package/.gitlab-ci.yml +1 -0
- package/.prettierrc.js +50 -0
- package/README.md +207 -0
- package/babel.config.js +3 -0
- package/code.jpg +0 -0
- package/examples/example.ts +624 -0
- package/libs/metamaker-for-three.js +1 -0
- package/package.json +89 -0
- package/public/SSSLUT.png +0 -0
- package/public/f9d25cc22be065191dca0f2ac7b248fd.zip +0 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +31 -0
- package/public/models/gltf/xj/-43190.jpg +0 -0
- package/public/models/gltf/xj/-43240.jpg +0 -0
- package/public/models/gltf/xj/-43256.png +0 -0
- package/public/models/gltf/xj/-44804.jpg +0 -0
- package/public/models/gltf/xj/22344.jpg +0 -0
- package/public/models/gltf/xj/37430.jpg +0 -0
- package/public/models/gltf/xj/37432.jpg +0 -0
- package/public/models/gltf/xj/character.bin +0 -0
- package/public/models/gltf/xj/character.glb +0 -0
- package/public/models/gltf/xj/character.gltf +12110 -0
- package/public/models/gltf/xj/character.zip +0 -0
- package/src/assets/SSSLUT.png +0 -0
- package/src/assets/metacrypto.wasm +0 -0
- package/src/lib/core/index.ts +103 -0
- package/src/lib/core/utils/GLTFLoader.d.ts +319 -0
- package/src/lib/core/utils/GLTFLoader.js +3827 -0
- package/src/lib/core/utils/ResetMaterial.ts +264 -0
- package/src/lib/core/utils/convert.ts +124 -0
- package/src/lib/core/utils/downloadAnimation.ts +117 -0
- package/src/lib/core/utils/downloadData.ts +20 -0
- package/src/lib/core/utils/index.ts +59 -0
- package/src/lib/core/utils/metacrypto.js +49 -0
- package/src/lib/globals.d.ts +7 -0
- package/src/lib/index.ts +7 -0
- package/tsconfig.dist.json +7 -0
- package/tsconfig.json +33 -0
- package/types/core/index.d.ts +9 -0
- package/types/core/utils/GLTFLoader.d.ts +17 -0
- package/types/core/utils/ResetMaterial.d.ts +2 -0
- package/types/core/utils/convert.d.ts +13 -0
- package/types/core/utils/downloadAnimation.d.ts +10 -0
- package/types/core/utils/downloadData.d.ts +2 -0
- package/types/core/utils/index.d.ts +13 -0
- package/types/core/utils/metacrypto.d.ts +12 -0
- package/types/index.d.ts +5 -0
- package/vue.config.js +49 -0
- package/vue.config.lib.js +61 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/* eslint-disable*/
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
import SSSLUT from "@/assets/SSSLUT.png";
|
|
4
|
+
import { b64toBlob, splitb64 } from ".";
|
|
5
|
+
let splitb64Result = splitb64(SSSLUT);
|
|
6
|
+
let SSSLUTBlob = b64toBlob(splitb64Result.b64Data, splitb64Result.contentType);
|
|
7
|
+
let SSSLUTBlobURL = URL.createObjectURL(SSSLUTBlob);
|
|
8
|
+
function replaceAll(string, find, replace) {
|
|
9
|
+
return string.split(find).join(replace);
|
|
10
|
+
}
|
|
11
|
+
const meshphong_frag_head = THREE.ShaderChunk["meshphysical_frag"].slice(
|
|
12
|
+
0,
|
|
13
|
+
THREE.ShaderChunk["meshphysical_frag"].indexOf("void main() {")
|
|
14
|
+
);
|
|
15
|
+
const meshphong_frag_body = THREE.ShaderChunk["meshphysical_frag"].slice(
|
|
16
|
+
THREE.ShaderChunk["meshphysical_frag"].indexOf("void main() {")
|
|
17
|
+
);
|
|
18
|
+
const loader = new THREE.TextureLoader();
|
|
19
|
+
const _SSSLUTTexture = loader.load(SSSLUTBlobURL);
|
|
20
|
+
const SubsurfaceScatteringShader = {
|
|
21
|
+
uniforms: THREE.UniformsUtils.merge([
|
|
22
|
+
THREE.ShaderLib["standard"].uniforms,
|
|
23
|
+
{
|
|
24
|
+
_SSSLUT: {
|
|
25
|
+
value: _SSSLUTTexture,
|
|
26
|
+
},
|
|
27
|
+
_CurveFactor: {
|
|
28
|
+
value: 0.8,
|
|
29
|
+
},
|
|
30
|
+
_SSSFactor: {
|
|
31
|
+
value: 0.3,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
]),
|
|
35
|
+
vertexShader: ["#define USE_UV", THREE.ShaderChunk["meshphong_vert"]].join("\n"),
|
|
36
|
+
fragmentShader: [
|
|
37
|
+
meshphong_frag_head,
|
|
38
|
+
"uniform sampler2D _SSSLUT;",
|
|
39
|
+
"uniform float _CurveFactor;",
|
|
40
|
+
"uniform float _SSSFactor;",
|
|
41
|
+
"void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in GeometricContext geometry, const in PhysicalMaterial material,inout ReflectedLight reflectedLight) {",
|
|
42
|
+
"float dotNL = saturate( dot( geometry.normal, directLight.direction ) );",
|
|
43
|
+
"vec3 irradiance = dotNL * directLight.color;",
|
|
44
|
+
"reflectedLight.directDiffuse -= irradiance * BRDF_Lambert( material.diffuseColor )*_SSSFactor;",
|
|
45
|
+
" float NoL = dot(geometry.normal, directLight.direction);",
|
|
46
|
+
" vec4 diffuse =texture2D(_SSSLUT,vec2(NoL * 0.5 + 0.5,_CurveFactor));",
|
|
47
|
+
" reflectedLight.directDiffuse += diffuse.xyz * directLight.color* BRDF_Lambert( material.diffuseColor )*_SSSFactor;",
|
|
48
|
+
"}",
|
|
49
|
+
meshphong_frag_body.replace(
|
|
50
|
+
"#include <lights_fragment_begin>",
|
|
51
|
+
replaceAll(
|
|
52
|
+
THREE.ShaderChunk["lights_fragment_begin"],
|
|
53
|
+
"RE_Direct( directLight, geometry, material, reflectedLight );",
|
|
54
|
+
[
|
|
55
|
+
"RE_Direct( directLight, geometry, material, reflectedLight );",
|
|
56
|
+
"RE_Direct_Scattering(directLight, vUv, geometry, material,reflectedLight);",
|
|
57
|
+
].join("\n")
|
|
58
|
+
)
|
|
59
|
+
),
|
|
60
|
+
].join("\n"),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
export function resetPolygonOffset(model,camera)
|
|
68
|
+
{
|
|
69
|
+
//return;
|
|
70
|
+
model.traverse((n) => {
|
|
71
|
+
if (n.material != null ){
|
|
72
|
+
if(n.material.name.indexOf("Hair") >= 0) {
|
|
73
|
+
} else if (n.material.name.indexOf("DiffNormalPacked") >= 0||n.material.name.indexOf("Custom/Diff") >= 0) {
|
|
74
|
+
}else if (n.material.name.indexOf("head_sss") >= 0||n.material.name.indexOf("body_sss") >= 0 ){
|
|
75
|
+
} else if (n.material.name.indexOf("eye") >= 0||n.material.name.indexOf("Eye") >= 0 ||n.material.name.indexOf("yachi") >= 0||n.material.name.indexOf("Eye") >= 0 ){
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
{
|
|
79
|
+
console.log("XXXXXXXXXXXXXXXXXXXXXXX"+n.name+" "+n.material.name);
|
|
80
|
+
|
|
81
|
+
var m=n.material.clone();
|
|
82
|
+
m.polygonOffset=true;
|
|
83
|
+
|
|
84
|
+
m.polygonOffsetFactor = -1.0;
|
|
85
|
+
var p = model.position.clone().sub(camera.position);
|
|
86
|
+
p.y = 0;
|
|
87
|
+
console.log(p);
|
|
88
|
+
m.polygonOffsetUnits = -3000.0 / p.length();
|
|
89
|
+
n.material = m;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export function resetMaterial(model) {
|
|
95
|
+
const hairs: any[] = [];
|
|
96
|
+
const s=1.04;
|
|
97
|
+
model.traverse((n) => {
|
|
98
|
+
if (n.material != null) {
|
|
99
|
+
if (n.material.name.indexOf("Hair") >= 0) {
|
|
100
|
+
hairs.push(n);
|
|
101
|
+
n.scale.x=n.scale.x*s;
|
|
102
|
+
n.scale.z=n.scale.z*s;
|
|
103
|
+
} else if (
|
|
104
|
+
n.material.name.indexOf("DiffNormalPacked") >= 0 ||
|
|
105
|
+
n.material.name.indexOf("Custom/Diff") >= 0
|
|
106
|
+
) {
|
|
107
|
+
n.scale.x=n.scale.x*s;
|
|
108
|
+
n.scale.z=n.scale.z*s;
|
|
109
|
+
const m = new THREE.MeshBasicMaterial({
|
|
110
|
+
side: THREE.DoubleSide,
|
|
111
|
+
});
|
|
112
|
+
m.map = n.material.map;
|
|
113
|
+
m.name = n.material.name + "_resetMaterial_hat";
|
|
114
|
+
n.material = m;
|
|
115
|
+
} else {
|
|
116
|
+
// n.material.roughness=0.8;
|
|
117
|
+
}
|
|
118
|
+
resetSSSMaterial(n);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
hairs.forEach((n) => {
|
|
123
|
+
const materialFirstPass = new THREE.MeshBasicMaterial({
|
|
124
|
+
alphaTest: 0.99,
|
|
125
|
+
transparent: false,
|
|
126
|
+
side: THREE.DoubleSide,
|
|
127
|
+
});
|
|
128
|
+
const materialBackSide = new THREE.MeshBasicMaterial({
|
|
129
|
+
blending: THREE.NormalBlending,
|
|
130
|
+
blendEquation: THREE.AddEquation,
|
|
131
|
+
blendSrc: THREE.SrcAlphaFactor,
|
|
132
|
+
blendDst: THREE.OneMinusSrcAlphaFactor,
|
|
133
|
+
depthWrite: false,
|
|
134
|
+
depthTest: true,
|
|
135
|
+
transparent: true,
|
|
136
|
+
side: THREE.BackSide,
|
|
137
|
+
});
|
|
138
|
+
const materialFrontSide = new THREE.MeshBasicMaterial({
|
|
139
|
+
blending: THREE.NormalBlending,
|
|
140
|
+
blendEquation: THREE.AddEquation,
|
|
141
|
+
blendSrc: THREE.SrcAlphaFactor,
|
|
142
|
+
blendDst: THREE.OneMinusSrcAlphaFactor,
|
|
143
|
+
depthWrite: false,
|
|
144
|
+
depthTest: true,
|
|
145
|
+
transparent: true,
|
|
146
|
+
side: THREE.FrontSide,
|
|
147
|
+
});
|
|
148
|
+
materialFirstPass.map = n.material.map;
|
|
149
|
+
materialBackSide.map = n.material.map;
|
|
150
|
+
materialFrontSide.map = n.material.map;
|
|
151
|
+
materialFirstPass.name=n.material.name+"materialFirstPass";
|
|
152
|
+
materialBackSide.name=n.material.name+"materialBackSide";
|
|
153
|
+
materialFrontSide.name=n.material.name+"materialFrontSide";
|
|
154
|
+
let mesh = n;
|
|
155
|
+
let mesh2 = n.clone();
|
|
156
|
+
n.parent.add(mesh2);
|
|
157
|
+
let mesh3 = n.clone();
|
|
158
|
+
n.parent.add(mesh3);
|
|
159
|
+
mesh.material = materialFirstPass;
|
|
160
|
+
mesh2.material = materialBackSide;
|
|
161
|
+
mesh2.renderOrder = n.renderOrder + 1;
|
|
162
|
+
mesh3.material = materialFrontSide;
|
|
163
|
+
mesh3.renderOrder = n.renderOrder + 2;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function resetSSSMaterial(n) {
|
|
167
|
+
if (n.material.name.indexOf("head_sss") >= 0 || n.material.name.indexOf("body_sss") >= 0) {
|
|
168
|
+
const shader = SubsurfaceScatteringShader;
|
|
169
|
+
var material = new THREE.ShaderMaterial({
|
|
170
|
+
uniforms: THREE.UniformsUtils.clone(SubsurfaceScatteringShader.uniforms),
|
|
171
|
+
vertexShader: shader.vertexShader,
|
|
172
|
+
fragmentShader: shader.fragmentShader,
|
|
173
|
+
});
|
|
174
|
+
var source = n.material;
|
|
175
|
+
var m: any = material;
|
|
176
|
+
m.blending = source.blending;
|
|
177
|
+
m.side = source.side;
|
|
178
|
+
m.vertexColors = source.vertexColors;
|
|
179
|
+
m.opacity = source.opacity;
|
|
180
|
+
m.transparent = source.transparent;
|
|
181
|
+
m.blendSrc = source.blendSrc;
|
|
182
|
+
m.blendDst = source.blendDst;
|
|
183
|
+
m.blendEquation = source.blendEquation;
|
|
184
|
+
m.blendSrcAlpha = source.blendSrcAlpha;
|
|
185
|
+
m.blendDstAlpha = source.blendDstAlpha;
|
|
186
|
+
m.blendEquationAlpha = source.blendEquationAlpha;
|
|
187
|
+
m.depthFunc = source.depthFunc;
|
|
188
|
+
m.depthTest = source.depthTest;
|
|
189
|
+
m.depthWrite = source.depthWrite;
|
|
190
|
+
m.stencilWriteMask = source.stencilWriteMask;
|
|
191
|
+
m.stencilFunc = source.stencilFunc;
|
|
192
|
+
m.stencilRef = source.stencilRef;
|
|
193
|
+
m.stencilFuncMask = source.stencilFuncMask;
|
|
194
|
+
m.stencilFail = source.stencilFail;
|
|
195
|
+
m.stencilZFail = source.stencilZFail;
|
|
196
|
+
m.stencilZPass = source.stencilZPass;
|
|
197
|
+
m.stencilWrite = source.stencilWrite;
|
|
198
|
+
const srcPlanes = source.clippingPlanes;
|
|
199
|
+
let dstPlanes = null;
|
|
200
|
+
if (srcPlanes !== null) {
|
|
201
|
+
const n = srcPlanes.length;
|
|
202
|
+
dstPlanes = new Array(n);
|
|
203
|
+
|
|
204
|
+
for (let i = 0; i !== n; ++i) {
|
|
205
|
+
dstPlanes[i] = srcPlanes[i].clone();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
m.clippingPlanes = dstPlanes;
|
|
209
|
+
m.clipIntersection = source.clipIntersection;
|
|
210
|
+
m.clipShadows = source.clipShadows;
|
|
211
|
+
m.shadowSide = source.shadowSide;
|
|
212
|
+
m.colorWrite = source.colorWrite;
|
|
213
|
+
m.precision = source.precision;
|
|
214
|
+
m.polygonOffset = source.polygonOffset;
|
|
215
|
+
m.polygonOffsetFactor = source.polygonOffsetFactor;
|
|
216
|
+
m.polygonOffsetUnits = source.polygonOffsetUnits;
|
|
217
|
+
m.dithering = source.dithering;
|
|
218
|
+
m.alphaTest = source.alphaTest;
|
|
219
|
+
m.alphaToCoverage = source.alphaToCoverage;
|
|
220
|
+
m.premultipliedAlpha = source.premultipliedAlpha;
|
|
221
|
+
m.visible = source.visible;
|
|
222
|
+
m.toneMapped = source.toneMapped;
|
|
223
|
+
m.userData = JSON.parse(JSON.stringify(source.userData));
|
|
224
|
+
|
|
225
|
+
material.defines = { STANDARD: "" };
|
|
226
|
+
|
|
227
|
+
m.color = source.color.clone();
|
|
228
|
+
m.roughness = source.roughness;
|
|
229
|
+
m.metalness = source.metalness;
|
|
230
|
+
m.map = source.map;
|
|
231
|
+
m.lightMap = source.lightMap;
|
|
232
|
+
m.lightMapIntensity = source.lightMapIntensity;
|
|
233
|
+
m.aoMap = source.aoMap;
|
|
234
|
+
m.aoMapIntensity = source.aoMapIntensity;
|
|
235
|
+
m.emissive = source.emissive.clone();
|
|
236
|
+
m.emissiveMap = source.emissiveMap;
|
|
237
|
+
m.emissiveIntensity = source.emissiveIntensity;
|
|
238
|
+
m.bumpMap = source.bumpMap;
|
|
239
|
+
m.bumpScale = source.bumpScale;
|
|
240
|
+
m.normalMap = source.normalMap;
|
|
241
|
+
m.normalMapType = source.normalMapType;
|
|
242
|
+
m.normalScale = source.normalScale.clone();
|
|
243
|
+
m.displacementMap = source.displacementMap;
|
|
244
|
+
m.displacementScale = source.displacementScale;
|
|
245
|
+
m.displacementBias = source.displacementBias;
|
|
246
|
+
m.roughnessMap = source.roughnessMap;
|
|
247
|
+
m.metalnessMap = source.metalnessMap;
|
|
248
|
+
m.alphaMap = source.alphaMap;
|
|
249
|
+
m.envMap = source.envMap;
|
|
250
|
+
m.envMapIntensity = source.envMapIntensity;
|
|
251
|
+
m.wireframe = source.wireframe;
|
|
252
|
+
m.wireframeLinewidth = source.wireframeLinewidth;
|
|
253
|
+
m.wireframeLinecap = source.wireframeLinecap;
|
|
254
|
+
m.wireframeLinejoin = source.wireframeLinejoin;
|
|
255
|
+
m.flatShading = source.flatShading;
|
|
256
|
+
m.fog = source.fog;
|
|
257
|
+
m.isMeshStandardMaterial = true;
|
|
258
|
+
|
|
259
|
+
console.log(n.material);
|
|
260
|
+
material.name = n.material.name;
|
|
261
|
+
n.material = material;
|
|
262
|
+
console.log(n.material);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
let bodyMorphTargetDictionary = {};
|
|
4
|
+
let teethMorphTargetDictionary = {};
|
|
5
|
+
export let bodyMeshName;
|
|
6
|
+
export let Tooth_downMeshName;
|
|
7
|
+
export function setBodyMorphTargetDictionary(name, map) {
|
|
8
|
+
bodyMorphTargetDictionary = map;
|
|
9
|
+
console.log(bodyMorphTargetDictionary);
|
|
10
|
+
bodyMeshName = name;
|
|
11
|
+
}
|
|
12
|
+
export function setTeethMorphTargetDictionary(name, map) {
|
|
13
|
+
teethMorphTargetDictionary = map;
|
|
14
|
+
Tooth_downMeshName = name;
|
|
15
|
+
console.log(teethMorphTargetDictionary);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param { object } fp 动画文件json结构的描述
|
|
21
|
+
* @param {boolean} isEmotion 是否为表情类型的动画
|
|
22
|
+
* @returns { AnimationClip }
|
|
23
|
+
* @desc 通过将JSON结构的描述转化为 THREEJS 的AnimationClip
|
|
24
|
+
*/
|
|
25
|
+
export default function Convert(fp, isEmotion = false) {
|
|
26
|
+
// console.log(fp);
|
|
27
|
+
const kfs = new Array<THREE.KeyframeTrack>();
|
|
28
|
+
const arry = fp["CurveInfos"] as Array<JSON>;
|
|
29
|
+
for (let i = 0; i < arry.length; i++) {
|
|
30
|
+
const element = arry[i];
|
|
31
|
+
const str = element["PathKey"] as string;
|
|
32
|
+
const index = str.indexOf("Transform");
|
|
33
|
+
if (index >= 0) {
|
|
34
|
+
if (str.indexOf(".x") >= 0 && (!isEmotion || str.indexOf(".eye") >= 0)) {
|
|
35
|
+
const s = str.split(":");
|
|
36
|
+
const s2 = s[0].split("/");
|
|
37
|
+
const boneName = s2[s2.length - 1];
|
|
38
|
+
let trackName = boneName + ".";
|
|
39
|
+
if (str.indexOf("Position") >= 0) {
|
|
40
|
+
trackName = trackName + "position";
|
|
41
|
+
}
|
|
42
|
+
if (str.indexOf("Scale") >= 0) {
|
|
43
|
+
trackName = trackName + "scale";
|
|
44
|
+
}
|
|
45
|
+
if (str.indexOf("Rotation") >= 0) {
|
|
46
|
+
trackName = trackName + "quaternion";
|
|
47
|
+
}
|
|
48
|
+
const keys = element["Keys"] as Array<JSON>;
|
|
49
|
+
const times = keys.map((k) => k["Time"] as number);
|
|
50
|
+
const xs = keys.map((k) => k["Value"] as number);
|
|
51
|
+
const ys = (arry[i + 1]["Keys"] as Array<JSON>).map((k) => k["Value"] as number);
|
|
52
|
+
const zs = (arry[i + 2]["Keys"] as Array<JSON>).map((k) => k["Value"] as number);
|
|
53
|
+
let vs = new Float32Array();
|
|
54
|
+
if (str.indexOf("Position") > 0) {
|
|
55
|
+
vs = new Float32Array(xs.length * 3);
|
|
56
|
+
for (var j = 0; j < xs.length; j++) {
|
|
57
|
+
vs[j * 3] = -xs[j];
|
|
58
|
+
vs[j * 3 + 1] = ys[j];
|
|
59
|
+
vs[j * 3 + 2] = zs[j];
|
|
60
|
+
}
|
|
61
|
+
var track = new THREE.KeyframeTrack(trackName, times, vs, THREE.InterpolateLinear);
|
|
62
|
+
} else if (str.indexOf("Scale") > 0) {
|
|
63
|
+
vs = new Float32Array(xs.length * 3);
|
|
64
|
+
for (var j = 0; j < xs.length; j++) {
|
|
65
|
+
vs[j * 3] = xs[j];
|
|
66
|
+
vs[j * 3 + 1] = ys[j];
|
|
67
|
+
vs[j * 3 + 2] = zs[j];
|
|
68
|
+
}
|
|
69
|
+
var track = new THREE.KeyframeTrack(trackName, times, vs, THREE.InterpolateLinear);
|
|
70
|
+
} else {
|
|
71
|
+
var ws = arry[i + 3]["Keys"].map((k) => k["Value"]);
|
|
72
|
+
var vs2 = [];
|
|
73
|
+
for (var j = 0; j < xs.length; j++) {
|
|
74
|
+
var q = new THREE.Quaternion(xs[j], ys[j], zs[j], ws[j]);
|
|
75
|
+
vs2[j * 4] = q.x;
|
|
76
|
+
vs2[j * 4 + 1] = -q.y;
|
|
77
|
+
vs2[j * 4 + 2] = -q.z;
|
|
78
|
+
vs2[j * 4 + 3] = q.w;
|
|
79
|
+
}
|
|
80
|
+
var track = new THREE.QuaternionKeyframeTrack(
|
|
81
|
+
trackName,
|
|
82
|
+
times,
|
|
83
|
+
vs2,
|
|
84
|
+
THREE.InterpolateLinear
|
|
85
|
+
);
|
|
86
|
+
track.ValueTypeName = "quaternion";
|
|
87
|
+
kfs.push(track);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else if (str.indexOf("Skinned") > 0) {
|
|
91
|
+
const s = str.split(":");
|
|
92
|
+
const s2 = s[0].split("/");
|
|
93
|
+
const boneName = s2[s2.length - 1];
|
|
94
|
+
if (boneName == "body") {
|
|
95
|
+
/////////////////////////////////liujun
|
|
96
|
+
const trackName =
|
|
97
|
+
bodyMeshName +
|
|
98
|
+
".morphTargetInfluences[" +
|
|
99
|
+
bodyMorphTargetDictionary[s[2].substring(11)] +
|
|
100
|
+
"]";
|
|
101
|
+
const keys = element["Keys"] as Array<JSON>;
|
|
102
|
+
const times = keys.map((k) => k["Time"] as number);
|
|
103
|
+
const values = keys.map((k) => ((k["Value"] as number) / 100) * 0.65);
|
|
104
|
+
const track = new THREE.KeyframeTrack(trackName, times, values);
|
|
105
|
+
kfs.push(track);
|
|
106
|
+
}
|
|
107
|
+
if (boneName == "tooth_down") {
|
|
108
|
+
const trackName =
|
|
109
|
+
Tooth_downMeshName +
|
|
110
|
+
".morphTargetInfluences[" +
|
|
111
|
+
teethMorphTargetDictionary[s[2].substring(11)] +
|
|
112
|
+
"]";
|
|
113
|
+
const keys = element["Keys"] as Array<JSON>;
|
|
114
|
+
const times = keys.map((k) => k["Time"] as number);
|
|
115
|
+
const values = keys.map((k) => ((k["Value"] as number) / 100) * 0.65);
|
|
116
|
+
const track = new THREE.KeyframeTrack(trackName, times, values);
|
|
117
|
+
kfs.push(track);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const ac = new THREE.AnimationClip(fp["name"], undefined, kfs, THREE.NormalAnimationBlendMode);
|
|
122
|
+
|
|
123
|
+
return ac;
|
|
124
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { downloadData } from "./downloadData";
|
|
3
|
+
import * as fflate from "fflate";
|
|
4
|
+
import { getSuffixName, largeUint8ArrayToString } from ".";
|
|
5
|
+
import cryptoModule from "./metacrypto.js";
|
|
6
|
+
export async function downloadAnimation(animationName, geometryName) {
|
|
7
|
+
let arraybuffer: ArrayBuffer;
|
|
8
|
+
// eslint-disable-next-line prefer-const
|
|
9
|
+
arraybuffer = (await downloadData(animationName, "arraybuffer")) as ArrayBuffer;
|
|
10
|
+
console.log(arraybuffer);
|
|
11
|
+
const dataView = new DataView(arraybuffer);
|
|
12
|
+
let offset = 0;
|
|
13
|
+
const nameLen = dataView.getInt32(offset, true);
|
|
14
|
+
offset += 4;
|
|
15
|
+
console.log(nameLen);
|
|
16
|
+
offset += nameLen;
|
|
17
|
+
const length = dataView.getFloat32(offset, true);
|
|
18
|
+
offset += 4;
|
|
19
|
+
console.log(length);
|
|
20
|
+
const num = dataView.getUint32(offset, true);
|
|
21
|
+
offset += 4;
|
|
22
|
+
console.log(num);
|
|
23
|
+
|
|
24
|
+
const dict = {};
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < num; i++) {
|
|
27
|
+
const time = dataView.getFloat32(offset, true);
|
|
28
|
+
offset += 4;
|
|
29
|
+
const posLen = dataView.getUint32(offset, true);
|
|
30
|
+
offset += 4;
|
|
31
|
+
const pos = [];
|
|
32
|
+
const mag = [];
|
|
33
|
+
for (let j = 0; j < posLen; j++) {
|
|
34
|
+
const posj = dataView.getUint16(offset, true);
|
|
35
|
+
offset += 2;
|
|
36
|
+
const magj = dataView.getFloat32(offset, true);
|
|
37
|
+
offset += 4;
|
|
38
|
+
if (dict[posj] == undefined) {
|
|
39
|
+
dict[posj] = {};
|
|
40
|
+
dict[posj].times = [];
|
|
41
|
+
dict[posj].values = [];
|
|
42
|
+
}
|
|
43
|
+
dict[posj].times.push(time);
|
|
44
|
+
dict[posj].values.push(magj * 0.65);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
console.log(dict);
|
|
48
|
+
const kfs = new Array<THREE.KeyframeTrack>();
|
|
49
|
+
for (const key in dict) {
|
|
50
|
+
const track = new THREE.KeyframeTrack(
|
|
51
|
+
geometryName + ".morphTargetInfluences[" + key + "]",
|
|
52
|
+
dict[key].times,
|
|
53
|
+
dict[key].values,
|
|
54
|
+
THREE.InterpolateLinear
|
|
55
|
+
);
|
|
56
|
+
kfs.push(track);
|
|
57
|
+
}
|
|
58
|
+
const ac = new THREE.AnimationClip(animationName, -1, kfs, THREE.NormalAnimationBlendMode);
|
|
59
|
+
return ac;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @param animateName 动画名称
|
|
65
|
+
* @param baseUrl 地址前缀
|
|
66
|
+
* @returns {Promise<object>}
|
|
67
|
+
* 通过动画名称加载动画的描述,得到的是JSON结构的数据
|
|
68
|
+
*/
|
|
69
|
+
export const loadAnimationData = async function (
|
|
70
|
+
animateName: string,
|
|
71
|
+
baseUrl = "//img.metaworks.cn/webgl/app"
|
|
72
|
+
): Promise<object> {
|
|
73
|
+
let url: string;
|
|
74
|
+
if (!animateName) {
|
|
75
|
+
return Promise.reject("没有对应的动画名称");
|
|
76
|
+
}
|
|
77
|
+
if (animateName.startsWith("http")) {
|
|
78
|
+
url = animateName;
|
|
79
|
+
} else {
|
|
80
|
+
url = `${baseUrl}/${animateName}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result = (await downloadData(url, "arraybuffer")) as ArrayBuffer;
|
|
84
|
+
const buffer = new Uint8Array(result) as Uint8Array;
|
|
85
|
+
let fileBuffer = await new Promise((resolve) => {
|
|
86
|
+
const unzipper = new fflate.Unzip();
|
|
87
|
+
unzipper.register(fflate.UnzipInflate);
|
|
88
|
+
unzipper.onfile = (file) => {
|
|
89
|
+
// file.name is a string, file is a stream
|
|
90
|
+
if (getSuffixName(file.name) == "json") {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
file.ondata = (err, dat, final) => {
|
|
94
|
+
// Stream output here
|
|
95
|
+
resolve(dat);
|
|
96
|
+
};
|
|
97
|
+
console.log("Reading:", file.name);
|
|
98
|
+
// File sizes are sometimes not set if the ZIP file did not encode
|
|
99
|
+
// them, so you may want to check that file.size != undefined
|
|
100
|
+
console.log("Compressed size", file.size);
|
|
101
|
+
console.log("Decompressed size", file.originalSize);
|
|
102
|
+
|
|
103
|
+
file.start();
|
|
104
|
+
};
|
|
105
|
+
unzipper.push(buffer, true);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
fileBuffer = new Uint8Array(fileBuffer as any);
|
|
109
|
+
|
|
110
|
+
let s = await largeUint8ArrayToString(fileBuffer);
|
|
111
|
+
if (s[0] != "{") {
|
|
112
|
+
const arraybuffer = await cryptoModule.decryptData(fileBuffer);
|
|
113
|
+
s = await largeUint8ArrayToString(arraybuffer);
|
|
114
|
+
}
|
|
115
|
+
const json = JSON.parse(s);
|
|
116
|
+
return json;
|
|
117
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const downloadData = function (url, type) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const xhr = new XMLHttpRequest();
|
|
4
|
+
xhr.responseType = type;
|
|
5
|
+
xhr.onreadystatechange = function () {
|
|
6
|
+
if (xhr.readyState == 4) {
|
|
7
|
+
const status = xhr.status;
|
|
8
|
+
if (status >= 200 && status < 300) {
|
|
9
|
+
resolve(xhr.response);
|
|
10
|
+
} else {
|
|
11
|
+
reject(status);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
xhr.open("GET", url, true);
|
|
16
|
+
xhr.send(null);
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { downloadData };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param { string } name 文件名称
|
|
4
|
+
* @returns { string } 后缀名
|
|
5
|
+
*/
|
|
6
|
+
export const getSuffixName = (name) => {
|
|
7
|
+
const splits = name.split(".");
|
|
8
|
+
return splits[splits.length - 1];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function Uint8ArrayToString(fileData) {
|
|
12
|
+
let dataString = "";
|
|
13
|
+
for (let i = 0; i < fileData.length; i++) {
|
|
14
|
+
dataString += String.fromCharCode(fileData[i]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return dataString;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function largeUint8ArrayToString(uint8arr): Promise<string> {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const blob = new Blob([uint8arr]);
|
|
23
|
+
const reader = new FileReader();
|
|
24
|
+
reader.onload = function (e) {
|
|
25
|
+
resolve(e.target.result as string);
|
|
26
|
+
};
|
|
27
|
+
reader.readAsText(blob);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const b64toBlob = (b64Data, contentType = "", sliceSize = 512) => {
|
|
32
|
+
const byteCharacters = atob(b64Data);
|
|
33
|
+
const byteArrays = [];
|
|
34
|
+
|
|
35
|
+
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
|
36
|
+
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
|
37
|
+
|
|
38
|
+
const byteNumbers = new Array(slice.length);
|
|
39
|
+
for (let i = 0; i < slice.length; i++) {
|
|
40
|
+
byteNumbers[i] = slice.charCodeAt(i);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
44
|
+
byteArrays.push(byteArray);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const blob = new Blob(byteArrays, { type: contentType });
|
|
48
|
+
return blob;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const splitb64 = (str: string): { b64Data: string; contentType: string } => {
|
|
52
|
+
const prefix = str.split(";")[0];
|
|
53
|
+
const contentType = prefix.split("data:")[1];
|
|
54
|
+
const b64Data = str.split(",")[1];
|
|
55
|
+
return {
|
|
56
|
+
b64Data,
|
|
57
|
+
contentType,
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
+
|
|
3
|
+
import wasm from "@/assets/metacrypto.wasm";
|
|
4
|
+
const importObject = {
|
|
5
|
+
wasi_snapshot_preview1: { proc_exit: () => {} },
|
|
6
|
+
};
|
|
7
|
+
let loadPromise = wasm(importObject);
|
|
8
|
+
class CryptoModule {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.initPromise = new Promise((_resolve) => {});
|
|
11
|
+
this.info = {
|
|
12
|
+
wasi_snapshot_preview1: { proc_exit: () => {} },
|
|
13
|
+
};
|
|
14
|
+
this.loadWasm();
|
|
15
|
+
}
|
|
16
|
+
loadWasm() {
|
|
17
|
+
this.initPromise = loadPromise;
|
|
18
|
+
}
|
|
19
|
+
decryptData(data) {
|
|
20
|
+
return this.initPromise.then(({ instance }) => {
|
|
21
|
+
let {
|
|
22
|
+
cppDecodeEncrypt,
|
|
23
|
+
cppGetReadDataLength,
|
|
24
|
+
cppGetWriteDataPtr,
|
|
25
|
+
cppSetEncryptKey,
|
|
26
|
+
cppEncodeEncrypt,
|
|
27
|
+
memory,
|
|
28
|
+
} = instance.exports;
|
|
29
|
+
let Int8View = new Uint8Array(memory.buffer);
|
|
30
|
+
if (ArrayBuffer.isView(data)) {
|
|
31
|
+
//if(true){
|
|
32
|
+
var intdata = new Uint8Array(data);
|
|
33
|
+
let bytesSize = intdata.length;
|
|
34
|
+
|
|
35
|
+
let writeDataOffset = cppGetWriteDataPtr(bytesSize);
|
|
36
|
+
Int8View.set(intdata, writeDataOffset);
|
|
37
|
+
|
|
38
|
+
let readDataOffset = cppDecodeEncrypt(bytesSize);
|
|
39
|
+
let readDataLength = cppGetReadDataLength();
|
|
40
|
+
let out_intdata = Int8View.subarray(readDataOffset, readDataOffset + readDataLength);
|
|
41
|
+
|
|
42
|
+
return out_intdata.slice(0);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let cryptoModule = new CryptoModule();
|
|
49
|
+
export default cryptoModule;
|
package/src/lib/index.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"strict": false,
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"jsx": "preserve",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"useDefineForClassFields": true,
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"baseUrl": ".",
|
|
18
|
+
"types": ["webpack-env", "jest"],
|
|
19
|
+
"paths": {
|
|
20
|
+
"@/*": ["src/*"]
|
|
21
|
+
},
|
|
22
|
+
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
|
|
23
|
+
},
|
|
24
|
+
"include": [
|
|
25
|
+
"examples/**/*.ts",
|
|
26
|
+
"examples/**/*.tsx",
|
|
27
|
+
"examples/**/*.vue",
|
|
28
|
+
"tests/**/*.ts",
|
|
29
|
+
"tests/**/*.tsx",
|
|
30
|
+
"src/**/*.ts"
|
|
31
|
+
],
|
|
32
|
+
"exclude": ["node_modules"]
|
|
33
|
+
}
|