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.
@@ -1,4 +1,4 @@
1
- import { Model } from "./model";
1
+ import { Model, } from "./model";
2
2
  import { Mat4, Vec3 } from "./math";
3
3
  export class PmxLoader {
4
4
  constructor(buffer) {
@@ -17,6 +17,8 @@ export class PmxLoader {
17
17
  this.inverseBindMatrices = null;
18
18
  this.joints0 = null;
19
19
  this.weights0 = null;
20
+ this.morphs = [];
21
+ this.vertexCount = 0;
20
22
  this.rigidbodies = [];
21
23
  this.joints = [];
22
24
  this.view = new DataView(buffer);
@@ -28,12 +30,13 @@ export class PmxLoader {
28
30
  parse() {
29
31
  this.parseHeader();
30
32
  const { positions, normals, uvs } = this.parseVertices();
33
+ this.vertexCount = positions.length / 3;
31
34
  const indices = this.parseIndices();
32
35
  this.parseTextures();
33
36
  this.parseMaterials();
34
37
  this.parseBones();
35
- // Skip morphs and display frames before parsing rigidbodies
36
- this.skipMorphs();
38
+ // Parse morphs and display frames before parsing rigidbodies
39
+ this.parseMorphs();
37
40
  this.skipDisplayFrames();
38
41
  this.parseRigidbodies();
39
42
  this.parseJoints();
@@ -390,114 +393,146 @@ export class PmxLoader {
390
393
  this.bones = [];
391
394
  }
392
395
  }
393
- skipMorphs() {
396
+ parseMorphs() {
394
397
  try {
395
398
  // Check if we have enough bytes to read the count
396
399
  if (this.offset + 4 > this.view.buffer.byteLength) {
397
- return false;
400
+ this.morphs = [];
401
+ return;
398
402
  }
399
403
  const count = this.getInt32();
400
404
  if (count < 0 || count > 100000) {
401
- // Suspicious count, likely corrupted - restore offset
402
- this.offset -= 4;
403
- return false;
405
+ // Suspicious count, likely corrupted
406
+ console.warn(`Suspicious morph count: ${count}`);
407
+ this.morphs = [];
408
+ return;
404
409
  }
410
+ this.morphs = [];
405
411
  for (let i = 0; i < count; i++) {
406
412
  // Check bounds before reading each morph
407
413
  if (this.offset >= this.view.buffer.byteLength) {
408
- return false;
414
+ break;
409
415
  }
410
416
  try {
411
- this.getText(); // name
412
- this.getText(); // englishName
413
- this.getUint8(); // panelType
417
+ const name = this.getText();
418
+ this.getText(); // englishName (skip)
419
+ this.getUint8(); // panelType (skip)
414
420
  const morphType = this.getUint8();
415
421
  const offsetCount = this.getInt32();
416
- // Skip offsets based on morph type
417
- for (let j = 0; j < offsetCount; j++) {
418
- if (this.offset >= this.view.buffer.byteLength) {
419
- return false;
420
- }
421
- if (morphType === 0) {
422
- // Group morph
423
- this.getNonVertexIndex(this.morphIndexSize); // morphIndex
424
- this.getFloat32(); // ratio
425
- }
426
- else if (morphType === 1) {
427
- // Vertex morph
428
- this.getIndex(this.vertexIndexSize); // vertexIndex
429
- this.getFloat32(); // x
430
- this.getFloat32(); // y
431
- this.getFloat32(); // z
432
- }
433
- else if (morphType === 2) {
434
- // Bone morph
435
- this.getNonVertexIndex(this.boneIndexSize); // boneIndex
436
- this.getFloat32(); // x
437
- this.getFloat32(); // y
438
- this.getFloat32(); // z
439
- this.getFloat32(); // rx
440
- this.getFloat32(); // ry
441
- this.getFloat32(); // rz
442
- }
443
- else if (morphType === 3) {
444
- // UV morph
445
- this.getIndex(this.vertexIndexSize); // vertexIndex
446
- this.getFloat32(); // u
447
- this.getFloat32(); // v
422
+ const morph = {
423
+ name,
424
+ type: morphType,
425
+ vertexOffsets: [],
426
+ groupReferences: [],
427
+ };
428
+ // Parse vertex morphs (type 1)
429
+ if (morphType === 1) {
430
+ for (let j = 0; j < offsetCount; j++) {
431
+ if (this.offset >= this.view.buffer.byteLength) {
432
+ break;
433
+ }
434
+ const vertexIndex = this.getIndex(this.vertexIndexSize);
435
+ const x = this.getFloat32();
436
+ const y = this.getFloat32();
437
+ const z = this.getFloat32();
438
+ if (vertexIndex >= 0 && vertexIndex < this.vertexCount) {
439
+ morph.vertexOffsets.push({
440
+ vertexIndex,
441
+ positionOffset: [x, y, z],
442
+ });
443
+ }
448
444
  }
449
- else if (morphType === 4 || morphType === 5 || morphType === 6 || morphType === 7) {
450
- // UV morph types 4-7 (additional UV channels)
451
- this.getIndex(this.vertexIndexSize); // vertexIndex
452
- this.getFloat32(); // u
453
- this.getFloat32(); // v
445
+ }
446
+ else if (morphType === 0) {
447
+ // Parse group morphs
448
+ for (let j = 0; j < offsetCount; j++) {
449
+ if (this.offset >= this.view.buffer.byteLength) {
450
+ break;
451
+ }
452
+ const morphIndex = this.getNonVertexIndex(this.morphIndexSize);
453
+ const ratio = this.getFloat32();
454
+ if (morphIndex >= 0) {
455
+ morph.groupReferences.push({
456
+ morphIndex,
457
+ ratio,
458
+ });
459
+ }
454
460
  }
455
- else if (morphType === 8) {
456
- // Material morph
457
- this.getNonVertexIndex(this.materialIndexSize); // materialIndex
458
- this.getUint8(); // offsetType
459
- this.getFloat32(); // diffuse r
460
- this.getFloat32(); // diffuse g
461
- this.getFloat32(); // diffuse b
462
- this.getFloat32(); // diffuse a
463
- this.getFloat32(); // specular r
464
- this.getFloat32(); // specular g
465
- this.getFloat32(); // specular b
466
- this.getFloat32(); // specular power
467
- this.getFloat32(); // ambient r
468
- this.getFloat32(); // ambient g
469
- this.getFloat32(); // ambient b
470
- this.getFloat32(); // edgeColor r
471
- this.getFloat32(); // edgeColor g
472
- this.getFloat32(); // edgeColor b
473
- this.getFloat32(); // edgeColor a
474
- this.getFloat32(); // edgeSize
475
- this.getFloat32(); // textureCoeff r
476
- this.getFloat32(); // textureCoeff g
477
- this.getFloat32(); // textureCoeff b
478
- this.getFloat32(); // textureCoeff a
479
- this.getFloat32(); // sphereCoeff r
480
- this.getFloat32(); // sphereCoeff g
481
- this.getFloat32(); // sphereCoeff b
482
- this.getFloat32(); // sphereCoeff a
483
- this.getFloat32(); // toonCoeff r
484
- this.getFloat32(); // toonCoeff g
485
- this.getFloat32(); // toonCoeff b
486
- this.getFloat32(); // toonCoeff a
461
+ }
462
+ else {
463
+ // Skip other morph types for now
464
+ for (let j = 0; j < offsetCount; j++) {
465
+ if (this.offset >= this.view.buffer.byteLength) {
466
+ break;
467
+ }
468
+ if (morphType === 2) {
469
+ // Bone morph
470
+ this.getNonVertexIndex(this.boneIndexSize); // boneIndex
471
+ this.getFloat32(); // x
472
+ this.getFloat32(); // y
473
+ this.getFloat32(); // z
474
+ this.getFloat32(); // rx
475
+ this.getFloat32(); // ry
476
+ this.getFloat32(); // rz
477
+ }
478
+ else if (morphType === 3) {
479
+ // UV morph
480
+ this.getIndex(this.vertexIndexSize); // vertexIndex
481
+ this.getFloat32(); // u
482
+ this.getFloat32(); // v
483
+ }
484
+ else if (morphType === 4 || morphType === 5 || morphType === 6 || morphType === 7) {
485
+ // UV morph types 4-7 (additional UV channels)
486
+ this.getIndex(this.vertexIndexSize); // vertexIndex
487
+ this.getFloat32(); // u
488
+ this.getFloat32(); // v
489
+ }
490
+ else if (morphType === 8) {
491
+ // Material morph
492
+ this.getNonVertexIndex(this.materialIndexSize); // materialIndex
493
+ this.getUint8(); // offsetType
494
+ this.getFloat32(); // diffuse r
495
+ this.getFloat32(); // diffuse g
496
+ this.getFloat32(); // diffuse b
497
+ this.getFloat32(); // diffuse a
498
+ this.getFloat32(); // specular r
499
+ this.getFloat32(); // specular g
500
+ this.getFloat32(); // specular b
501
+ this.getFloat32(); // specular power
502
+ this.getFloat32(); // ambient r
503
+ this.getFloat32(); // ambient g
504
+ this.getFloat32(); // ambient b
505
+ this.getFloat32(); // edgeColor r
506
+ this.getFloat32(); // edgeColor g
507
+ this.getFloat32(); // edgeColor b
508
+ this.getFloat32(); // edgeColor a
509
+ this.getFloat32(); // edgeSize
510
+ this.getFloat32(); // textureCoeff r
511
+ this.getFloat32(); // textureCoeff g
512
+ this.getFloat32(); // textureCoeff b
513
+ this.getFloat32(); // textureCoeff a
514
+ this.getFloat32(); // sphereCoeff r
515
+ this.getFloat32(); // sphereCoeff g
516
+ this.getFloat32(); // sphereCoeff b
517
+ this.getFloat32(); // sphereCoeff a
518
+ this.getFloat32(); // toonCoeff r
519
+ this.getFloat32(); // toonCoeff g
520
+ this.getFloat32(); // toonCoeff b
521
+ this.getFloat32(); // toonCoeff a
522
+ }
487
523
  }
488
524
  }
525
+ this.morphs.push(morph);
489
526
  }
490
527
  catch (e) {
491
- // If we fail to read a morph, stop skipping
528
+ // If we fail to read a morph, skip it
492
529
  console.warn(`Error reading morph ${i}:`, e);
493
- return false;
494
530
  }
495
531
  }
496
- return true;
497
532
  }
498
533
  catch (e) {
499
- console.warn("Error skipping morphs:", e);
500
- return false;
534
+ console.warn("Error parsing morphs:", e);
535
+ this.morphs = [];
501
536
  }
502
537
  }
503
538
  skipDisplayFrames() {
@@ -748,9 +783,9 @@ export class PmxLoader {
748
783
  }
749
784
  toModel(positions, normals, uvs, indices) {
750
785
  // Create indexed vertex buffer
751
- const vertexCount = positions.length / 3;
752
- const vertexData = new Float32Array(vertexCount * 8);
753
- for (let i = 0; i < vertexCount; i++) {
786
+ // Format: [x,y,z, nx,ny,nz, u,v, x,y,z, ...]
787
+ const vertexData = new Float32Array(this.vertexCount * 8);
788
+ for (let i = 0; i < this.vertexCount; i++) {
754
789
  const pi = i * 3;
755
790
  const ui = i * 2;
756
791
  const vi = i * 8;
@@ -862,16 +897,48 @@ export class PmxLoader {
862
897
  }
863
898
  else {
864
899
  // Create default skinning (single bone per vertex)
865
- const vertexCount = positions.length / 3;
866
- const joints = new Uint16Array(vertexCount * 4);
867
- const weights = new Uint8Array(vertexCount * 4);
868
- for (let i = 0; i < vertexCount; i++) {
900
+ const joints = new Uint16Array(this.vertexCount * 4);
901
+ const weights = new Uint8Array(this.vertexCount * 4);
902
+ for (let i = 0; i < this.vertexCount; i++) {
869
903
  joints[i * 4] = 0;
870
904
  weights[i * 4] = 255;
871
905
  }
872
906
  skinning = { joints, weights };
873
907
  }
874
- return new Model(vertexData, indexData, this.textures, this.materials, skeleton, skinning, this.rigidbodies, this.joints);
908
+ // Create morphing data structure
909
+ const morphCount = this.morphs.length;
910
+ // Dense buffer: morphCount * vertexCount * 3 floats (one vec3 per morph per vertex)
911
+ const offsetsBuffer = new Float32Array(morphCount * this.vertexCount * 3);
912
+ // Initialize all offsets to zero
913
+ offsetsBuffer.fill(0);
914
+ // Fill in actual offsets for vertex morphs
915
+ for (let morphIdx = 0; morphIdx < morphCount; morphIdx++) {
916
+ const morph = this.morphs[morphIdx];
917
+ if (morph.type === 1) {
918
+ // Vertex morph
919
+ // Store offsets in dense buffer: [morph0_v0, morph0_v1, ..., morph1_v0, ...]
920
+ // Each vec3 is 3 consecutive floats
921
+ for (const offset of morph.vertexOffsets) {
922
+ // Calculate index in the dense buffer
923
+ // Layout: morphIdx * (vertexCount * 3) + vertexIndex * 3
924
+ // This gives us the starting float index for this morph's vertex offset
925
+ const bufferIdx = morphIdx * this.vertexCount * 3 + offset.vertexIndex * 3;
926
+ if (bufferIdx >= 0 &&
927
+ bufferIdx + 2 < offsetsBuffer.length &&
928
+ offset.vertexIndex >= 0 &&
929
+ offset.vertexIndex < this.vertexCount) {
930
+ offsetsBuffer[bufferIdx] = offset.positionOffset[0];
931
+ offsetsBuffer[bufferIdx + 1] = offset.positionOffset[1];
932
+ offsetsBuffer[bufferIdx + 2] = offset.positionOffset[2];
933
+ }
934
+ }
935
+ }
936
+ }
937
+ const morphing = {
938
+ morphs: this.morphs,
939
+ offsetsBuffer,
940
+ };
941
+ return new Model(vertexData, indexData, this.textures, this.materials, skeleton, skinning, morphing, this.rigidbodies, this.joints);
875
942
  }
876
943
  getUint8() {
877
944
  if (this.offset >= this.view.buffer.byteLength) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "A WebGPU-based MMD model renderer",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",