|
@@ -1,720 +0,0 @@
|
|
|
-
|
|
|
-///if arm_skin
|
|
|
-
|
|
|
-type anim_bone_t = {
|
|
|
- base?: anim_raw_t;
|
|
|
- object?: mesh_object_t;
|
|
|
- data?: mesh_data_t;
|
|
|
- skin_buffer?: f32_array_t;
|
|
|
- skeleton_bones?: obj_t[];
|
|
|
- skeleton_mats?: mat4_t[];
|
|
|
- skeleton_bones_blend?: obj_t[];
|
|
|
- skeleton_mats_blend?: mat4_t[];
|
|
|
- abs_mats?: mat4_t[];
|
|
|
- apply_parent?: bool[];
|
|
|
- mats_fast?: mat4_t[];
|
|
|
- mats_fast_sort?: i32[];
|
|
|
- mats_fast_blend?: mat4_t[];
|
|
|
- mats_fast_blend_sort?: i32[];
|
|
|
- bone_children?: map_t<string, object_t[]>; // Parented to bone
|
|
|
- // Do inverse kinematics here
|
|
|
- on_updates?: (()=>void)[];
|
|
|
-};
|
|
|
-
|
|
|
-let _anim_bone_skin_max_bones: i32 = 128;
|
|
|
-let _anim_bone_m: mat4_t = mat4_identity(); // Skinning matrix
|
|
|
-let _anim_bone_m1: mat4_t = mat4_identity();
|
|
|
-let _anim_bone_m2: mat4_t = mat4_identity();
|
|
|
-let _anim_bone_bm: mat4_t = mat4_identity(); // Absolute bone matrix
|
|
|
-let _anim_bone_wm: mat4_t = mat4_identity();
|
|
|
-let _anim_bone_vpos: vec4_t = vec4_create();
|
|
|
-let _anim_bone_vscale: vec4_t = vec4_create();
|
|
|
-let _anim_bone_q1: quat_t = quat_create();
|
|
|
-let _anim_bone_q2: quat_t = quat_create();
|
|
|
-let _anim_bone_q3: quat_t = quat_create();
|
|
|
-let _anim_bone_vpos2: vec4_t = vec4_create();
|
|
|
-let _anim_bone_vscale2: vec4_t = vec4_create();
|
|
|
-let _anim_bone_v1: vec4_t = vec4_create();
|
|
|
-let _anim_bone_v2: vec4_t = vec4_create();
|
|
|
-
|
|
|
-function anim_bone_create(armature_name: string = ""): anim_bone_t {
|
|
|
- let raw: anim_bone_t = {};
|
|
|
- raw.mats_fast = [];
|
|
|
- raw.mats_fast_sort = [];
|
|
|
- raw.mats_fast_blend = [];
|
|
|
- raw.mats_fast_blend_sort = [];
|
|
|
- raw.base = anim_create();
|
|
|
- raw.base.ext = raw;
|
|
|
- raw.base.ext_type = "anim_bone_t";
|
|
|
-
|
|
|
- for (let i: i32 = 0; i < scene_armatures.length; ++i) {
|
|
|
- let a: armature_t = scene_armatures[i];
|
|
|
- if (a.name == armature_name) {
|
|
|
- raw.base.armature = a;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return raw;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_set_skin(raw: anim_bone_t, mo: mesh_object_t) {
|
|
|
- raw.object = mo;
|
|
|
- raw.data = mo != null ? mo.data : null;
|
|
|
- raw.base.is_skinned = raw.data != null ? raw.data.skin != null : false;
|
|
|
- if (raw.base.is_skinned) {
|
|
|
- let bone_size: i32 = 8; // Dual-quat skinning
|
|
|
- raw.skin_buffer = f32_array_create(_anim_bone_skin_max_bones * bone_size);
|
|
|
- for (let i: i32 = 0; i < raw.skin_buffer.length; ++i) {
|
|
|
- raw.skin_buffer[i] = 0;
|
|
|
- }
|
|
|
- // Rotation is already applied to skin at export
|
|
|
- raw.object.base.transform.rot = quat_create(0, 0, 0, 1);
|
|
|
- transform_build_matrix(raw.object.base.transform);
|
|
|
-
|
|
|
- let refs: string[] = mo.base.parent.raw.anim.bone_actions;
|
|
|
- if (refs != null && refs.length > 0) {
|
|
|
- let action: scene_t = data_get_scene_raw(refs[0]);
|
|
|
- anim_bone_play(raw, action.name);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_add_bone_child(raw: anim_bone_t, bone: string, o: object_t) {
|
|
|
- if (raw.bone_children == null) {
|
|
|
- raw.bone_children = map_create();
|
|
|
- }
|
|
|
- let ar: object_t[] = map_get(raw.bone_children, bone);
|
|
|
- if (ar == null) {
|
|
|
- ar = [];
|
|
|
- map_set(raw.bone_children, bone, ar);
|
|
|
- }
|
|
|
- array_push(ar, o);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_remove_bone_child(raw: anim_bone_t, bone: string, o: object_t) {
|
|
|
- if (raw.bone_children != null) {
|
|
|
- let ar: object_t[] = map_get(raw.bone_children, bone);
|
|
|
- if (ar != null) {
|
|
|
- array_remove(ar, o);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_update_bone_children(raw: anim_bone_t, bone: obj_t, bm: mat4_t) {
|
|
|
- let ar: object_t[] = map_get(raw.bone_children, bone.name);
|
|
|
- if (ar == null) {
|
|
|
- return;
|
|
|
- }
|
|
|
- for (let i: i32 = 0; i < ar.length; ++i) {
|
|
|
- let o: object_t = ar[i];
|
|
|
- let t: transform_t = o.transform;
|
|
|
- if (t.bone_parent == null) {
|
|
|
- t.bone_parent = mat4_identity();
|
|
|
- }
|
|
|
- if (o.raw.anim.parent_bone_tail != null) {
|
|
|
- if (o.raw.anim.parent_bone_connected || raw.base.is_skinned) {
|
|
|
- let v: f32_array_t = o.raw.anim.parent_bone_tail;
|
|
|
- t.bone_parent = mat4_init_translate(v[0], v[1], v[2]);
|
|
|
- t.bone_parent = mat4_mult_mat(t.bone_parent, bm);
|
|
|
- }
|
|
|
- else {
|
|
|
- let v: f32_array_t = o.raw.anim.parent_bone_tail_pose;
|
|
|
- t.bone_parent = mat4_clone(bm);
|
|
|
- t.bone_parent = mat4_translate(t.bone_parent, v[0], v[1], v[2]);
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- t.bone_parent = mat4_clone(bm);
|
|
|
- }
|
|
|
- transform_build_matrix(t);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_num_parents(b: obj_t): i32 {
|
|
|
- let i: i32 = 0;
|
|
|
- let p: obj_t = b.parent;
|
|
|
- while (p != null) {
|
|
|
- i++;
|
|
|
- p = p.parent;
|
|
|
- }
|
|
|
- return i;
|
|
|
-}
|
|
|
-
|
|
|
-let _anim_bone_sort_data: any;
|
|
|
-
|
|
|
-function anim_bone_sort(pa: any_ptr, pb: any_ptr) {
|
|
|
- let a: i32 = DEREFERENCE(pa);
|
|
|
- let b: i32 = DEREFERENCE(pb);
|
|
|
- let i: i32 = anim_bone_num_parents(_anim_bone_sort_data[a]);
|
|
|
- let j: i32 = anim_bone_num_parents(_anim_bone_sort_data[b]);
|
|
|
- return i < j ? -1 : i > j ? 1 : 0;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_set_mats(raw: anim_bone_t) {
|
|
|
- while (raw.mats_fast.length < raw.skeleton_bones.length) {
|
|
|
- array_push(raw.mats_fast, mat4_identity());
|
|
|
- array_push(raw.mats_fast_sort, raw.mats_fast_sort.length);
|
|
|
- }
|
|
|
- // Calc bones with 0 parents first
|
|
|
- _anim_bone_sort_data = raw.skeleton_bones;
|
|
|
- array_sort(raw.mats_fast_sort, anim_bone_sort);
|
|
|
-
|
|
|
- if (raw.skeleton_bones_blend != null) {
|
|
|
- while (raw.mats_fast_blend.length < raw.skeleton_bones_blend.length) {
|
|
|
- array_push(raw.mats_fast_blend, mat4_identity());
|
|
|
- array_push(raw.mats_fast_blend_sort, raw.mats_fast_blend_sort.length);
|
|
|
- }
|
|
|
- _anim_bone_sort_data = raw.skeleton_bones_blend;
|
|
|
- array_sort(raw.mats_fast_blend_sort, anim_bone_sort);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_set_action(raw: anim_bone_t, action: string) {
|
|
|
- if (raw.base.is_skinned) {
|
|
|
- raw.skeleton_bones = map_get(raw.data._actions, action);
|
|
|
- raw.skeleton_mats = map_get(raw.data._mats, action);
|
|
|
- raw.skeleton_bones_blend = null;
|
|
|
- raw.skeleton_mats_blend = null;
|
|
|
- }
|
|
|
- else {
|
|
|
- armature_init_mats(raw.base.armature);
|
|
|
- let a = armature_get_action(raw.base.armature, action);
|
|
|
- raw.skeleton_bones = a.bones;
|
|
|
- raw.skeleton_mats = a.mats;
|
|
|
- }
|
|
|
- anim_bone_set_mats(raw);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_set_action_blend(raw: anim_bone_t, action: string) {
|
|
|
- if (raw.base.is_skinned) {
|
|
|
- raw.skeleton_bones_blend = raw.skeleton_bones;
|
|
|
- raw.skeleton_mats_blend = raw.skeleton_mats;
|
|
|
- raw.skeleton_bones = map_get(raw.data._actions, action);
|
|
|
- raw.skeleton_mats = map_get(raw.data._mats, action);
|
|
|
- }
|
|
|
- else {
|
|
|
- armature_init_mats(raw.base.armature);
|
|
|
- let a: armature_action_t = armature_get_action(raw.base.armature, action);
|
|
|
- raw.skeleton_bones = a.bones;
|
|
|
- raw.skeleton_mats = a.mats;
|
|
|
- }
|
|
|
- anim_bone_set_mats(raw);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_mult_parent(raw: anim_bone_t, i: i32, fasts: mat4_t[], bones: obj_t[], mats: mat4_t[]) {
|
|
|
- let f: mat4_t = fasts[i];
|
|
|
- if (raw.apply_parent != null && !raw.apply_parent[i]) {
|
|
|
- f = mat4_clone(mats[i]);
|
|
|
- return;
|
|
|
- }
|
|
|
- let p = bones[i].parent;
|
|
|
- let bi = anim_bone_get_bone_index(raw, p, bones);
|
|
|
- if (p == null || bi == -1) {
|
|
|
- f = mat4_clone(mats[i]);
|
|
|
- }
|
|
|
- else {
|
|
|
- f = mat4_mult_mat(mats[i], fasts[bi]);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_mult_parents(raw: anim_bone_t, m: mat4_t, i: i32, bones: obj_t[], mats: mat4_t[]) {
|
|
|
- let bone: obj_t = bones[i];
|
|
|
- let p: obj_t = bone.parent;
|
|
|
- while (p != null) {
|
|
|
- let i: i32 = anim_bone_get_bone_index(raw, p, bones);
|
|
|
- if (i == -1) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- m = mat4_mult_mat(m, mats[i]);
|
|
|
- p = p.parent;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_notify_on_update(raw: anim_bone_t, f: ()=>void) {
|
|
|
- if (raw.on_updates == null) {
|
|
|
- raw.on_updates = [];
|
|
|
- }
|
|
|
- array_push(raw.on_updates, f);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_remove_update(raw: anim_bone_t, f: ()=>void) {
|
|
|
- array_remove(raw.on_updates, f);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_update_bones_only(raw: anim_bone_t) {
|
|
|
- if (raw.bone_children != null) {
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones.length; ++i) {
|
|
|
- let b = raw.skeleton_bones[i]; // TODO: blend_time > 0
|
|
|
- _anim_bone_m = mat4_clone(raw.mats_fast[i]);
|
|
|
- anim_bone_update_bone_children(raw, b, _anim_bone_m);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_update_skin_gpu(raw: anim_bone_t) {
|
|
|
- let bones: obj_t[] = raw.skeleton_bones;
|
|
|
-
|
|
|
- let s: f32 = raw.base.blend_current / raw.base.blend_time;
|
|
|
- s = s * s * (3.0 - 2.0 * s); // Smoothstep
|
|
|
- if (raw.base.blend_factor != 0.0) {
|
|
|
- s = 1.0 - raw.base.blend_factor;
|
|
|
- }
|
|
|
-
|
|
|
- // Update skin buffer
|
|
|
- for (let i: i32 = 0; i < bones.length; ++i) {
|
|
|
- _anim_bone_m = mat4_clone(raw.mats_fast[i]);
|
|
|
-
|
|
|
- if (raw.base.blend_time > 0 && raw.skeleton_bones_blend != null) {
|
|
|
- // Decompose
|
|
|
- _anim_bone_m1 = mat4_clone(raw.mats_fast_blend[i]);
|
|
|
- mat4_decompose(_anim_bone_m1, _anim_bone_vpos, _anim_bone_q1, _anim_bone_vscale);
|
|
|
- mat4_decompose(_anim_bone_m, _anim_bone_vpos2, _anim_bone_q2, _anim_bone_vscale2);
|
|
|
-
|
|
|
- // Lerp
|
|
|
- _anim_bone_v1 = vec4_lerp(_anim_bone_vpos, _anim_bone_vpos2, s);
|
|
|
- _anim_bone_v2 = vec4_lerp(_anim_bone_vscale, _anim_bone_vscale2, s);
|
|
|
- _anim_bone_q3 = quat_lerp(_anim_bone_q1, _anim_bone_q2, s);
|
|
|
-
|
|
|
- // Compose
|
|
|
- _anim_bone_m = mat4_from_quat(_anim_bone_q3);
|
|
|
- _anim_bone_m = mat4_scale(_anim_bone_m, _anim_bone_v2);
|
|
|
- _anim_bone_m.m30 = _anim_bone_v1.x;
|
|
|
- _anim_bone_m.m31 = _anim_bone_v1.y;
|
|
|
- _anim_bone_m.m32 = _anim_bone_v1.z;
|
|
|
- }
|
|
|
-
|
|
|
- if (raw.abs_mats != null && i < raw.abs_mats.length) {
|
|
|
- raw.abs_mats[i] = mat4_clone(_anim_bone_m);
|
|
|
- }
|
|
|
- if (raw.bone_children != null) {
|
|
|
- anim_bone_update_bone_children(raw, bones[i], _anim_bone_m);
|
|
|
- }
|
|
|
-
|
|
|
- _anim_bone_m = mat4_mult_mat(raw.data._skeleton_transforms_inv[i], _anim_bone_m);
|
|
|
- anim_bone_update_skin_buffer(raw, _anim_bone_m, i);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_update_skin_buffer(raw: anim_bone_t, m: mat4_t, i: i32) {
|
|
|
- // Dual quat skinning
|
|
|
- mat4_decompose(m, _anim_bone_vpos, _anim_bone_q1, _anim_bone_vscale);
|
|
|
- _anim_bone_q1 = quat_norm(_anim_bone_q1);
|
|
|
- _anim_bone_q2 = quat_create(_anim_bone_vpos.x, _anim_bone_vpos.y, _anim_bone_vpos.z, 0.0);
|
|
|
- _anim_bone_q2 = quat_mult(_anim_bone_q2, _anim_bone_q1);
|
|
|
- raw.skin_buffer[i * 8] = _anim_bone_q1.x; // Real
|
|
|
- raw.skin_buffer[i * 8 + 1] = _anim_bone_q1.y;
|
|
|
- raw.skin_buffer[i * 8 + 2] = _anim_bone_q1.z;
|
|
|
- raw.skin_buffer[i * 8 + 3] = _anim_bone_q1.w;
|
|
|
- raw.skin_buffer[i * 8 + 4] = _anim_bone_q2.x * 0.5; // Dual
|
|
|
- raw.skin_buffer[i * 8 + 5] = _anim_bone_q2.y * 0.5;
|
|
|
- raw.skin_buffer[i * 8 + 6] = _anim_bone_q2.z * 0.5;
|
|
|
- raw.skin_buffer[i * 8 + 7] = _anim_bone_q2.w * 0.5;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_bone(raw: anim_bone_t, name: string): obj_t {
|
|
|
- if (raw.skeleton_bones == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones.length; ++i) {
|
|
|
- let b: obj_t = raw.skeleton_bones[i];
|
|
|
- if (b.name == name) {
|
|
|
- return b;
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_bone_index(raw: anim_bone_t, bone: obj_t, bones: obj_t[] = null): i32 {
|
|
|
- if (bones == null) {
|
|
|
- bones = raw.skeleton_bones;
|
|
|
- }
|
|
|
- if (bones != null) {
|
|
|
- for (let i: i32 = 0; i < bones.length; ++i) {
|
|
|
- if (bones[i] == bone) {
|
|
|
- return i;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_bone_mat(raw: anim_bone_t, bone: obj_t): mat4_t {
|
|
|
- return raw.skeleton_mats != null ? raw.skeleton_mats[anim_bone_get_bone_index(raw, bone)] : null;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_bone_mat_blend(raw: anim_bone_t, bone: obj_t): mat4_t {
|
|
|
- return raw.skeleton_mats_blend != null ? raw.skeleton_mats_blend[anim_bone_get_bone_index(raw, bone)] : null;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_abs_mat(raw: anim_bone_t, bone: obj_t): mat4_t {
|
|
|
- // With applied blending
|
|
|
- if (raw.skeleton_mats == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (raw.abs_mats == null) {
|
|
|
- raw.abs_mats = [];
|
|
|
- while (raw.abs_mats.length < raw.skeleton_mats.length) {
|
|
|
- array_push(raw.abs_mats, mat4_identity());
|
|
|
- }
|
|
|
- }
|
|
|
- return raw.abs_mats[anim_bone_get_bone_index(raw, bone)];
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_world_mat(raw: anim_bone_t, bone: obj_t): mat4_t {
|
|
|
- if (raw.skeleton_mats == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (raw.apply_parent == null) {
|
|
|
- raw.apply_parent = [];
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_mats.length; ++i) {
|
|
|
- array_push(raw.apply_parent, true);
|
|
|
- }
|
|
|
- }
|
|
|
- let i: i32 = anim_bone_get_bone_index(raw, bone);
|
|
|
- _anim_bone_wm = mat4_clone(raw.skeleton_mats[i]);
|
|
|
- anim_bone_mult_parents(raw, _anim_bone_wm, i, raw.skeleton_bones, raw.skeleton_mats);
|
|
|
- // anim_bone_wm = mat4_clone(raw.mats_fast[i]); // TODO
|
|
|
- return _anim_bone_wm;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_get_bone_len(raw: anim_bone_t, bone: obj_t): f32 {
|
|
|
- let refs: string[] = raw.data.skin.bone_ref_array;
|
|
|
- let lens: f32_array_t = raw.data.skin.bone_len_array;
|
|
|
- for (let i: i32 = 0; i < refs.length; ++i) {
|
|
|
- if (refs[i] == bone.name) {
|
|
|
- return lens[i];
|
|
|
- }
|
|
|
- }
|
|
|
- return 0.0;
|
|
|
-}
|
|
|
-
|
|
|
-// Returns bone length with scale applied
|
|
|
-function anim_bone_get_bone_abs_len(raw: anim_bone_t, bone: obj_t): f32 {
|
|
|
- let refs: string[] = raw.data.skin.bone_ref_array;
|
|
|
- let lens: f32_array_t = raw.data.skin.bone_len_array;
|
|
|
- let scale: f32 = mat4_get_scale(raw.object.base.parent.transform.world).z;
|
|
|
- for (let i: i32 = 0; i < refs.length; ++i) {
|
|
|
- if (refs[i] == bone.name) {
|
|
|
- return lens[i] * scale;
|
|
|
- }
|
|
|
- }
|
|
|
- return 0.0;
|
|
|
-}
|
|
|
-
|
|
|
-// Returns bone matrix in world space
|
|
|
-function anim_bone_get_abs_world_mat(raw: anim_bone_t, bone: obj_t): mat4_t {
|
|
|
- let wm = anim_bone_get_world_mat(raw, bone);
|
|
|
- wm = mat4_mult_mat(wm, raw.object.base.parent.transform.world);
|
|
|
- return wm;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_solve_ik(raw: anim_bone_t, effector: obj_t, goal: vec4_t, precision: f32 = 0.01, max_iters: i32 = 100, chain_lenght: i32 = 100, roll_angle: f32 = 0.0) {
|
|
|
- // Array of bones to solve IK for, effector at 0
|
|
|
- let bones: obj_t[] = [];
|
|
|
-
|
|
|
- // Array of bones lengths, effector length at 0
|
|
|
- let lengths: f32[] = [];
|
|
|
-
|
|
|
- // Array of bones matrices in world coordinates, effector at 0
|
|
|
- let bone_world_mats: mat4_t[];
|
|
|
-
|
|
|
- let temp_loc: vec4_t = vec4_create();
|
|
|
- let temp_rot: quat_t = quat_create();
|
|
|
- let temp_rot2: quat_t = quat_create();
|
|
|
- let temp_scale: vec4_t = vec4_create();
|
|
|
- let roll: quat_t = quat_from_euler(0, roll_angle, 0);
|
|
|
-
|
|
|
- // Store all bones and lengths in array
|
|
|
- let tip: obj_t = effector;
|
|
|
- array_push(bones, tip);
|
|
|
- array_push(lengths, anim_bone_get_bone_abs_len(raw, tip));
|
|
|
- let root: obj_t = tip;
|
|
|
-
|
|
|
- while (root.parent != null) {
|
|
|
- if (bones.length > chain_lenght - 1) {
|
|
|
- break;
|
|
|
- }
|
|
|
- array_push(bones, root.parent);
|
|
|
- array_push(lengths, anim_bone_get_bone_abs_len(raw, root.parent));
|
|
|
- root = root.parent;
|
|
|
- }
|
|
|
-
|
|
|
- // Root bone
|
|
|
- root = bones[bones.length - 1];
|
|
|
-
|
|
|
- // World matrix of root bone
|
|
|
- let root_world_mat: mat4_t = mat4_clone(anim_bone_get_world_mat(raw, root));
|
|
|
- // World matrix of armature
|
|
|
- let armature_mat: mat4_t = mat4_clone(raw.object.base.parent.transform.world);
|
|
|
- // Apply armature transform to world matrix
|
|
|
- root_world_mat = mat4_mult_mat(root_world_mat, armature_mat);
|
|
|
- // Distance from root to goal
|
|
|
- let dist: f32 = vec4_dist(goal, mat4_get_loc(root_world_mat));
|
|
|
-
|
|
|
- // Total bones length
|
|
|
- let total_length: f32 = 0.0;
|
|
|
- for (let i: i32 = 0; i < lengths.length; ++i) {
|
|
|
- let l: f32 = lengths[i];
|
|
|
- total_length += l;
|
|
|
- }
|
|
|
-
|
|
|
- // Unreachable distance
|
|
|
- if (dist > total_length) {
|
|
|
- // Calculate unit vector from root to goal
|
|
|
- let new_look: vec4_t = vec4_clone(goal);
|
|
|
- new_look = vec4_sub(new_look, mat4_get_loc(root_world_mat));
|
|
|
- new_look = vec4_norm(new_look);
|
|
|
-
|
|
|
- // Rotate root bone to point at goal
|
|
|
- mat4_decompose(root_world_mat, temp_loc, temp_rot, temp_scale);
|
|
|
- temp_rot2 = quat_from_to(vec4_norm(mat4_look(root_world_mat)), new_look);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, temp_rot);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, roll);
|
|
|
- root_world_mat = mat4_compose(temp_loc, temp_rot2, temp_scale);
|
|
|
-
|
|
|
- // Set bone matrix in local space from world space
|
|
|
- anim_bone_set_bone_mat_from_world_mat(raw, root_world_mat, root);
|
|
|
-
|
|
|
- // Set child bone rotations to zero
|
|
|
- for (let i: i32 = 0; i < bones.length - 1; ++i) {
|
|
|
- mat4_decompose(anim_bone_get_bone_mat(raw, bones[i]), temp_loc, temp_rot, temp_scale);
|
|
|
- mat4_compose(anim_bone_get_bone_mat(raw, bones[i]), temp_loc, roll, temp_scale);
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // Get all bone mats in world space
|
|
|
- bone_world_mats = anim_bone_get_world_mats_fast(raw, effector, bones.length);
|
|
|
-
|
|
|
- // Array of bone locations in world space, root location at [0]
|
|
|
- let bone_world_locs: vec4_t[] = [];
|
|
|
- for (let i: i32 = 0; i < bone_world_mats.length; ++i) {
|
|
|
- let b: mat4_t = bone_world_mats[i];
|
|
|
- array_push(bone_world_locs, mat4_get_loc(b));
|
|
|
- }
|
|
|
-
|
|
|
- // Solve FABRIK
|
|
|
- let vec: vec4_t = vec4_create();
|
|
|
- let start_loc: vec4_t = vec4_clone(bone_world_locs[0]);
|
|
|
- let l: i32 = bone_world_locs.length;
|
|
|
-
|
|
|
- for (let iter: i32 = 0; iter < max_iters; ++iter) {
|
|
|
- // Backward
|
|
|
- vec = vec4_clone(goal);
|
|
|
- vec = vec4_sub(vec, bone_world_locs[l - 1]);
|
|
|
- vec = vec4_norm(vec);
|
|
|
- vec = vec4_mult(vec, lengths[0]);
|
|
|
- bone_world_locs[l - 1] = vec4_clone(goal);
|
|
|
- bone_world_locs[l - 1] = vec4_sub(bone_world_locs[l - 1], vec);
|
|
|
-
|
|
|
- for (let j: i32 = 1; j < l; ++j) {
|
|
|
- vec = vec4_clone(bone_world_locs[l - 1 - j]);
|
|
|
- vec = vec4_sub(vec, bone_world_locs[l - j]);
|
|
|
- vec = vec4_norm(vec);
|
|
|
- vec = vec4_mult(vec, lengths[j]);
|
|
|
- bone_world_locs[l - 1 - j] = vec4_clone(bone_world_locs[l - j]);
|
|
|
- bone_world_locs[l - 1 - j] = vec4_add(bone_world_locs[l - 1 - j], vec);
|
|
|
- }
|
|
|
-
|
|
|
- // Forward
|
|
|
- bone_world_locs[0] = vec4_clone(start_loc);
|
|
|
- for (let j: i32 = 1; j < l; ++j) {
|
|
|
- vec = vec4_clone(bone_world_locs[j]);
|
|
|
- vec = vec4_sub(vec, bone_world_locs[j - 1]);
|
|
|
- vec = vec4_norm(vec);
|
|
|
- vec = vec4_mult(vec, lengths[l - j]);
|
|
|
- bone_world_locs[j] = vec4_clone(bone_world_locs[j - 1]);
|
|
|
- bone_world_locs[j] = vec4_add(bone_world_locs[j], vec);
|
|
|
- }
|
|
|
-
|
|
|
- if (vec4_dist(bone_world_locs[l - 1], goal) - lengths[0] <= precision) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Correct rotations
|
|
|
- // Applying locations and rotations
|
|
|
- let temp_look: vec4_t = vec4_create();
|
|
|
- let temp_loc2: vec4_t = vec4_create();
|
|
|
-
|
|
|
- for (let i: i32 = 0; i < l - 1; ++i) {
|
|
|
- // Decompose matrix
|
|
|
- mat4_decompose(bone_world_mats[i], temp_loc, temp_rot, temp_scale);
|
|
|
-
|
|
|
- // Rotate to point to parent bone
|
|
|
- temp_loc2 = vec4_clone(bone_world_locs[i + 1]);
|
|
|
- temp_loc2 = vec4_sub(temp_loc2, bone_world_locs[i]);
|
|
|
- temp_loc2 = vec4_norm(temp_loc2);
|
|
|
- temp_look = vec4_clone(mat4_look(bone_world_mats[i]));
|
|
|
- temp_look = vec4_norm(temp_look);
|
|
|
- temp_rot2 = quat_from_to(temp_look, temp_loc2);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, temp_rot);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, roll);
|
|
|
-
|
|
|
- // Compose matrix with new rotation and location
|
|
|
- bone_world_mats[i] = mat4_compose(bone_world_locs[i], temp_rot2, temp_scale);
|
|
|
-
|
|
|
- // Set bone matrix in local space from world space
|
|
|
- anim_bone_set_bone_mat_from_world_mat(raw, bone_world_mats[i], bones[bones.length - 1 - i]);
|
|
|
- }
|
|
|
-
|
|
|
- // Decompose matrix
|
|
|
- mat4_decompose(bone_world_mats[l - 1], temp_loc, temp_rot, temp_scale);
|
|
|
-
|
|
|
- // Rotate to point to goal
|
|
|
- temp_loc2 = vec4_clone(goal);
|
|
|
- temp_loc2 = vec4_sub(temp_loc2, temp_loc);
|
|
|
- temp_loc2 = vec4_norm(temp_loc2);
|
|
|
- temp_look = vec4_clone(mat4_look(bone_world_mats[l - 1]));
|
|
|
- temp_look = vec4_norm(temp_look);
|
|
|
- temp_rot2 = quat_from_to(temp_look, temp_loc2);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, temp_rot);
|
|
|
- temp_rot2 = quat_mult(temp_rot2, roll);
|
|
|
-
|
|
|
- // Compose matrix with new rotation and location
|
|
|
- bone_world_mats[l - 1] = mat4_compose(bone_world_locs[l - 1], temp_rot2, temp_scale);
|
|
|
-
|
|
|
- // Set bone matrix in local space from world space
|
|
|
- anim_bone_set_bone_mat_from_world_mat(raw, bone_world_mats[l - 1], bones[0]);
|
|
|
-}
|
|
|
-
|
|
|
-// Returns an array of bone matrices in world space
|
|
|
-function anim_bone_get_world_mats_fast(raw: anim_bone_t, tip: obj_t, chain_len: i32): mat4_t[] {
|
|
|
- let wm_array: mat4_t[] = [];
|
|
|
- let root: obj_t = tip;
|
|
|
- let num_p: i32 = chain_len;
|
|
|
- for (let i: i32 = 0; i < chain_len; ++i) {
|
|
|
- let wm: mat4_t = anim_bone_get_abs_world_mat(raw, root);
|
|
|
- wm_array[chain_len - 1 - i] = mat4_clone(wm);
|
|
|
- root = root.parent;
|
|
|
- num_p--;
|
|
|
- }
|
|
|
-
|
|
|
- // Root bone at [0]
|
|
|
- return wm_array;
|
|
|
-}
|
|
|
-
|
|
|
-// Set bone transforms in world space
|
|
|
-function anim_bone_set_bone_mat_from_world_mat(raw: anim_bone_t, wm: mat4_t, bone: obj_t) {
|
|
|
- let inv_mat: mat4_t = mat4_identity();
|
|
|
- let temp_mat: mat4_t = mat4_clone(wm);
|
|
|
- inv_mat = mat4_inv(raw.object.base.parent.transform.world);
|
|
|
- temp_mat = mat4_mult_mat(temp_mat, inv_mat);
|
|
|
- let bones: obj_t[] = [];
|
|
|
- let p_bone: obj_t = bone;
|
|
|
- while (p_bone.parent != null) {
|
|
|
- array_push(bones, p_bone.parent);
|
|
|
- p_bone = p_bone.parent;
|
|
|
- }
|
|
|
-
|
|
|
- for (let i: i32 = 0; i < bones.length; ++i) {
|
|
|
- let x: i32 = bones.length - 1;
|
|
|
- inv_mat = mat4_inv(anim_bone_get_bone_mat(raw, bones[x - i]));
|
|
|
- temp_mat = mat4_mult_mat(temp_mat, inv_mat);
|
|
|
- }
|
|
|
-
|
|
|
- mat4_set_from(anim_bone_get_bone_mat(raw, bone), temp_mat);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_play(raw: anim_bone_t, action: string = "", on_complete: ()=>void = null, blend_time: f32 = 0.2, speed: f32 = 1.0, loop: bool = true) {
|
|
|
- if (action != "") {
|
|
|
- blend_time > 0 ? anim_bone_set_action_blend(raw, action) : anim_bone_set_action(raw, action);
|
|
|
- }
|
|
|
- raw.base.blend_factor = 0.0;
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_blend(raw: anim_bone_t, action1: string, action2: string, factor: f32) {
|
|
|
- if (factor == 0.0) {
|
|
|
- anim_bone_set_action(raw, action1);
|
|
|
- return;
|
|
|
- }
|
|
|
- anim_bone_set_action(raw, action2);
|
|
|
- anim_bone_set_action_blend(raw, action1);
|
|
|
-
|
|
|
- anim_blend_super(raw.base, action1, action2, factor);
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_update(raw: anim_bone_t, delta: f32) {
|
|
|
- if (!raw.base.is_skinned && raw.skeleton_bones == null) {
|
|
|
- anim_bone_set_action(raw, raw.base.armature.actions[0].name);
|
|
|
- }
|
|
|
- if (raw.object != null && (!raw.object.base.visible || raw.object.base.culled)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (raw.skeleton_bones == null || raw.skeleton_bones.length == 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- anim_update_super(raw.base, delta);
|
|
|
-
|
|
|
- if (raw.base.paused || raw.base.speed == 0.0) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let last_bones: obj_t[] = raw.skeleton_bones;
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones.length; ++i) {
|
|
|
- let b: obj_t = raw.skeleton_bones[i];
|
|
|
- if (b.anim != null) {
|
|
|
- anim_update_track(raw.base, b.anim);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- // Action has been changed by on_complete
|
|
|
- if (last_bones != raw.skeleton_bones) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones.length; ++i) {
|
|
|
- anim_update_anim_sampled(raw.base, raw.skeleton_bones[i].anim, raw.skeleton_mats[i]);
|
|
|
- }
|
|
|
- if (raw.base.blend_time > 0 && raw.skeleton_bones_blend != null) {
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones_blend.length; ++i) {
|
|
|
- let b: obj_t = raw.skeleton_bones_blend[i];
|
|
|
- if (b.anim != null) {
|
|
|
- anim_update_track(raw.base, b.anim);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones_blend.length; ++i) {
|
|
|
- anim_update_anim_sampled(raw.base, raw.skeleton_bones_blend[i].anim, raw.skeleton_mats_blend[i]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Do forward kinematics and inverse kinematics here
|
|
|
- if (raw.on_updates != null) {
|
|
|
- let i: i32 = 0;
|
|
|
- let l: i32 = raw.on_updates.length;
|
|
|
- while (i < l) {
|
|
|
- raw.on_updates[i]();
|
|
|
- l <= raw.on_updates.length ? i++ : l = raw.on_updates.length;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Calc absolute bones
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones.length; ++i) {
|
|
|
- // Take bones with 0 parents first
|
|
|
- anim_bone_mult_parent(raw, raw.mats_fast_sort[i], raw.mats_fast, raw.skeleton_bones, raw.skeleton_mats);
|
|
|
- }
|
|
|
- if (raw.skeleton_bones_blend != null) {
|
|
|
- for (let i: i32 = 0; i < raw.skeleton_bones_blend.length; ++i) {
|
|
|
- anim_bone_mult_parent(raw, raw.mats_fast_blend_sort[i], raw.mats_fast_blend, raw.skeleton_bones_blend, raw.skeleton_mats_blend);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (raw.base.is_skinned) {
|
|
|
- anim_bone_update_skin_gpu(raw);
|
|
|
- }
|
|
|
- else {
|
|
|
- anim_bone_update_bones_only(raw);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function anim_bone_total_frames(raw: anim_bone_t): i32 {
|
|
|
- if (raw.skeleton_bones == null) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- let track: track_t = raw.skeleton_bones[0].anim.tracks[0];
|
|
|
- return math_floor(track.frames[track.frames.length - 1] - track.frames[0]);
|
|
|
-}
|
|
|
-
|
|
|
-///end
|