| 27 | } |
| 28 | |
| 29 | bool SkinController::Update(double applicationTime) |
| 30 | { |
| 31 | if (!Controller::Update(applicationTime)) |
| 32 | { |
| 33 | return false; |
| 34 | } |
| 35 | |
| 36 | if (mFirstUpdate) |
| 37 | { |
| 38 | mFirstUpdate = false; |
| 39 | OnFirstUpdate(); |
| 40 | } |
| 41 | |
| 42 | if (mCanUpdate) |
| 43 | { |
| 44 | // The skin vertices are calculated in the bone world coordinate system, |
| 45 | // so the visual's world transform must be the identity. |
| 46 | auto visual = static_cast<Visual*>(mObject); |
| 47 | visual->worldTransform = Transform<float>::Identity(); |
| 48 | visual->worldTransformIsCurrent = true; |
| 49 | |
| 50 | // Package the bone transformations into a std::vector to avoid the |
| 51 | // expensive lock() calls in the inner loop of the position updates. |
| 52 | std::vector<Matrix4x4<float>> worldTransforms(mNumBones); |
| 53 | for (int32_t bone = 0; bone < mNumBones; ++bone) |
| 54 | { |
| 55 | worldTransforms[bone] = mBones[bone].lock()->worldTransform; |
| 56 | } |
| 57 | |
| 58 | // Compute the skin vertex locations. The typecasting to raw 'float' |
| 59 | // pointers increases the frame rate dramatically, both in Debug and |
| 60 | // Release builds. Without this in Debug builds, the lack of inlining |
| 61 | // of Vector4, Matrix4, std::array and std::vector operator[] |
| 62 | // functions leads to a low frame rate. Without this in Release |
| 63 | // builds, the lack of a highly efficient implementation of operator[] |
| 64 | // in std::array and std::vector leads to a low frame rate. Running |
| 65 | // on an Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz, the Debug frame rate |
| 66 | // before the typecasting is 16 fps and after the typecasting is |
| 67 | // 223 fps. The Release frame rate before the typecasting is 2390 fps |
| 68 | // and after the typecasting is 4170 fps (sync to vertical retrace is |
| 69 | // turned off for these experiments). |
| 70 | char* current = mPosition; |
| 71 | float const* weights = mWeights.data(); |
| 72 | Vector4<float> const* offsets = mOffsets.data(); |
| 73 | for (int32_t vertex = 0; vertex < mNumVertices; ++vertex) |
| 74 | { |
| 75 | Matrix4x4<float> const* worldTransform = worldTransforms.data(); |
| 76 | float position[3] = { 0.0f, 0.0f, 0.0f }; |
| 77 | for (int32_t bone = 0; bone < mNumBones; ++bone, ++weights, ++offsets, ++worldTransform) |
| 78 | { |
| 79 | float weight = *weights; |
| 80 | if (weight != 0.0f) |
| 81 | { |
| 82 | float const* M = reinterpret_cast<float const*>(worldTransform); |
| 83 | float const* P = reinterpret_cast<float const*>(offsets); |
| 84 | #if defined (GTE_USE_VEC_MAT) |
| 85 | position[0] += weight * (M[0] * P[0] + M[4] * P[1] + M[8] * P[2] + M[12]); |
| 86 | position[1] += weight * (M[1] * P[0] + M[5] * P[1] + M[9] * P[2] + M[13]); |
nothing calls this directly
no test coverage detected