reze-engine 0.2.18 → 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/src/pmx-loader.ts CHANGED
@@ -1,4 +1,15 @@
1
- import { Model, Texture, Material, Bone, Skeleton, Skinning } from "./model"
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
- // Skip morphs and display frames before parsing rigidbodies
43
- this.skipMorphs()
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 skipMorphs(): boolean {
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
- return false
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 - restore offset
459
- this.offset -= 4
460
- return false
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
- return false
484
+ break
466
485
  }
467
486
  try {
468
- this.getText() // name
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
- // Skip offsets based on morph type
475
- for (let j = 0; j < offsetCount; j++) {
476
- if (this.offset >= this.view.buffer.byteLength) {
477
- return false
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
- if (morphType === 0) {
480
- // Group morph
481
- this.getNonVertexIndex(this.morphIndexSize) // morphIndex
482
- this.getFloat32() // ratio
483
- } else if (morphType === 1) {
484
- // Vertex morph
485
- this.getIndex(this.vertexIndexSize) // vertexIndex
486
- this.getFloat32() // x
487
- this.getFloat32() // y
488
- this.getFloat32() // z
489
- } else if (morphType === 2) {
490
- // Bone morph
491
- this.getNonVertexIndex(this.boneIndexSize) // boneIndex
492
- this.getFloat32() // x
493
- this.getFloat32() // y
494
- this.getFloat32() // z
495
- this.getFloat32() // rx
496
- this.getFloat32() // ry
497
- this.getFloat32() // rz
498
- } else if (morphType === 3) {
499
- // UV morph
500
- this.getIndex(this.vertexIndexSize) // vertexIndex
501
- this.getFloat32() // u
502
- this.getFloat32() // v
503
- } else if (morphType === 4 || morphType === 5 || morphType === 6 || morphType === 7) {
504
- // UV morph types 4-7 (additional UV channels)
505
- this.getIndex(this.vertexIndexSize) // vertexIndex
506
- this.getFloat32() // u
507
- this.getFloat32() // v
508
- } else if (morphType === 8) {
509
- // Material morph
510
- this.getNonVertexIndex(this.materialIndexSize) // materialIndex
511
- this.getUint8() // offsetType
512
- this.getFloat32() // diffuse r
513
- this.getFloat32() // diffuse g
514
- this.getFloat32() // diffuse b
515
- this.getFloat32() // diffuse a
516
- this.getFloat32() // specular r
517
- this.getFloat32() // specular g
518
- this.getFloat32() // specular b
519
- this.getFloat32() // specular power
520
- this.getFloat32() // ambient r
521
- this.getFloat32() // ambient g
522
- this.getFloat32() // ambient b
523
- this.getFloat32() // edgeColor r
524
- this.getFloat32() // edgeColor g
525
- this.getFloat32() // edgeColor b
526
- this.getFloat32() // edgeColor a
527
- this.getFloat32() // edgeSize
528
- this.getFloat32() // textureCoeff r
529
- this.getFloat32() // textureCoeff g
530
- this.getFloat32() // textureCoeff b
531
- this.getFloat32() // textureCoeff a
532
- this.getFloat32() // sphereCoeff r
533
- this.getFloat32() // sphereCoeff g
534
- this.getFloat32() // sphereCoeff b
535
- this.getFloat32() // sphereCoeff a
536
- this.getFloat32() // toonCoeff r
537
- this.getFloat32() // toonCoeff g
538
- this.getFloat32() // toonCoeff b
539
- this.getFloat32() // toonCoeff a
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, stop skipping
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 skipping morphs:", e)
551
- return false
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
- const vertexCount = positions.length / 3
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 vertexCount = positions.length / 3
944
- const joints = new Uint16Array(vertexCount * 4)
945
- const weights = new Uint8Array(vertexCount * 4)
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
  )