From d2d83c82cbb2a2d615251e730c58661f54757057 Mon Sep 17 00:00:00 2001 From: Daan Vanden Bosch Date: Sun, 30 Jun 2019 02:07:59 +0200 Subject: [PATCH] Bone weights are now extracted from nj files. --- src/bin_data/parsing/ninja/index.ts | 1 + src/bin_data/parsing/ninja/nj.ts | 19 +++++++---- src/bin_data/parsing/ninja/xj.ts | 2 +- src/rendering/models.ts | 53 +++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/bin_data/parsing/ninja/index.ts b/src/bin_data/parsing/ninja/index.ts index 9095c7ab..e8f0b690 100644 --- a/src/bin_data/parsing/ninja/index.ts +++ b/src/bin_data/parsing/ninja/index.ts @@ -12,6 +12,7 @@ const ANGLE_TO_RAD = 2 * Math.PI / 65536; export type NinjaVertex = { position: Vec3, normal?: Vec3, + bone_weight: number, } export type NinjaModel = NjModel | XjModel; diff --git a/src/bin_data/parsing/ninja/nj.ts b/src/bin_data/parsing/ninja/nj.ts index 4c9a697f..5bf3363a 100644 --- a/src/bin_data/parsing/ninja/nj.ts +++ b/src/bin_data/parsing/ninja/nj.ts @@ -86,6 +86,7 @@ type NjVertex = { index: number, position: Vec3, normal?: Vec3, + bone_weight: number, } type NjTriangleStrip = { @@ -113,7 +114,8 @@ export function parse_nj_model(cursor: BufferCursor, cached_chunk_offsets: numbe for (const vertex of chunk.vertices) { vertices[vertex.index] = { position: vertex.position, - normal: vertex.normal + normal: vertex.normal, + bone_weight: vertex.bone_weight }; } } @@ -267,12 +269,15 @@ function parse_vertex_chunk( cursor.f32(), // x cursor.f32(), // y cursor.f32(), // z - ) + ), + bone_weight: 1 }; if (chunk_type_id === 32) { + // NJD_CV_SH cursor.seek(4); // Always 1.0 } else if (chunk_type_id === 33) { + // NJD_CV_VN_SH cursor.seek(4); // Always 1.0 vertex.normal = new Vec3( cursor.f32(), // x @@ -282,9 +287,10 @@ function parse_vertex_chunk( cursor.seek(4); // Always 0.0 } else if (35 <= chunk_type_id && chunk_type_id <= 40) { if (chunk_type_id === 37) { - // Ninja flags + // NJD_CV_NF + // NinjaFlags32 vertex.index = index + cursor.u16(); - cursor.seek(2); + vertex.bone_weight = cursor.u16() / 255; } else { // Skip user flags and material information. cursor.seek(4); @@ -298,9 +304,10 @@ function parse_vertex_chunk( if (chunk_type_id >= 42) { if (chunk_type_id === 44) { - // Ninja flags + // NJD_CV_VN_NF + // NinjaFlags32 vertex.index = index + cursor.u16(); - cursor.seek(2); + vertex.bone_weight = cursor.u16() / 255; } else { // Skip user flags and material information. cursor.seek(4); diff --git a/src/bin_data/parsing/ninja/xj.ts b/src/bin_data/parsing/ninja/xj.ts index 4d069fee..660d97bb 100644 --- a/src/bin_data/parsing/ninja/xj.ts +++ b/src/bin_data/parsing/ninja/xj.ts @@ -58,7 +58,7 @@ export function parse_xj_model(cursor: BufferCursor): XjModel { ); } - model.vertices.push({ position, normal }); + model.vertices.push({ position, normal, bone_weight: 1.0 }); } } diff --git a/src/rendering/models.ts b/src/rendering/models.ts index 07ae4aff..7815b8e6 100644 --- a/src/rendering/models.ts +++ b/src/rendering/models.ts @@ -29,9 +29,38 @@ export function ninja_object_to_skinned_mesh( return new Object3DCreator(material).create_skinned_mesh(object); } +type Vertex = { + bone_id: number, + position: Vector3, + normal?: Vector3, + bone_weight: number, +} + +class VerticesHolder { + private vertices_stack: Vertex[][] = []; + + put(vertices: Vertex[]) { + this.vertices_stack.push(vertices); + } + + get(index: number): Vertex[] { + const vertices: Vertex[] = []; + + for (let i = this.vertices_stack.length - 1; i >= 0; i--) { + const vertex = this.vertices_stack[i][index]; + + if (vertex) { + vertices.push(vertex); + } + } + + return vertices; + } +} + class Object3DCreator { private id: number = 0; - private vertices: { position: Vector3, normal?: Vector3 }[] = []; + private vertices = new VerticesHolder(); private positions: number[] = []; private normals: number[] = []; private indices: number[] = []; @@ -64,7 +93,7 @@ class Object3DCreator { create_skinned_mesh(object: NinjaObject): SkinnedMesh { const geom = this.create_buffer_geometry(object); geom.addAttribute('skinIndex', new Uint16BufferAttribute(this.bone_indices, 4)); - geom.addAttribute('skinWeight', new Uint16BufferAttribute(this.bone_weights, 4)); + geom.addAttribute('skinWeight', new Float32BufferAttribute(this.bone_weights, 4)); const mesh = new SkinnedMesh(geom, this.material); @@ -144,7 +173,7 @@ class Object3DCreator { const normal_matrix = new Matrix3().getNormalMatrix(matrix); - const new_vertices = model.vertices.map(({ position, normal }) => { + const new_vertices = model.vertices.map(({ position, normal, bone_weight }) => { const new_position = vec3_to_threejs(position); const new_normal = normal ? vec3_to_threejs(normal) : DEFAULT_NORMAL; @@ -152,21 +181,23 @@ class Object3DCreator { new_normal.applyMatrix3(normal_matrix); return { + bone_id: this.id, position: new_position, - normal: new_normal + normal: new_normal, + bone_weight }; }); - Object.assign(this.vertices, new_vertices); + this.vertices.put(new_vertices); for (const mesh of model.meshes) { for (let i = 2; i < mesh.indices.length; ++i) { const a_idx = mesh.indices[i - 2]; const b_idx = mesh.indices[i - 1]; const c_idx = mesh.indices[i]; - const a = this.vertices[a_idx]; - const b = this.vertices[b_idx]; - const c = this.vertices[c_idx]; + const a = this.vertices.get(a_idx)[0]; + const b = this.vertices.get(b_idx)[0]; + const c = this.vertices.get(c_idx)[0]; if (a && b && c) { const a_n = a.normal || DEFAULT_NORMAL; @@ -189,9 +220,9 @@ class Object3DCreator { normals.push(c_n.x, c_n.y, c_n.z); } - bone_indices.push(this.id, 0, 0, 0); - bone_indices.push(this.id, 0, 0, 0); - bone_indices.push(this.id, 0, 0, 0); + bone_indices.push(a.bone_id, 0, 0, 0); + bone_indices.push(b.bone_id, 0, 0, 0); + bone_indices.push(c.bone_id, 0, 0, 0); bone_weights.push(1, 0, 0, 0); bone_weights.push(1, 0, 0, 0); bone_weights.push(1, 0, 0, 0);