All files / engine/Source/Scene/Model ModelSkin.js

100% Statements 43/43
50% Branches 1/2
100% Functions 9/9
100% Lines 41/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181                                      12x   12x 11x     10x 10x   10x   10x 10x 10x   10x     1x                       12x                             11x                             70x                             81x                                     11x           10x 10x 10x   10x 10x   10x 10x 10x 10x 71x 71x 71x   71x 71x         71x         140x           140x           140x               1x 9x 9x 9x 69x 69x 69x                  
import Matrix4 from "../../Core/Matrix4.js";
import Check from "../../Core/Check.js";
import Frozen from "../../Core/Frozen.js";
 
/**
 * An in-memory representation of a skin that affects nodes in the {@link ModelSceneGraph}.
 * Skins should only be initialized after all of the {@link ModelRuntimeNode}s have been instantiated
 * by the scene graph.
 *
 * @param {object} options An object containing the following options:
 * @param {ModelComponents.Skin} options.skin The corresponding skin components from the 3D model
 * @param {ModelSceneGraph} options.sceneGraph The scene graph this skin belongs to.
 *
 * @alias ModelSkin
 * @constructor
 *
 * @private
 */
function ModelSkin(options) {
  options = options ?? Frozen.EMPTY_OBJECT;
  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.object("options.skin", options.skin);
  Check.typeOf.object("options.sceneGraph", options.sceneGraph);
  //>>includeEnd('debug');
 
  this._sceneGraph = options.sceneGraph;
  const skin = options.skin;
 
  this._skin = skin;
 
  this._inverseBindMatrices = undefined;
  this._joints = [];
  this._jointMatrices = [];
 
  initialize(this);
}
 
Object.defineProperties(ModelSkin.prototype, {
  /**
   * The internal skin this runtime skin represents.
   *
   * @memberof ModelSkin.prototype
   * @type {ModelComponents.Skin}
   * @readonly
   *
   * @private
   */
  skin: {
    get: function () {
      return this._skin;
    },
  },
 
  /**
   * The scene graph this skin belongs to.
   *
   * @memberof ModelSkin.prototype
   * @type {ModelSceneGraph}
   * @readonly
   *
   * @private
   */
  sceneGraph: {
    get: function () {
      return this._sceneGraph;
    },
  },
 
  /**
   * The inverse bind matrices of the skin.
   *
   * @memberof ModelSkin.prototype
   * @type {Matrix4[]}
   * @readonly
   *
   * @private
   */
  inverseBindMatrices: {
    get: function () {
      return this._inverseBindMatrices;
    },
  },
 
  /**
   * The joints of the skin.
   *
   * @memberof ModelSkin.prototype
   * @type {ModelRuntimeNode[]}
   * @readonly
   *
   * @private
   */
  joints: {
    get: function () {
      return this._joints;
    },
  },
 
  /**
   * The joint matrices for the skin, where each joint matrix is computed as
   * jointMatrix = jointWorldTransform * inverseBindMatrix.
   *
   * Each node that references this skin is responsible for pre-multiplying its inverse
   * world transform to the joint matrices for its own use.
   *
   * @memberof ModelSkin.prototype
   * @type {Matrix4[]}
   * @readonly
   *
   * @private
   */
  jointMatrices: {
    get: function () {
      return this._jointMatrices;
    },
  },
});
 
function initialize(runtimeSkin) {
  const skin = runtimeSkin.skin;
  const inverseBindMatrices = skin.inverseBindMatrices;
  runtimeSkin._inverseBindMatrices = inverseBindMatrices;
 
  const joints = skin.joints;
  const length = joints.length;
 
  const runtimeNodes = runtimeSkin.sceneGraph._runtimeNodes;
  const runtimeJoints = runtimeSkin.joints;
  const runtimeJointMatrices = runtimeSkin._jointMatrices;
  for (let i = 0; i < length; i++) {
    const jointIndex = joints[i].index;
    const runtimeNode = runtimeNodes[jointIndex];
    runtimeJoints.push(runtimeNode);
 
    const inverseBindMatrix = inverseBindMatrices[i];
    const jointMatrix = computeJointMatrix(
      runtimeNode,
      inverseBindMatrix,
      new Matrix4(),
    );
    runtimeJointMatrices.push(jointMatrix);
  }
}
 
function computeJointMatrix(joint, inverseBindMatrix, result) {
  const jointWorldTransform = Matrix4.multiplyTransformation(
    joint.transformToRoot,
    joint.transform,
    result,
  );
 
  result = Matrix4.multiplyTransformation(
    jointWorldTransform,
    inverseBindMatrix,
    result,
  );
 
  return result;
}
 
/**
 * Updates the joint matrices for the skin.
 *
 * @private
 */
ModelSkin.prototype.updateJointMatrices = function () {
  const jointMatrices = this._jointMatrices;
  const length = jointMatrices.length;
  for (let i = 0; i < length; i++) {
    const joint = this.joints[i];
    const inverseBindMatrix = this.inverseBindMatrices[i];
    jointMatrices[i] = computeJointMatrix(
      joint,
      inverseBindMatrix,
      jointMatrices[i],
    );
  }
};
 
export default ModelSkin;