reze-engine 0.2.17 → 0.2.19
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 +1 -2
- package/dist/engine.d.ts +16 -5
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +604 -722
- package/dist/model.d.ts +36 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +156 -1
- package/dist/pmx-loader.d.ts +3 -1
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +161 -94
- package/package.json +1 -1
- package/src/engine.ts +2267 -2392
- package/src/model.ts +649 -421
- package/src/pmx-loader.ts +180 -89
package/src/pmx-loader.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Model,
|
|
3
|
+
Texture,
|
|
4
|
+
Material,
|
|
5
|
+
Bone,
|
|
6
|
+
Skeleton,
|
|
7
|
+
Skinning,
|
|
8
|
+
Morph,
|
|
9
|
+
Morphing,
|
|
10
|
+
VertexMorphOffset,
|
|
11
|
+
GroupMorphReference,
|
|
12
|
+
} from "./model"
|
|
2
13
|
import { Mat4, Vec3 } from "./math"
|
|
3
14
|
import { Rigidbody, Joint, RigidbodyShape, RigidbodyType } from "./physics"
|
|
4
15
|
|
|
@@ -20,6 +31,8 @@ export class PmxLoader {
|
|
|
20
31
|
private inverseBindMatrices: Float32Array | null = null
|
|
21
32
|
private joints0: Uint16Array | null = null
|
|
22
33
|
private weights0: Uint8Array | null = null
|
|
34
|
+
private morphs: Morph[] = []
|
|
35
|
+
private vertexCount: number = 0
|
|
23
36
|
private rigidbodies: Rigidbody[] = []
|
|
24
37
|
private joints: Joint[] = []
|
|
25
38
|
|
|
@@ -35,12 +48,13 @@ export class PmxLoader {
|
|
|
35
48
|
private parse(): Model {
|
|
36
49
|
this.parseHeader()
|
|
37
50
|
const { positions, normals, uvs } = this.parseVertices()
|
|
51
|
+
this.vertexCount = positions.length / 3
|
|
38
52
|
const indices = this.parseIndices()
|
|
39
53
|
this.parseTextures()
|
|
40
54
|
this.parseMaterials()
|
|
41
55
|
this.parseBones()
|
|
42
|
-
//
|
|
43
|
-
this.
|
|
56
|
+
// Parse morphs and display frames before parsing rigidbodies
|
|
57
|
+
this.parseMorphs()
|
|
44
58
|
this.skipDisplayFrames()
|
|
45
59
|
this.parseRigidbodies()
|
|
46
60
|
this.parseJoints()
|
|
@@ -447,108 +461,146 @@ export class PmxLoader {
|
|
|
447
461
|
}
|
|
448
462
|
}
|
|
449
463
|
|
|
450
|
-
private
|
|
464
|
+
private parseMorphs(): void {
|
|
451
465
|
try {
|
|
452
466
|
// Check if we have enough bytes to read the count
|
|
453
467
|
if (this.offset + 4 > this.view.buffer.byteLength) {
|
|
454
|
-
|
|
468
|
+
this.morphs = []
|
|
469
|
+
return
|
|
455
470
|
}
|
|
456
471
|
const count = this.getInt32()
|
|
457
472
|
if (count < 0 || count > 100000) {
|
|
458
|
-
// Suspicious count, likely corrupted
|
|
459
|
-
|
|
460
|
-
|
|
473
|
+
// Suspicious count, likely corrupted
|
|
474
|
+
console.warn(`Suspicious morph count: ${count}`)
|
|
475
|
+
this.morphs = []
|
|
476
|
+
return
|
|
461
477
|
}
|
|
478
|
+
|
|
479
|
+
this.morphs = []
|
|
480
|
+
|
|
462
481
|
for (let i = 0; i < count; i++) {
|
|
463
482
|
// Check bounds before reading each morph
|
|
464
483
|
if (this.offset >= this.view.buffer.byteLength) {
|
|
465
|
-
|
|
484
|
+
break
|
|
466
485
|
}
|
|
467
486
|
try {
|
|
468
|
-
this.getText()
|
|
469
|
-
this.getText() // englishName
|
|
470
|
-
this.getUint8() // panelType
|
|
487
|
+
const name = this.getText()
|
|
488
|
+
this.getText() // englishName (skip)
|
|
489
|
+
this.getUint8() // panelType (skip)
|
|
471
490
|
const morphType = this.getUint8()
|
|
472
491
|
const offsetCount = this.getInt32()
|
|
473
492
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
493
|
+
const morph: Morph = {
|
|
494
|
+
name,
|
|
495
|
+
type: morphType,
|
|
496
|
+
vertexOffsets: [],
|
|
497
|
+
groupReferences: [],
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Parse vertex morphs (type 1)
|
|
501
|
+
if (morphType === 1) {
|
|
502
|
+
for (let j = 0; j < offsetCount; j++) {
|
|
503
|
+
if (this.offset >= this.view.buffer.byteLength) {
|
|
504
|
+
break
|
|
505
|
+
}
|
|
506
|
+
const vertexIndex = this.getIndex(this.vertexIndexSize)
|
|
507
|
+
const x = this.getFloat32()
|
|
508
|
+
const y = this.getFloat32()
|
|
509
|
+
const z = this.getFloat32()
|
|
510
|
+
|
|
511
|
+
if (vertexIndex >= 0 && vertexIndex < this.vertexCount) {
|
|
512
|
+
morph.vertexOffsets.push({
|
|
513
|
+
vertexIndex,
|
|
514
|
+
positionOffset: [x, y, z],
|
|
515
|
+
})
|
|
516
|
+
}
|
|
478
517
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
this.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
this.
|
|
486
|
-
this.getFloat32()
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
518
|
+
} else if (morphType === 0) {
|
|
519
|
+
// Parse group morphs
|
|
520
|
+
for (let j = 0; j < offsetCount; j++) {
|
|
521
|
+
if (this.offset >= this.view.buffer.byteLength) {
|
|
522
|
+
break
|
|
523
|
+
}
|
|
524
|
+
const morphIndex = this.getNonVertexIndex(this.morphIndexSize)
|
|
525
|
+
const ratio = this.getFloat32()
|
|
526
|
+
|
|
527
|
+
if (morphIndex >= 0) {
|
|
528
|
+
morph.groupReferences!.push({
|
|
529
|
+
morphIndex,
|
|
530
|
+
ratio,
|
|
531
|
+
})
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
} else {
|
|
535
|
+
// Skip other morph types for now
|
|
536
|
+
for (let j = 0; j < offsetCount; j++) {
|
|
537
|
+
if (this.offset >= this.view.buffer.byteLength) {
|
|
538
|
+
break
|
|
539
|
+
}
|
|
540
|
+
if (morphType === 2) {
|
|
541
|
+
// Bone morph
|
|
542
|
+
this.getNonVertexIndex(this.boneIndexSize) // boneIndex
|
|
543
|
+
this.getFloat32() // x
|
|
544
|
+
this.getFloat32() // y
|
|
545
|
+
this.getFloat32() // z
|
|
546
|
+
this.getFloat32() // rx
|
|
547
|
+
this.getFloat32() // ry
|
|
548
|
+
this.getFloat32() // rz
|
|
549
|
+
} else if (morphType === 3) {
|
|
550
|
+
// UV morph
|
|
551
|
+
this.getIndex(this.vertexIndexSize) // vertexIndex
|
|
552
|
+
this.getFloat32() // u
|
|
553
|
+
this.getFloat32() // v
|
|
554
|
+
} else if (morphType === 4 || morphType === 5 || morphType === 6 || morphType === 7) {
|
|
555
|
+
// UV morph types 4-7 (additional UV channels)
|
|
556
|
+
this.getIndex(this.vertexIndexSize) // vertexIndex
|
|
557
|
+
this.getFloat32() // u
|
|
558
|
+
this.getFloat32() // v
|
|
559
|
+
} else if (morphType === 8) {
|
|
560
|
+
// Material morph
|
|
561
|
+
this.getNonVertexIndex(this.materialIndexSize) // materialIndex
|
|
562
|
+
this.getUint8() // offsetType
|
|
563
|
+
this.getFloat32() // diffuse r
|
|
564
|
+
this.getFloat32() // diffuse g
|
|
565
|
+
this.getFloat32() // diffuse b
|
|
566
|
+
this.getFloat32() // diffuse a
|
|
567
|
+
this.getFloat32() // specular r
|
|
568
|
+
this.getFloat32() // specular g
|
|
569
|
+
this.getFloat32() // specular b
|
|
570
|
+
this.getFloat32() // specular power
|
|
571
|
+
this.getFloat32() // ambient r
|
|
572
|
+
this.getFloat32() // ambient g
|
|
573
|
+
this.getFloat32() // ambient b
|
|
574
|
+
this.getFloat32() // edgeColor r
|
|
575
|
+
this.getFloat32() // edgeColor g
|
|
576
|
+
this.getFloat32() // edgeColor b
|
|
577
|
+
this.getFloat32() // edgeColor a
|
|
578
|
+
this.getFloat32() // edgeSize
|
|
579
|
+
this.getFloat32() // textureCoeff r
|
|
580
|
+
this.getFloat32() // textureCoeff g
|
|
581
|
+
this.getFloat32() // textureCoeff b
|
|
582
|
+
this.getFloat32() // textureCoeff a
|
|
583
|
+
this.getFloat32() // sphereCoeff r
|
|
584
|
+
this.getFloat32() // sphereCoeff g
|
|
585
|
+
this.getFloat32() // sphereCoeff b
|
|
586
|
+
this.getFloat32() // sphereCoeff a
|
|
587
|
+
this.getFloat32() // toonCoeff r
|
|
588
|
+
this.getFloat32() // toonCoeff g
|
|
589
|
+
this.getFloat32() // toonCoeff b
|
|
590
|
+
this.getFloat32() // toonCoeff a
|
|
591
|
+
}
|
|
540
592
|
}
|
|
541
593
|
}
|
|
594
|
+
|
|
595
|
+
this.morphs.push(morph)
|
|
542
596
|
} catch (e) {
|
|
543
|
-
// If we fail to read a morph,
|
|
597
|
+
// If we fail to read a morph, skip it
|
|
544
598
|
console.warn(`Error reading morph ${i}:`, e)
|
|
545
|
-
return false
|
|
546
599
|
}
|
|
547
600
|
}
|
|
548
|
-
return true
|
|
549
601
|
} catch (e) {
|
|
550
|
-
console.warn("Error
|
|
551
|
-
|
|
602
|
+
console.warn("Error parsing morphs:", e)
|
|
603
|
+
this.morphs = []
|
|
552
604
|
}
|
|
553
605
|
}
|
|
554
606
|
|
|
@@ -825,10 +877,10 @@ export class PmxLoader {
|
|
|
825
877
|
|
|
826
878
|
private toModel(positions: number[], normals: number[], uvs: number[], indices: number[]): Model {
|
|
827
879
|
// Create indexed vertex buffer
|
|
828
|
-
|
|
829
|
-
const vertexData = new Float32Array(vertexCount * 8)
|
|
880
|
+
// Format: [x,y,z, nx,ny,nz, u,v, x,y,z, ...]
|
|
881
|
+
const vertexData = new Float32Array(this.vertexCount * 8)
|
|
830
882
|
|
|
831
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
883
|
+
for (let i = 0; i < this.vertexCount; i++) {
|
|
832
884
|
const pi = i * 3
|
|
833
885
|
const ui = i * 2
|
|
834
886
|
const vi = i * 8
|
|
@@ -940,16 +992,54 @@ export class PmxLoader {
|
|
|
940
992
|
skinning = { joints, weights }
|
|
941
993
|
} else {
|
|
942
994
|
// Create default skinning (single bone per vertex)
|
|
943
|
-
const
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
995
|
+
const joints = new Uint16Array(this.vertexCount * 4)
|
|
996
|
+
const weights = new Uint8Array(this.vertexCount * 4)
|
|
997
|
+
for (let i = 0; i < this.vertexCount; i++) {
|
|
947
998
|
joints[i * 4] = 0
|
|
948
999
|
weights[i * 4] = 255
|
|
949
1000
|
}
|
|
950
1001
|
skinning = { joints, weights }
|
|
951
1002
|
}
|
|
952
1003
|
|
|
1004
|
+
// Create morphing data structure
|
|
1005
|
+
const morphCount = this.morphs.length
|
|
1006
|
+
// Dense buffer: morphCount * vertexCount * 3 floats (one vec3 per morph per vertex)
|
|
1007
|
+
const offsetsBuffer = new Float32Array(morphCount * this.vertexCount * 3)
|
|
1008
|
+
|
|
1009
|
+
// Initialize all offsets to zero
|
|
1010
|
+
offsetsBuffer.fill(0)
|
|
1011
|
+
|
|
1012
|
+
// Fill in actual offsets for vertex morphs
|
|
1013
|
+
for (let morphIdx = 0; morphIdx < morphCount; morphIdx++) {
|
|
1014
|
+
const morph = this.morphs[morphIdx]
|
|
1015
|
+
if (morph.type === 1) {
|
|
1016
|
+
// Vertex morph
|
|
1017
|
+
// Store offsets in dense buffer: [morph0_v0, morph0_v1, ..., morph1_v0, ...]
|
|
1018
|
+
// Each vec3 is 3 consecutive floats
|
|
1019
|
+
for (const offset of morph.vertexOffsets) {
|
|
1020
|
+
// Calculate index in the dense buffer
|
|
1021
|
+
// Layout: morphIdx * (vertexCount * 3) + vertexIndex * 3
|
|
1022
|
+
// This gives us the starting float index for this morph's vertex offset
|
|
1023
|
+
const bufferIdx = morphIdx * this.vertexCount * 3 + offset.vertexIndex * 3
|
|
1024
|
+
if (
|
|
1025
|
+
bufferIdx >= 0 &&
|
|
1026
|
+
bufferIdx + 2 < offsetsBuffer.length &&
|
|
1027
|
+
offset.vertexIndex >= 0 &&
|
|
1028
|
+
offset.vertexIndex < this.vertexCount
|
|
1029
|
+
) {
|
|
1030
|
+
offsetsBuffer[bufferIdx] = offset.positionOffset[0]
|
|
1031
|
+
offsetsBuffer[bufferIdx + 1] = offset.positionOffset[1]
|
|
1032
|
+
offsetsBuffer[bufferIdx + 2] = offset.positionOffset[2]
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const morphing: Morphing = {
|
|
1039
|
+
morphs: this.morphs,
|
|
1040
|
+
offsetsBuffer,
|
|
1041
|
+
}
|
|
1042
|
+
|
|
953
1043
|
return new Model(
|
|
954
1044
|
vertexData,
|
|
955
1045
|
indexData,
|
|
@@ -957,6 +1047,7 @@ export class PmxLoader {
|
|
|
957
1047
|
this.materials,
|
|
958
1048
|
skeleton,
|
|
959
1049
|
skinning,
|
|
1050
|
+
morphing,
|
|
960
1051
|
this.rigidbodies,
|
|
961
1052
|
this.joints
|
|
962
1053
|
)
|