getJointsTexture method

Texture getJointsTexture()

Implementation

gpu.Texture getJointsTexture() {
  // Each joint has a matrix. 1 matrix = 16 floats. 1 pixel = 4 floats.
  // Therefore, each joint needs 4 pixels.
  int requiredPixels = joints.length * 4;
  int dimensionSize =
      max(2, _getNextPowerOfTwoSize(sqrt(requiredPixels).ceil()));

  gpu.Texture? texture = gpu.gpuContext.createTexture(
      gpu.StorageMode.hostVisible, dimensionSize, dimensionSize,
      format: gpu.PixelFormat.r32g32b32a32Float);
  if (texture == null) {
    throw Exception('Failed to create joints texture.');
  }
  // 64 bytes per matrix. 4 bytes per pixel.
  Float32List jointMatrixFloats =
      Float32List(dimensionSize * dimensionSize * 4);
  // Initialize with identity matrices.
  for (int i = 0; i < jointMatrixFloats.length; i += 16) {
    jointMatrixFloats[i] = 1.0;
    jointMatrixFloats[i + 5] = 1.0;
    jointMatrixFloats[i + 10] = 1.0;
    jointMatrixFloats[i + 15] = 1.0;
  }

  for (int jointIndex = 0; jointIndex < joints.length; jointIndex++) {
    Node? joint = joints[jointIndex];

    // Compute a model space matrix for the joint by walking up the bones to the
    // skeleton root.
    final floatOffset = jointIndex * 16;
    while (joint != null && joint.isJoint) {
      final Matrix4 matrix = joint.localTransform *
          Matrix4.fromFloat32List(
              jointMatrixFloats.sublist(floatOffset, floatOffset + 16));

      jointMatrixFloats.setRange(
          floatOffset, floatOffset + 16, matrix.storage);

      joint = joint.parent;
    }

    // Get the joint transform relative to the default pose of the bone by
    // incorporating the joint's inverse bind matrix. The inverse bind matrix
    // transforms from model space to the default pose space of the joint. The
    // result is a model space matrix that only captures the difference between
    // the joint's default pose and the joint's current pose in the scene. This
    // is necessary because the skinned model's vertex positions (which _define_
    // the default pose) are all in model space.
    final Matrix4 matrix = Matrix4.fromFloat32List(
            jointMatrixFloats.sublist(floatOffset, floatOffset + 16)) *
        inverseBindMatrices[jointIndex];

    jointMatrixFloats.setRange(floatOffset, floatOffset + 16, matrix.storage);
  }

  if (!texture.overwrite(jointMatrixFloats.buffer.asByteData())) {
    throw Exception('Failed to overwrite joints texture data.');
  }
  return texture;
}