transform-data.ts 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { ValueCell } from 'mol-util';
  7. import { Mat4 } from 'mol-math/linear-algebra';
  8. import { fillSerial } from 'mol-util/array';
  9. export type TransformData = {
  10. /**
  11. * final per-instance transform calculated for instance `i` as
  12. * `aTransform[i] = matrix * transform[i] * extraTransform[i]`
  13. */
  14. aTransform: ValueCell<Float32Array>,
  15. /** global transform, see aTransform */
  16. matrix: ValueCell<Mat4>,
  17. /** base per-instance transform, see aTransform */
  18. transform: ValueCell<Float32Array>,
  19. /** additional per-instance transform, see aTransform */
  20. extraTransform: ValueCell<Float32Array>,
  21. uInstanceCount: ValueCell<number>,
  22. instanceCount: ValueCell<number>,
  23. aInstance: ValueCell<Float32Array>,
  24. }
  25. export function createTransform(transformArray: Float32Array, instanceCount: number, transformData?: TransformData): TransformData {
  26. if (transformData) {
  27. ValueCell.update(transformData.matrix, transformData.matrix.ref.value)
  28. ValueCell.update(transformData.transform, transformArray)
  29. ValueCell.update(transformData.uInstanceCount, instanceCount)
  30. ValueCell.update(transformData.instanceCount, instanceCount)
  31. const aTransform = transformData.aTransform.ref.value.length >= instanceCount * 16 ? transformData.aTransform.ref.value : new Float32Array(instanceCount * 16)
  32. aTransform.set(transformArray)
  33. ValueCell.update(transformData.aTransform, aTransform)
  34. // Note that this sets `extraTransform` to identity transforms
  35. const extraTransform = transformData.extraTransform.ref.value.length >= instanceCount * 16 ? transformData.extraTransform.ref.value : new Float32Array(instanceCount * 16)
  36. ValueCell.update(transformData.extraTransform, fillIdentityTransform(extraTransform, instanceCount))
  37. const aInstance = transformData.aInstance.ref.value.length >= instanceCount ? transformData.aInstance.ref.value : new Float32Array(instanceCount)
  38. ValueCell.update(transformData.aInstance, fillSerial(aInstance, instanceCount))
  39. updateTransformData(transformData)
  40. return transformData
  41. } else {
  42. return {
  43. aTransform: ValueCell.create(new Float32Array(transformArray)),
  44. matrix: ValueCell.create(Mat4.identity()),
  45. transform: ValueCell.create(transformArray),
  46. extraTransform: ValueCell.create(fillIdentityTransform(new Float32Array(instanceCount * 16), instanceCount)),
  47. uInstanceCount: ValueCell.create(instanceCount),
  48. instanceCount: ValueCell.create(instanceCount),
  49. aInstance: ValueCell.create(fillSerial(new Float32Array(instanceCount)))
  50. }
  51. }
  52. }
  53. const identityTransform = new Float32Array(16)
  54. Mat4.toArray(Mat4.identity(), identityTransform, 0)
  55. export function createIdentityTransform(transformData?: TransformData): TransformData {
  56. return createTransform(new Float32Array(identityTransform), 1, transformData)
  57. }
  58. export function fillIdentityTransform(transform: Float32Array, count: number) {
  59. for (let i = 0; i < count; i++) {
  60. transform.set(identityTransform, i * 16)
  61. }
  62. return transform
  63. }
  64. /**
  65. * updates per-instance transform calculated for instance `i` as
  66. * `aTransform[i] = matrix * transform[i] * extraTransform[i]`
  67. */
  68. export function updateTransformData(transformData: TransformData) {
  69. const aTransform = transformData.aTransform.ref.value
  70. const instanceCount = transformData.instanceCount.ref.value
  71. const matrix = transformData.matrix.ref.value
  72. const transform = transformData.transform.ref.value
  73. const extraTransform = transformData.extraTransform.ref.value
  74. for (let i = 0; i < instanceCount; i++) {
  75. const i16 = i * 16
  76. Mat4.mulOffset(aTransform, extraTransform, transform, i16, i16, i16)
  77. Mat4.mulOffset(aTransform, matrix, aTransform, i16, 0, i16)
  78. }
  79. ValueCell.update(transformData.aTransform, aTransform)
  80. }