@xmov/avatar 2.0.0-alpha.38
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/README.md +139 -0
- package/dist/agent/__tests__/agent.test.d.ts +1 -0
- package/dist/agent/audio-debug.d.ts +3 -0
- package/dist/agent/audio-uplink.d.ts +62 -0
- package/dist/agent/avatar.cjs +2 -0
- package/dist/agent/avatar.cjs.map +1 -0
- package/dist/agent/avatar.modern.js +2 -0
- package/dist/agent/avatar.modern.js.map +1 -0
- package/dist/agent/avatar.module.js +2 -0
- package/dist/agent/avatar.module.js.map +1 -0
- package/dist/agent/avatar.umd.js +2 -0
- package/dist/agent/avatar.umd.js.map +1 -0
- package/dist/agent/e2e-client.d.ts +32 -0
- package/dist/agent/fixed-audio-track.d.ts +48 -0
- package/dist/agent/index.cjs +5 -0
- package/dist/agent/index.d.ts +104 -0
- package/dist/agent/index.umd.js +10 -0
- package/dist/agent/microphone.d.ts +49 -0
- package/dist/agent/types.d.ts +153 -0
- package/dist/baseRender/AudioRenderer.d.ts +46 -0
- package/dist/baseRender/AudioWorklet.d.ts +78 -0
- package/dist/baseRender/AvatarRenderer.d.ts +226 -0
- package/dist/baseRender/MSEAudioPlayer.d.ts +51 -0
- package/dist/baseRender/UIRenderer.d.ts +39 -0
- package/dist/baseRender/pcm-audio-processor.d.ts +63 -0
- package/dist/control/APIForwarder.d.ts +23 -0
- package/dist/control/DataCacheQueue.d.ts +69 -0
- package/dist/control/EventDispatcher.d.ts +35 -0
- package/dist/control/RenderScheduler.d.ts +162 -0
- package/dist/control/SaveAndDownload.d.ts +14 -0
- package/dist/control/StreamingClient.d.ts +33 -0
- package/dist/control/VideoPlayer.d.ts +47 -0
- package/dist/control/ttsa.d.ts +111 -0
- package/dist/encoding/media-recorder-encoder.d.ts +33 -0
- package/dist/encoding/pcm-webm-encoder.d.ts +13 -0
- package/dist/encoding/webcodec-opus-encoder.d.ts +41 -0
- package/dist/encoding/webm-muxer.d.ts +90 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +231 -0
- package/dist/index.modern.js +2 -0
- package/dist/index.modern.js.map +1 -0
- package/dist/index.module.js +2 -0
- package/dist/index.module.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/modules/Composition.d.ts +28 -0
- package/dist/modules/ResourceManager.d.ts +295 -0
- package/dist/modules/TrackRenderer/base-track.d.ts +4 -0
- package/dist/modules/TrackRenderer/index.d.ts +12 -0
- package/dist/modules/TrackRenderer/render-implements.d.ts +19 -0
- package/dist/modules/TrackRenderer/track-pic.d.ts +8 -0
- package/dist/modules/TrackRenderer/track-subtitle.d.ts +8 -0
- package/dist/modules/cache-manager.d.ts +5 -0
- package/dist/modules/decoder.d.ts +84 -0
- package/dist/modules/error-handle.d.ts +17 -0
- package/dist/modules/network.d.ts +21 -0
- package/dist/proto/face_data_pb.d.ts +0 -0
- package/dist/types/capability.d.ts +15 -0
- package/dist/types/error.d.ts +70 -0
- package/dist/types/event.d.ts +25 -0
- package/dist/types/frame-data.d.ts +107 -0
- package/dist/types/index.d.ts +187 -0
- package/dist/types/render.d.ts +18 -0
- package/dist/utils/DataInterface.d.ts +113 -0
- package/dist/utils/GLDevice.d.ts +46 -0
- package/dist/utils/GLPipeline.d.ts +84 -0
- package/dist/utils/GLPipelineDebugTools.d.ts +5 -0
- package/dist/utils/Math.d.ts +21 -0
- package/dist/utils/__tests__/capability-checker.test.d.ts +1 -0
- package/dist/utils/audio-session.d.ts +11 -0
- package/dist/utils/audio.d.ts +1 -0
- package/dist/utils/capability-checker.d.ts +23 -0
- package/dist/utils/encodeToken.d.ts +7 -0
- package/dist/utils/face.d.ts +1 -0
- package/dist/utils/float32-decoder.d.ts +26 -0
- package/dist/utils/fpsTracker.d.ts +27 -0
- package/dist/utils/index.d.ts +22 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/media-recorder-timestamp.d.ts +15 -0
- package/dist/utils/pcmAnalyzer.d.ts +40 -0
- package/dist/utils/perfermance.d.ts +15 -0
- package/dist/utils/request.d.ts +19 -0
- package/dist/utils/requestAnimateFrames.d.ts +31 -0
- package/dist/utils/time.d.ts +9 -0
- package/dist/view/DebugOverlay.d.ts +54 -0
- package/dist/worker/streaming-video.d.ts +1 -0
- package/package.json +82 -0
- package/src/agent/__tests__/agent.test.ts +3787 -0
- package/src/agent/audio-debug.ts +36 -0
- package/src/agent/audio-uplink.ts +392 -0
- package/src/agent/e2e-client.ts +215 -0
- package/src/agent/fixed-audio-track.ts +547 -0
- package/src/agent/index.ts +1393 -0
- package/src/agent/microphone.ts +534 -0
- package/src/agent/types.ts +197 -0
- package/src/baseRender/AudioRenderer.ts +317 -0
- package/src/baseRender/AudioWorklet.ts +776 -0
- package/src/baseRender/AvatarRenderer.ts +1559 -0
- package/src/baseRender/MSEAudioPlayer.ts +243 -0
- package/src/baseRender/UIRenderer.ts +195 -0
- package/src/baseRender/pcm-audio-processor.js +267 -0
- package/src/control/APIForwarder.ts +67 -0
- package/src/control/DataCacheQueue.ts +372 -0
- package/src/control/EventDispatcher.ts +106 -0
- package/src/control/RenderScheduler.ts +945 -0
- package/src/control/SaveAndDownload.js +77 -0
- package/src/control/StreamingClient.ts +138 -0
- package/src/control/VideoPlayer.ts +306 -0
- package/src/control/ttsa.ts +676 -0
- package/src/encoding/media-recorder-encoder.ts +175 -0
- package/src/encoding/pcm-webm-encoder.ts +72 -0
- package/src/encoding/webcodec-opus-encoder.ts +258 -0
- package/src/encoding/webm-muxer.ts +337 -0
- package/src/global.d.ts +105 -0
- package/src/index.ts +1920 -0
- package/src/modules/Composition.ts +79 -0
- package/src/modules/ResourceManager.ts +899 -0
- package/src/modules/TrackRenderer/base-track.ts +7 -0
- package/src/modules/TrackRenderer/index.ts +40 -0
- package/src/modules/TrackRenderer/render-implements.ts +269 -0
- package/src/modules/TrackRenderer/track-pic.ts +19 -0
- package/src/modules/TrackRenderer/track-subtitle.ts +16 -0
- package/src/modules/cache-manager.ts +10 -0
- package/src/modules/decoder.ts +515 -0
- package/src/modules/error-handle.ts +20 -0
- package/src/modules/network.ts +71 -0
- package/src/proto/face_data.proto +45 -0
- package/src/proto/face_data_pb.js +1297 -0
- package/src/proto/protobuf.min.js +8 -0
- package/src/types/capability.ts +23 -0
- package/src/types/error.ts +211 -0
- package/src/types/event.ts +38 -0
- package/src/types/frame-data.ts +121 -0
- package/src/types/index.ts +207 -0
- package/src/types/render.ts +18 -0
- package/src/utils/DataInterface.ts +746 -0
- package/src/utils/GLDevice.ts +286 -0
- package/src/utils/GLPipeline.ts +1293 -0
- package/src/utils/GLPipelineDebugTools.ts +174 -0
- package/src/utils/Math.ts +266 -0
- package/src/utils/__tests__/capability-checker.test.ts +159 -0
- package/src/utils/audio-session.ts +144 -0
- package/src/utils/audio.ts +44 -0
- package/src/utils/blueimp-md5.d.ts +3 -0
- package/src/utils/capability-checker.ts +379 -0
- package/src/utils/encodeToken.ts +100 -0
- package/src/utils/face.ts +29 -0
- package/src/utils/float32-decoder.js +130 -0
- package/src/utils/fpsTracker.ts +100 -0
- package/src/utils/index.ts +182 -0
- package/src/utils/logger.js +36 -0
- package/src/utils/media-recorder-timestamp.ts +79 -0
- package/src/utils/pcmAnalyzer.ts +154 -0
- package/src/utils/perfermance.ts +141 -0
- package/src/utils/request.ts +95 -0
- package/src/utils/requestAnimateFrames.ts +195 -0
- package/src/utils/time.ts +32 -0
- package/src/view/DebugOverlay.ts +404 -0
- package/src/worker/streaming-video.ts +4647 -0
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import * as GLMath from "./Math"
|
|
3
|
+
|
|
4
|
+
const __version__ = "3.0.0"
|
|
5
|
+
|
|
6
|
+
export interface DataViewWithCustomOffset {
|
|
7
|
+
offset: number,
|
|
8
|
+
dataview: DataView // DataView is a generic type after TypeScript 5.7. We do not derive from it for the sake of compatibility.
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function checkVersion(buffer: ArrayBuffer | DataViewWithCustomOffset, version: string): [number, number, number] {
|
|
12
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
13
|
+
|
|
14
|
+
const dataver: [number, number, number] = [0, 0, 0];
|
|
15
|
+
for (let i = 0; i < 3; i++) {
|
|
16
|
+
dataver[i] = buffer.dataview.getUint8(buffer.offset);
|
|
17
|
+
buffer.offset += 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const refver = version.split(".").map(x => parseInt(x))
|
|
21
|
+
if (refver[0] < dataver[0]) throw new Error(`Data version (${dataver[0]}.${dataver[1]}.${dataver[2]}) is incompatible with the version of current data interface (${refver[0]}.${refver[1]}.${refver[2]}).`)
|
|
22
|
+
return dataver;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function decodeStr(buffer: ArrayBuffer | DataViewWithCustomOffset): string {
|
|
26
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
27
|
+
const charView = new Uint8Array(buffer.dataview.buffer, buffer.offset, buffer.dataview.byteLength - buffer.offset);
|
|
28
|
+
let strlen = 0;
|
|
29
|
+
while (strlen < charView.byteLength && charView[strlen] > 0) strlen++;
|
|
30
|
+
buffer.offset += strlen + 1;
|
|
31
|
+
const stringBytes = charView.slice(0, strlen);
|
|
32
|
+
const decoder = new TextDecoder('utf-8');
|
|
33
|
+
return decoder.decode(stringBytes);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function decodeLongInt(buffer: ArrayBuffer | DataViewWithCustomOffset): number {
|
|
37
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
38
|
+
|
|
39
|
+
let result = 0, shift = 0;
|
|
40
|
+
while (true) {
|
|
41
|
+
let byte_val = buffer.dataview.getUint8(buffer.offset);
|
|
42
|
+
buffer.offset++;
|
|
43
|
+
let data_bits = byte_val & 0x7F;
|
|
44
|
+
let new_result = result | (data_bits << shift);
|
|
45
|
+
if (new_result < result) throw new Error("Integer too large to decode.");
|
|
46
|
+
result = new_result;
|
|
47
|
+
if (0 === (byte_val & 0x80)) break;
|
|
48
|
+
shift += 7;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const TensorDataTypeMap = {
|
|
54
|
+
"B": Uint8Array,
|
|
55
|
+
"b": Int8Array,
|
|
56
|
+
"H": Uint16Array,
|
|
57
|
+
"h": Int16Array,
|
|
58
|
+
"I": Uint32Array,
|
|
59
|
+
"i": Int32Array,
|
|
60
|
+
"L": BigUint64Array,
|
|
61
|
+
"l": BigInt64Array,
|
|
62
|
+
"f": Float32Array,
|
|
63
|
+
"d": Float64Array
|
|
64
|
+
};
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
if ("undefined" !== typeof Float16Array) TensorDataTypeMap["e"] = Float16Array;
|
|
67
|
+
|
|
68
|
+
type ValueOf<T> = T[keyof T];
|
|
69
|
+
export type TensorDataConstructorType = ValueOf<typeof TensorDataTypeMap>;
|
|
70
|
+
export type TensorDataType = InstanceType<TensorDataConstructorType>;
|
|
71
|
+
|
|
72
|
+
export class Tensor {
|
|
73
|
+
public size: number[];
|
|
74
|
+
public data: TensorDataType;
|
|
75
|
+
constructor(size: number[], data: TensorDataType) {
|
|
76
|
+
this.size = size;
|
|
77
|
+
this.data = data;
|
|
78
|
+
}
|
|
79
|
+
itemSize(): number {
|
|
80
|
+
let size = 1;
|
|
81
|
+
for (let dim of this.size) size *= dim;
|
|
82
|
+
return size;
|
|
83
|
+
}
|
|
84
|
+
byteSize(): number { return this.itemSize() * this.data.BYTES_PER_ELEMENT; }
|
|
85
|
+
|
|
86
|
+
static zeros(size: number[], dataType: TensorDataConstructorType = Float32Array): Tensor {
|
|
87
|
+
let itemSize = 1;
|
|
88
|
+
for (let i = 0; i < size.length; i++)itemSize *= size[i];
|
|
89
|
+
const data = new dataType(itemSize);
|
|
90
|
+
for (let i = 0; i < itemSize; i++)data[i] = 0;
|
|
91
|
+
return new Tensor(size, data);
|
|
92
|
+
}
|
|
93
|
+
// extract subtensors
|
|
94
|
+
part(...index: number[]): Tensor {
|
|
95
|
+
if (index.length > this.size.length) throw new Error("Subtensor index length larger than tensor dimension.");
|
|
96
|
+
let size: number[] = [];
|
|
97
|
+
let newLength = 1;
|
|
98
|
+
for (let i = index.length; i < this.size.length; i++) {
|
|
99
|
+
size.push(this.size[i]);
|
|
100
|
+
newLength *= this.size[i];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let newStart = 0;
|
|
104
|
+
if (index.length > 0) newStart += index[0];
|
|
105
|
+
for (let i = 1; i < index.length; i++) {
|
|
106
|
+
newStart *= this.size[i];
|
|
107
|
+
newStart += index[i];
|
|
108
|
+
}
|
|
109
|
+
newStart *= newLength;
|
|
110
|
+
return new Tensor(size, this.data.slice(newStart, newStart + newLength));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static deserialize(buffer: ArrayBuffer | DataViewWithCustomOffset) {
|
|
114
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
115
|
+
|
|
116
|
+
const dimCount = buffer.dataview.getUint8(buffer.offset);
|
|
117
|
+
buffer.offset++;
|
|
118
|
+
const size = new Array<number>(dimCount);
|
|
119
|
+
let dataSize = 1;
|
|
120
|
+
for (let i = 0; i < dimCount; i++) {
|
|
121
|
+
size[i] = decodeLongInt(buffer);
|
|
122
|
+
dataSize *= size[i];
|
|
123
|
+
}
|
|
124
|
+
const dataTypeSymbol = String.fromCodePoint(buffer.dataview.getUint8(buffer.offset)) as keyof typeof TensorDataTypeMap;
|
|
125
|
+
buffer.offset++;
|
|
126
|
+
const dataType = TensorDataTypeMap[dataTypeSymbol];
|
|
127
|
+
if (undefined === dataType) throw new Error(`Unsupported tensor element type "${dataTypeSymbol}".`);
|
|
128
|
+
const dataByteSize = dataSize * dataType.BYTES_PER_ELEMENT;
|
|
129
|
+
const dataView = buffer.dataview.buffer.slice(buffer.offset, buffer.offset + dataByteSize);
|
|
130
|
+
const data = new dataType(dataView as ArrayBuffer);
|
|
131
|
+
buffer.offset += dataByteSize;
|
|
132
|
+
|
|
133
|
+
return new Tensor(size, data);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function loadArchives(buffer: ArrayBuffer | DataViewWithCustomOffset): unknown[] {
|
|
138
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
139
|
+
|
|
140
|
+
let result: unknown[] = [null];
|
|
141
|
+
while (true) {
|
|
142
|
+
const mimeType = decodeStr(buffer);
|
|
143
|
+
if ('' == mimeType) break;
|
|
144
|
+
else {
|
|
145
|
+
let item: unknown = null;
|
|
146
|
+
if ("text/plain;charset=UTF-8" === mimeType) {
|
|
147
|
+
const dataLen = decodeLongInt(buffer);
|
|
148
|
+
const charView = new Uint8Array(buffer.dataview.buffer, buffer.offset, dataLen);
|
|
149
|
+
buffer.offset += dataLen;
|
|
150
|
+
const decoder = new TextDecoder('utf-8');
|
|
151
|
+
item = decoder.decode(charView);
|
|
152
|
+
}
|
|
153
|
+
else if ("application/json;charset=UTF-8" == mimeType) {
|
|
154
|
+
const dataLen = decodeLongInt(buffer);
|
|
155
|
+
const charView = new Uint8Array(buffer.dataview.buffer, buffer.offset, dataLen);
|
|
156
|
+
buffer.offset += dataLen;
|
|
157
|
+
const decoder = new TextDecoder('utf-8');
|
|
158
|
+
item = JSON.parse(decoder.decode(charView));
|
|
159
|
+
}
|
|
160
|
+
else if ("application/octet-stream" === mimeType) item = Tensor.deserialize(buffer);
|
|
161
|
+
else {
|
|
162
|
+
const dataLen = decodeLongInt(buffer);
|
|
163
|
+
const dataSlice = buffer.dataview.buffer.slice(buffer.offset, buffer.offset + dataLen);
|
|
164
|
+
buffer.offset += dataLen;
|
|
165
|
+
item = new Blob([dataSlice as ArrayBuffer], { type: mimeType });
|
|
166
|
+
}
|
|
167
|
+
result.push(item);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export class CameraConfig {
|
|
174
|
+
focalLength: number = 75.0;
|
|
175
|
+
filmAperture: [number, number] = [1.0, 1.0]; // horizontal, vertical
|
|
176
|
+
translation: GLMath.vec3 = [0.0, 0.0, 0.0]; // X, Y, Z
|
|
177
|
+
rotation: GLMath.vec3 = [0.0, 0.0, 0.0]; // X, Y, Z
|
|
178
|
+
|
|
179
|
+
// methods
|
|
180
|
+
getIntrinsicMatrix(resolution: [number, number]): GLMath.mat3 {
|
|
181
|
+
const [size_X, size_Y] = resolution;
|
|
182
|
+
|
|
183
|
+
// 摄影机光圈是指多少英寸,25.4mm,胶片大小
|
|
184
|
+
let camera_aperture_in_mm_x = this.filmAperture[0] * 25.4
|
|
185
|
+
// 纵向的根据横向的来计算,而不是直接读取,可能和渲染分辨率、镜头挤压比有关系
|
|
186
|
+
// 在maya里面修改纵向光圈值完全没反应的,是根据渲染分辨率和横向光圈值来计算的
|
|
187
|
+
// 胶片纵横比理论上需要等于渲染分辨率的纵横比
|
|
188
|
+
// camera_aperture_in_mm_ = this.filmAperture[1] * 25.4
|
|
189
|
+
let camera_aperture_in_mm_y = camera_aperture_in_mm_x * resolution[1] / resolution[0];
|
|
190
|
+
|
|
191
|
+
// convert from maya camera to OpenCV camera
|
|
192
|
+
let px = resolution[0] / 2.0;
|
|
193
|
+
let py = resolution[1] / 2.0;
|
|
194
|
+
// 胶片尺寸/像素,代表1个像素多少mm,然后可以得到内参矩阵
|
|
195
|
+
let fx = this.focalLength / (camera_aperture_in_mm_x / size_X);
|
|
196
|
+
let fy = this.focalLength / (camera_aperture_in_mm_y / size_Y);
|
|
197
|
+
|
|
198
|
+
return [
|
|
199
|
+
[fx, 0, px],
|
|
200
|
+
[0, fy, py],
|
|
201
|
+
[0, 0, 1]
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
getProjMatrix(resolution: [number, number], near: number = 0.01, far: number = Infinity): GLMath.mat4 {
|
|
205
|
+
const [size_X, size_Y] = resolution;
|
|
206
|
+
const intrinsic_mat = this.getIntrinsicMatrix(resolution);
|
|
207
|
+
|
|
208
|
+
let proj22: number;
|
|
209
|
+
let proj23: number;
|
|
210
|
+
|
|
211
|
+
if (Infinity === far) {
|
|
212
|
+
proj22 = -1.0;
|
|
213
|
+
proj23 = -2.0 * near;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
proj22 = -(far + near) / (far - near);
|
|
217
|
+
proj23 = -(2.0 * far * near) / (far - near);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return [
|
|
221
|
+
[2.0 * intrinsic_mat[0][0] / size_X, 0.0, (size_X - 2 * intrinsic_mat[0][2]) / size_X, 0.0],
|
|
222
|
+
[0.0, 2.0 * intrinsic_mat[1][1] / size_Y, (size_Y - 2 * intrinsic_mat[1][2]) / size_Y, 0.0],
|
|
223
|
+
[0.0, 0.0, proj22, proj23],
|
|
224
|
+
[0.0, 0.0, -1.0, 0.0]
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
getExtrinsicMatrix(): GLMath.mat4 {
|
|
228
|
+
// 相机的世界坐标轴
|
|
229
|
+
const deg2rad = Math.PI / 180.0;
|
|
230
|
+
const R = GLMath.Euler_to_mat(this.rotation.map(x => x * deg2rad) as GLMath.vec3, "xyz");
|
|
231
|
+
// 反算物体的view matrix, 将相机坐标系转成世界坐标系, 相机朝向-z轴
|
|
232
|
+
const R_inv = GLMath.inv3(R);
|
|
233
|
+
const R_inv_neg_t = GLMath.mvmul(R_inv, this.translation.map(x => -x) as GLMath.vec3) as GLMath.vec3;
|
|
234
|
+
return GLMath.make_homogeneous(R_inv, R_inv_neg_t);
|
|
235
|
+
}
|
|
236
|
+
static deserialize(buffer: ArrayBuffer | DataViewWithCustomOffset) {
|
|
237
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
238
|
+
|
|
239
|
+
let result = new CameraConfig();
|
|
240
|
+
result.focalLength = buffer.dataview.getFloat32(buffer.offset, true);
|
|
241
|
+
for (let i = 0; i < 2; i++)result.filmAperture[i] = buffer.dataview.getFloat32(buffer.offset + (i + 1) * 4, true);
|
|
242
|
+
for (let i = 0; i < 3; i++)result.translation[i] = buffer.dataview.getFloat32(buffer.offset + (i + 3) * 4, true);
|
|
243
|
+
for (let i = 0; i < 3; i++)result.rotation[i] = buffer.dataview.getFloat32(buffer.offset + (i + 6) * 4, true);
|
|
244
|
+
buffer.offset += 9 * 4;
|
|
245
|
+
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export class RigidTransform {
|
|
251
|
+
translation: GLMath.vec3; // X, Y, Z
|
|
252
|
+
rotQuaternion: GLMath.vec4; // 1, i, j, k
|
|
253
|
+
|
|
254
|
+
// methods
|
|
255
|
+
constructor(translation: GLMath.vec3 = [0.0, 0.0, 0.0], rotQuaternion: GLMath.vec4 = [1.0, 0.0, 0.0, 0.0]) {
|
|
256
|
+
this.translation = translation;
|
|
257
|
+
this.rotQuaternion = rotQuaternion;
|
|
258
|
+
}
|
|
259
|
+
apply(x: GLMath.vec3 | RigidTransform): GLMath.vec3 | RigidTransform {
|
|
260
|
+
if (x instanceof RigidTransform) {
|
|
261
|
+
let result_quaternion = GLMath.quaternion_mul(this.rotQuaternion, x.rotQuaternion);
|
|
262
|
+
result_quaternion = GLMath.normalize(result_quaternion) as GLMath.vec4; // reduce floating point error
|
|
263
|
+
let result_translation = GLMath.mvmul(GLMath.quaternion_to_mat(this.rotQuaternion), x.translation) as GLMath.vec3;
|
|
264
|
+
for (let i = 0; i < 3; i++)result_translation[i] += this.translation[i];
|
|
265
|
+
return new RigidTransform(result_translation, result_quaternion);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
let result = GLMath.mvmul(this.matrix(), x) as GLMath.vec3;
|
|
269
|
+
for (let i = 0; i < 3; i++)result[i] += this.translation[i];
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
inv() {
|
|
274
|
+
let newRotQuaternion = GLMath.quaternion_conj(this.rotQuaternion);
|
|
275
|
+
let R_inv_neg_x = GLMath.mvmul(GLMath.quaternion_to_mat(newRotQuaternion), this.translation.map(x => -x) as GLMath.vec3) as GLMath.vec3;
|
|
276
|
+
return new RigidTransform(R_inv_neg_x, newRotQuaternion);
|
|
277
|
+
}
|
|
278
|
+
matrix() { return GLMath.quaternion_to_mat(this.rotQuaternion); }
|
|
279
|
+
homogeneous_matrix(): GLMath.mat4 { return GLMath.make_homogeneous(this.matrix(), this.translation); }
|
|
280
|
+
static deserialize(buffer: ArrayBuffer | DataViewWithCustomOffset) {
|
|
281
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
282
|
+
|
|
283
|
+
let translation: GLMath.vec3 = [0.0, 0.0, 0.0];
|
|
284
|
+
let rotQuaternion: GLMath.vec4 = [1.0, 0.0, 0.0, 0.0];
|
|
285
|
+
for (let i = 0; i < 3; i++)translation[i] = buffer.dataview.getFloat32(buffer.offset + i * 4, true);
|
|
286
|
+
let sum_sqr = 0.0;
|
|
287
|
+
for (let i = 0; i < 3; i++) {
|
|
288
|
+
rotQuaternion[i + 1] = buffer.dataview.getFloat32(buffer.offset + (i + 3) * 4, true);
|
|
289
|
+
sum_sqr += rotQuaternion[i + 1] * rotQuaternion[i + 1];
|
|
290
|
+
}
|
|
291
|
+
rotQuaternion[0] = Math.sqrt(Math.max(1.0 - sum_sqr, 0.0));
|
|
292
|
+
buffer.offset += 6 * 4;
|
|
293
|
+
|
|
294
|
+
return new RigidTransform(translation, rotQuaternion);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface JointInfo {
|
|
299
|
+
parent: number | null,
|
|
300
|
+
local_transform: RigidTransform
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface IBRMeshInfoSpec {
|
|
304
|
+
version: [number, number, number],
|
|
305
|
+
maxJointsPerVertex: number,
|
|
306
|
+
blendshapeIndices?: number[], // for v2.0 only
|
|
307
|
+
archivedItems?: unknown[]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export class IBRMeshInfo {
|
|
311
|
+
genMask: boolean;
|
|
312
|
+
vertices: Tensor; // neutral vertices
|
|
313
|
+
opacity?: Tensor;
|
|
314
|
+
triangles: Tensor;
|
|
315
|
+
UVCoord: Tensor;
|
|
316
|
+
blendshapeIndices: number[];
|
|
317
|
+
blendshapes: Tensor; // Dim 2 is the number of blendshapes
|
|
318
|
+
jointIndex: Uint8Array; // vertexCount * skeletonJointCount
|
|
319
|
+
jointWeight: Float32Array; // vertexCount * skeletonJointCount
|
|
320
|
+
textureModels: {
|
|
321
|
+
data: Tensor,
|
|
322
|
+
scalingFactor?: Tensor
|
|
323
|
+
}[];
|
|
324
|
+
|
|
325
|
+
constructor(buffer: ArrayBuffer | DataViewWithCustomOffset, spec: IBRMeshInfoSpec) {
|
|
326
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
327
|
+
|
|
328
|
+
if (spec.version[0] > 2) {
|
|
329
|
+
// v3.0
|
|
330
|
+
let meshFlag = buffer.dataview.getUint8(buffer.offset);
|
|
331
|
+
buffer.offset += 1;
|
|
332
|
+
this.genMask = (meshFlag & 1) > 0;
|
|
333
|
+
|
|
334
|
+
let bs_indices: number[] = [];
|
|
335
|
+
let bs_element_indices: number[][] = [];
|
|
336
|
+
let first_bs = true;
|
|
337
|
+
while (true) {
|
|
338
|
+
let bs_index = decodeLongInt(buffer);
|
|
339
|
+
if (0 === bs_index) {
|
|
340
|
+
if (!first_bs) break;
|
|
341
|
+
}
|
|
342
|
+
else bs_indices.push(bs_index - 1);
|
|
343
|
+
first_bs = false;
|
|
344
|
+
|
|
345
|
+
let cur_bs_element_indices: number[] = [];
|
|
346
|
+
let segment_stat = true, segment_ptr = 0;
|
|
347
|
+
while (true) {
|
|
348
|
+
let segment_len = decodeLongInt(buffer);
|
|
349
|
+
if (segment_stat) {
|
|
350
|
+
for (let i = 0; i < segment_len; i++)cur_bs_element_indices.push(segment_ptr + i);
|
|
351
|
+
}
|
|
352
|
+
segment_stat = !segment_stat;
|
|
353
|
+
segment_ptr += segment_len;
|
|
354
|
+
if (0 === segment_len && segment_ptr > 0) break;
|
|
355
|
+
}
|
|
356
|
+
bs_element_indices.push(cur_bs_element_indices);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let vertexCount = bs_element_indices[0].length;
|
|
360
|
+
|
|
361
|
+
this.blendshapeIndices = bs_indices;
|
|
362
|
+
let rawBlendshapeData: Tensor = spec.archivedItems![decodeLongInt(buffer)] as Tensor;
|
|
363
|
+
let vertices = Tensor.zeros([vertexCount, rawBlendshapeData.size[1]], rawBlendshapeData.data.constructor as TensorDataConstructorType);
|
|
364
|
+
let blendshapes = Tensor.zeros([vertexCount, rawBlendshapeData.size[1], this.blendshapeIndices.length], rawBlendshapeData.data.constructor as TensorDataConstructorType);
|
|
365
|
+
let bs_data_index = 0;
|
|
366
|
+
const elementIndexList = bs_element_indices[0];
|
|
367
|
+
for (let element_index of elementIndexList) {
|
|
368
|
+
for (let i = 0; i < rawBlendshapeData.size[1]; i++)vertices.data[element_index * rawBlendshapeData.size[1] + i] = rawBlendshapeData.data[bs_data_index * rawBlendshapeData.size[1] + i];
|
|
369
|
+
bs_data_index++;
|
|
370
|
+
}
|
|
371
|
+
const bs_stride = this.blendshapeIndices.length;
|
|
372
|
+
for (let bs_index = 1; bs_index < bs_element_indices.length; bs_index++) {
|
|
373
|
+
const elementIndexList = bs_element_indices[bs_index];
|
|
374
|
+
for (let element_index of elementIndexList) {
|
|
375
|
+
for (let i = 0; i < rawBlendshapeData.size[1]; i++)blendshapes.data[(element_index * rawBlendshapeData.size[1] + i) * bs_stride + bs_index - 1] = rawBlendshapeData.data[bs_data_index * rawBlendshapeData.size[1] + i];
|
|
376
|
+
bs_data_index++;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
this.vertices = vertices;
|
|
380
|
+
this.blendshapes = blendshapes;
|
|
381
|
+
this.triangles = spec.archivedItems![decodeLongInt(buffer)] as Tensor;
|
|
382
|
+
this.opacity = spec.archivedItems![decodeLongInt(buffer)] as Tensor;
|
|
383
|
+
this.UVCoord = spec.archivedItems![decodeLongInt(buffer)] as Tensor;
|
|
384
|
+
|
|
385
|
+
this.jointIndex = new Uint8Array(vertexCount * spec.maxJointsPerVertex);
|
|
386
|
+
this.jointWeight = new Float32Array(vertexCount * spec.maxJointsPerVertex);
|
|
387
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
388
|
+
for (let j = 0; j < spec.maxJointsPerVertex; j++) {
|
|
389
|
+
this.jointIndex[i * spec.maxJointsPerVertex + j] = buffer.dataview.getUint8(buffer.offset);
|
|
390
|
+
buffer.offset += 1;
|
|
391
|
+
}
|
|
392
|
+
for (let j = 0; j < spec.maxJointsPerVertex; j++) {
|
|
393
|
+
this.jointWeight[i * spec.maxJointsPerVertex + j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
394
|
+
buffer.offset += 4;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const textureModelCount = buffer.dataview.getUint8(buffer.offset);
|
|
399
|
+
buffer.offset += 1;
|
|
400
|
+
this.textureModels = new Array(textureModelCount);
|
|
401
|
+
for (let i = 0; i < textureModelCount; i++) {
|
|
402
|
+
this.textureModels[i] = {
|
|
403
|
+
data: spec.archivedItems![decodeLongInt(buffer)] as Tensor,
|
|
404
|
+
scalingFactor: spec.archivedItems![decodeLongInt(buffer)] as Tensor
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// v2.0
|
|
410
|
+
this.genMask = true;
|
|
411
|
+
|
|
412
|
+
let vertexCount = buffer.dataview.getUint16(buffer.offset, true);
|
|
413
|
+
buffer.offset += 2;
|
|
414
|
+
|
|
415
|
+
const opacity = new Float32Array(vertexCount);
|
|
416
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
417
|
+
opacity[i] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
418
|
+
buffer.offset += 4;
|
|
419
|
+
}
|
|
420
|
+
this.opacity = new Tensor([vertexCount], opacity);
|
|
421
|
+
|
|
422
|
+
let triangleCount = buffer.dataview.getUint16(buffer.offset, true);
|
|
423
|
+
buffer.offset += 2;
|
|
424
|
+
|
|
425
|
+
const triangles = new Uint16Array(triangleCount * 3);
|
|
426
|
+
for (let i = 0; i < triangleCount; i++) {
|
|
427
|
+
for (let j = 0; j < 3; j++) {
|
|
428
|
+
triangles[i * 3 + j] = buffer.dataview.getUint16(buffer.offset, true);
|
|
429
|
+
buffer.offset += 2;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
this.triangles = new Tensor([triangleCount, 3], triangles);
|
|
433
|
+
|
|
434
|
+
const UVCoord = new Float32Array(vertexCount * 2);
|
|
435
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
436
|
+
for (let j = 0; j < 2; j++) {
|
|
437
|
+
UVCoord[i * 2 + j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
438
|
+
buffer.offset += 4;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
this.UVCoord = new Tensor([vertexCount, 2], UVCoord);
|
|
442
|
+
|
|
443
|
+
const blendshapeCount = buffer.dataview.getUint16(buffer.offset, true);
|
|
444
|
+
buffer.offset += 2;
|
|
445
|
+
const vertices = new Float32Array(vertexCount * 3);
|
|
446
|
+
for (let i = 0; i < vertexCount * 3; i++) {
|
|
447
|
+
vertices[i] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
448
|
+
buffer.offset += 4;
|
|
449
|
+
}
|
|
450
|
+
const blendshapes = new Float32Array((blendshapeCount - 1) * vertexCount * 3);
|
|
451
|
+
// blendshape need transposition
|
|
452
|
+
for (let j = 0; j < blendshapeCount - 1; j++) {
|
|
453
|
+
for (let i = 0; i < vertexCount * 3; i++) {
|
|
454
|
+
blendshapes[i * (blendshapeCount - 1) + j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
455
|
+
buffer.offset += 4;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
this.vertices = new Tensor([vertexCount, 3], vertices);
|
|
459
|
+
this.blendshapes = new Tensor([vertexCount, 3, blendshapeCount - 1], blendshapes);
|
|
460
|
+
this.blendshapeIndices = [];
|
|
461
|
+
for (let index of spec.blendshapeIndices!) this.blendshapeIndices.push(index);
|
|
462
|
+
|
|
463
|
+
this.jointIndex = new Uint8Array(vertexCount * spec.maxJointsPerVertex);
|
|
464
|
+
this.jointWeight = new Float32Array(vertexCount * spec.maxJointsPerVertex);
|
|
465
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
466
|
+
for (let j = 0; j < spec.maxJointsPerVertex; j++) {
|
|
467
|
+
this.jointIndex[i * spec.maxJointsPerVertex + j] = buffer.dataview.getUint8(buffer.offset);
|
|
468
|
+
buffer.offset += 1;
|
|
469
|
+
}
|
|
470
|
+
for (let j = 0; j < spec.maxJointsPerVertex; j++) {
|
|
471
|
+
this.jointWeight[i * spec.maxJointsPerVertex + j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
472
|
+
buffer.offset += 4;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const textureModelCount = buffer.dataview.getUint8(buffer.offset);
|
|
477
|
+
buffer.offset += 1;
|
|
478
|
+
this.textureModels = new Array(textureModelCount);
|
|
479
|
+
for (let i = 0; i < textureModelCount; i++) {
|
|
480
|
+
const PCASize = [0, 0, 0, 3];
|
|
481
|
+
for (let j = 0; j < 3; j++) {
|
|
482
|
+
PCASize[j] = buffer.dataview.getUint16(buffer.offset, true);
|
|
483
|
+
buffer.offset += 2;
|
|
484
|
+
}
|
|
485
|
+
const PCAComponents = new Float32Array(PCASize[0] * PCASize[1] * PCASize[2] * 3);
|
|
486
|
+
for (let j = 0; j < PCAComponents.length; j++) {
|
|
487
|
+
PCAComponents[j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
488
|
+
buffer.offset += 4;
|
|
489
|
+
}
|
|
490
|
+
this.textureModels[i] = { data: new Tensor(PCASize, PCAComponents) };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export class IBRMeshFrameInfo {
|
|
497
|
+
textureModelIndex: number;
|
|
498
|
+
texturePCAWeights: Float32Array;
|
|
499
|
+
|
|
500
|
+
constructor(textureModelIndex: number, texturePCAWeights: Float32Array) {
|
|
501
|
+
this.textureModelIndex = textureModelIndex;
|
|
502
|
+
this.texturePCAWeights = texturePCAWeights;
|
|
503
|
+
}
|
|
504
|
+
static deserialize(buffer: ArrayBuffer | DataViewWithCustomOffset, char_data: IBRMeshInfo) {
|
|
505
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
506
|
+
|
|
507
|
+
let textureModelIndex = buffer.dataview.getUint8(buffer.offset);
|
|
508
|
+
buffer.offset += 1;
|
|
509
|
+
let texturePCAWeights = new Float32Array(char_data.textureModels[textureModelIndex].data.size[0] - 1);
|
|
510
|
+
for (let i = 0; i < texturePCAWeights.length; i++) {
|
|
511
|
+
texturePCAWeights[i] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
512
|
+
buffer.offset += 4;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return new IBRMeshFrameInfo(textureModelIndex, texturePCAWeights);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export class IBRAnimationGeneratorCharInfo_NN {
|
|
520
|
+
cameraConfig: CameraConfig;
|
|
521
|
+
blendshapeCount: number;
|
|
522
|
+
mesh: IBRMeshInfo[];
|
|
523
|
+
|
|
524
|
+
skeleton: JointInfo[];
|
|
525
|
+
jointEvalOrder: number[];
|
|
526
|
+
movableJoints: number[];
|
|
527
|
+
maxJointsPerVertex: number;
|
|
528
|
+
|
|
529
|
+
constructor(buffer: ArrayBuffer | DataViewWithCustomOffset, spec: { blendshapeMap?: number[][] } = {}) {
|
|
530
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
531
|
+
const version = checkVersion(buffer, __version__);
|
|
532
|
+
|
|
533
|
+
let archivedItems: unknown[] = [];
|
|
534
|
+
if (version[0] > 2) archivedItems = loadArchives(buffer);
|
|
535
|
+
|
|
536
|
+
this.cameraConfig = CameraConfig.deserialize(buffer);
|
|
537
|
+
if (version[0] > 2) this.blendshapeCount = decodeLongInt(buffer);
|
|
538
|
+
else {
|
|
539
|
+
if (!spec.blendshapeMap) throw new Error(`A blendshape map is required to load the character information of v2.0 format.`);
|
|
540
|
+
let bsIndexSet = new Set();
|
|
541
|
+
for (const map of spec.blendshapeMap) {
|
|
542
|
+
for (const index of map) bsIndexSet.add(index);
|
|
543
|
+
}
|
|
544
|
+
this.blendshapeCount = bsIndexSet.size;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
let skeletonJointCount = buffer.dataview.getUint8(buffer.offset);
|
|
548
|
+
buffer.offset += 1;
|
|
549
|
+
this.maxJointsPerVertex = buffer.dataview.getUint8(buffer.offset);
|
|
550
|
+
buffer.offset += 1;
|
|
551
|
+
let movableJointCount = buffer.dataview.getUint8(buffer.offset);
|
|
552
|
+
buffer.offset += 1;
|
|
553
|
+
let movableJoints = new Array(movableJointCount);
|
|
554
|
+
for (let i = 0; i < movableJointCount; i++) {
|
|
555
|
+
movableJoints[i] = buffer.dataview.getUint8(buffer.offset);
|
|
556
|
+
buffer.offset += 1;
|
|
557
|
+
}
|
|
558
|
+
this.movableJoints = movableJoints;
|
|
559
|
+
this.skeleton = new Array(skeletonJointCount);
|
|
560
|
+
for (let i = 0; i < skeletonJointCount; i++) {
|
|
561
|
+
let parent: number | null = buffer.dataview.getUint8(buffer.offset);
|
|
562
|
+
if (parent >= this.skeleton.length) parent = null;
|
|
563
|
+
buffer.offset += 1;
|
|
564
|
+
let local_transform = RigidTransform.deserialize(buffer);
|
|
565
|
+
this.skeleton[i] = { parent: parent, local_transform: local_transform };
|
|
566
|
+
}
|
|
567
|
+
this.jointEvalOrder = new Array(skeletonJointCount);
|
|
568
|
+
for (let i = 0; i < skeletonJointCount; i++) {
|
|
569
|
+
this.jointEvalOrder[i] = buffer.dataview.getUint8(buffer.offset);
|
|
570
|
+
buffer.offset += 1;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
let meshInfoSpec: IBRMeshInfoSpec = {
|
|
574
|
+
version: version,
|
|
575
|
+
maxJointsPerVertex: this.maxJointsPerVertex
|
|
576
|
+
}
|
|
577
|
+
if (version[0] > 2) meshInfoSpec.archivedItems = archivedItems;
|
|
578
|
+
|
|
579
|
+
let meshCount = buffer.dataview.getUint8(buffer.offset);
|
|
580
|
+
buffer.offset += 1;
|
|
581
|
+
this.mesh = new Array(meshCount);
|
|
582
|
+
for (let i = 0; i < meshCount; i++) {
|
|
583
|
+
if (version[0] <= 2) meshInfoSpec.blendshapeIndices = spec.blendshapeMap![i];
|
|
584
|
+
this.mesh[i] = new IBRMeshInfo(buffer, meshInfoSpec);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
evalSkeleton(): RigidTransform[] {
|
|
588
|
+
let result = Array(this.skeleton.length);
|
|
589
|
+
for (let i of this.jointEvalOrder) {
|
|
590
|
+
if (null == this.skeleton[i].parent) result[i] = this.skeleton[i].local_transform;
|
|
591
|
+
else result[i] = result[this.skeleton[i].parent].apply(this.skeleton[i].local_transform);
|
|
592
|
+
}
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
evalSkeletonFromMovable(movableJointTransforms: RigidTransform[]): RigidTransform[] {
|
|
596
|
+
let result = Array(this.skeleton.length);
|
|
597
|
+
for (let i = 0; i < movableJointTransforms.length; i++)result[this.movableJoints[i]] = movableJointTransforms[i];
|
|
598
|
+
for (let i of this.jointEvalOrder) {
|
|
599
|
+
if (null != this.skeleton[i].parent) result[i] = result[this.skeleton[i].parent].apply(this.skeleton[i].local_transform);
|
|
600
|
+
}
|
|
601
|
+
return result;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export class IBRAnimationFrameData_NN {
|
|
606
|
+
mesh: IBRMeshFrameInfo[];
|
|
607
|
+
blendshapeWeights: Float32Array;
|
|
608
|
+
movableJointTransforms: RigidTransform[];
|
|
609
|
+
|
|
610
|
+
constructor() {
|
|
611
|
+
this.mesh = [];
|
|
612
|
+
this.blendshapeWeights = new Float32Array();
|
|
613
|
+
this.movableJointTransforms = [];
|
|
614
|
+
}
|
|
615
|
+
static deserialize(buffer: ArrayBuffer | DataViewWithCustomOffset, char_data: IBRAnimationGeneratorCharInfo_NN, version: [number, number, number]): IBRAnimationFrameData_NN {
|
|
616
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
617
|
+
|
|
618
|
+
let result = new IBRAnimationFrameData_NN();
|
|
619
|
+
|
|
620
|
+
const meshCount = char_data.mesh.length;
|
|
621
|
+
result.mesh = new Array(meshCount);
|
|
622
|
+
|
|
623
|
+
result.blendshapeWeights = new Float32Array(char_data.blendshapeCount);
|
|
624
|
+
if (version[0] > 2) {
|
|
625
|
+
// v3.0
|
|
626
|
+
for (let i = 0; i < meshCount; i++)result.mesh[i] = IBRMeshFrameInfo.deserialize(buffer, char_data.mesh[i]);
|
|
627
|
+
for (let i = 0; i < result.blendshapeWeights.length; i++) {
|
|
628
|
+
result.blendshapeWeights[i] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
629
|
+
buffer.offset += 4;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
// v2.0
|
|
634
|
+
for (let i = 0; i < meshCount; i++) {
|
|
635
|
+
const blendshapeIndices = char_data.mesh[i].blendshapeIndices;
|
|
636
|
+
for (let j = 0; j + 1 < blendshapeIndices.length; j++) {
|
|
637
|
+
result.blendshapeWeights[blendshapeIndices[j + 1] - 1] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
638
|
+
buffer.offset += 4;
|
|
639
|
+
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
let textureModelIndex = buffer.dataview.getUint8(buffer.offset);
|
|
643
|
+
buffer.offset += 1;
|
|
644
|
+
let texturePCAWeights = new Float32Array(char_data.mesh[i].textureModels[textureModelIndex].data.size[0] - 1);
|
|
645
|
+
for (let j = 0; j < texturePCAWeights.length; j++) {
|
|
646
|
+
texturePCAWeights[j] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
647
|
+
buffer.offset += 4;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
result.mesh[i] = new IBRMeshFrameInfo(textureModelIndex, texturePCAWeights);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
result.movableJointTransforms = new Array(char_data.movableJoints.length);
|
|
655
|
+
for (let i = 0; i < char_data.movableJoints.length; i++)result.movableJointTransforms[i] = RigidTransform.deserialize(buffer);
|
|
656
|
+
|
|
657
|
+
return result;
|
|
658
|
+
}
|
|
659
|
+
static interp(frame1: IBRAnimationFrameData_NN, frame2: IBRAnimationFrameData_NN, frameJointRef: IBRAnimationFrameData_NN, t: number, jointEvalOrder: [number, number][]): IBRAnimationFrameData_NN {
|
|
660
|
+
// return linear interpolated result between frame data.
|
|
661
|
+
let result = new IBRAnimationFrameData_NN();
|
|
662
|
+
|
|
663
|
+
result.blendshapeWeights = new Float32Array(frame1.blendshapeWeights.length);
|
|
664
|
+
for (let i = 0; i < result.blendshapeWeights.length; i++)result.blendshapeWeights[i] = t * frame2.blendshapeWeights[i] + (1.0 - t) * frame1.blendshapeWeights[i];
|
|
665
|
+
result.mesh = [];
|
|
666
|
+
for (let i = 0; i < frame1.mesh.length; i++) {
|
|
667
|
+
let new_mesh_pca_info = new IBRMeshFrameInfo(frame1.mesh[i].textureModelIndex, new Float32Array(frame1.mesh[i].texturePCAWeights.length));
|
|
668
|
+
for (let j = 0; j < frame1.mesh[i].texturePCAWeights.length; j++)new_mesh_pca_info.texturePCAWeights[j] = t * frame2.mesh[i].texturePCAWeights[j] + (1.0 - t) * frame1.mesh[i].texturePCAWeights[j];
|
|
669
|
+
result.mesh.push(new_mesh_pca_info);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// joints
|
|
673
|
+
result.movableJointTransforms = new Array(frameJointRef.movableJointTransforms.length);
|
|
674
|
+
for (let i = 0; i < frameJointRef.movableJointTransforms.length; i++) {
|
|
675
|
+
let preserved = true;
|
|
676
|
+
for (let [index_child, _] of jointEvalOrder) {
|
|
677
|
+
if (index_child === i) {
|
|
678
|
+
preserved = false;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (preserved) result.movableJointTransforms[i] = frameJointRef.movableJointTransforms[i];
|
|
683
|
+
}
|
|
684
|
+
for (let [index_child, index_parent] of jointEvalOrder) {
|
|
685
|
+
let T1 = frame1.movableJointTransforms[index_parent].inv().apply(frame1.movableJointTransforms[index_child]) as RigidTransform;
|
|
686
|
+
let T2 = frame2.movableJointTransforms[index_parent].inv().apply(frame2.movableJointTransforms[index_child]) as RigidTransform;
|
|
687
|
+
let translation = [], rotQuaternion = [];
|
|
688
|
+
for (let j = 0; j < 3; j++)translation.push(t * T2.translation[j] + (1.0 - t) * T1.translation[j]);
|
|
689
|
+
for (let j = 0; j < 4; j++)rotQuaternion.push(t * T2.rotQuaternion[j] + (1.0 - t) * T1.rotQuaternion[j]);
|
|
690
|
+
rotQuaternion = GLMath.normalize(rotQuaternion);
|
|
691
|
+
let blended_transform = new RigidTransform(translation as GLMath.vec3, rotQuaternion as GLMath.vec4);
|
|
692
|
+
blended_transform = frameJointRef.movableJointTransforms[index_parent].apply(blended_transform) as RigidTransform;
|
|
693
|
+
result.movableJointTransforms[index_child] = blended_transform;
|
|
694
|
+
}
|
|
695
|
+
return result;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function unpackIBRAnimation(buffer: ArrayBuffer | DataViewWithCustomOffset, char_data: IBRAnimationGeneratorCharInfo_NN): IBRAnimationFrameData_NN[] {
|
|
700
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
701
|
+
const version = checkVersion(buffer, __version__);
|
|
702
|
+
|
|
703
|
+
const frameCount = buffer.dataview.getUint32(buffer.offset, true);
|
|
704
|
+
buffer.offset += 4;
|
|
705
|
+
|
|
706
|
+
let result = Array(frameCount);
|
|
707
|
+
for (let i = 0; i < frameCount; i++)result[i] = IBRAnimationFrameData_NN.deserialize(buffer, char_data, version);
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export class TextureFloat_3D {
|
|
712
|
+
size: [number, number, number, number]; // dim0, dim1, dim2, component
|
|
713
|
+
data: Float32Array; // first component is mean
|
|
714
|
+
constructor(buffer: ArrayBuffer | DataViewWithCustomOffset) {
|
|
715
|
+
if (buffer instanceof ArrayBuffer) buffer = { offset: 0, dataview: new DataView(buffer) } as DataViewWithCustomOffset;
|
|
716
|
+
|
|
717
|
+
this.size = [0, 0, 0, 0];
|
|
718
|
+
for (let i = 0; i < 4; i++) {
|
|
719
|
+
this.size[i] = buffer.dataview.getUint16(buffer.offset, true);
|
|
720
|
+
buffer.offset += 2;
|
|
721
|
+
}
|
|
722
|
+
this.data = new Float32Array(this.size[0] * this.size[1] * this.size[2] * this.size[3]);
|
|
723
|
+
for (let i = 0; i < this.data.length; i++) {
|
|
724
|
+
this.data[i] = buffer.dataview.getFloat32(buffer.offset, true);
|
|
725
|
+
buffer.offset += 4;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
export function transformMJT(mjt: number[][]): RigidTransform[] {
|
|
731
|
+
let result = Array(mjt.length);
|
|
732
|
+
for (let i = 0; i < mjt.length; i++) {
|
|
733
|
+
result[i] = new RigidTransform(
|
|
734
|
+
mjt[i].slice(0, 3) as [number, number, number],
|
|
735
|
+
mjt[i].slice(3) as [number, number, number, number]
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return result;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function formatMJT(a1: number[], a2: number[]) {
|
|
742
|
+
return new RigidTransform(
|
|
743
|
+
a1 as [number, number, number],
|
|
744
|
+
a2 as [number, number, number, number]
|
|
745
|
+
);
|
|
746
|
+
}
|