tube.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import { Vec3 } from 'mol-math/linear-algebra';
  8. import { ChunkedArray } from 'mol-data/util';
  9. import { MeshBuilder } from '../mesh-builder';
  10. const normalVector = Vec3.zero()
  11. const surfacePoint = Vec3.zero()
  12. const controlPoint = Vec3.zero()
  13. const u = Vec3.zero()
  14. const v = Vec3.zero()
  15. function add2AndScale2(out: Vec3, a: Vec3, b: Vec3, sa: number, sb: number) {
  16. out[0] = (a[0] * sa) + (b[0] * sb);
  17. out[1] = (a[1] * sa) + (b[1] * sb);
  18. out[2] = (a[2] * sa) + (b[2] * sb);
  19. }
  20. function add3AndScale2(out: Vec3, a: Vec3, b: Vec3, c: Vec3, sa: number, sb: number) {
  21. out[0] = (a[0] * sa) + (b[0] * sb) + c[0];
  22. out[1] = (a[1] * sa) + (b[1] * sb) + c[1];
  23. out[2] = (a[2] * sa) + (b[2] * sb) + c[2];
  24. }
  25. export function addTube(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, radialSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, waveFactor: number, startCap: boolean, endCap: boolean) {
  26. const { currentGroup, vertices, normals, indices, groups } = state
  27. let vertexCount = vertices.elementCount
  28. const di = 1 / linearSegments
  29. for (let i = 0; i <= linearSegments; ++i) {
  30. const i3 = i * 3
  31. Vec3.fromArray(u, normalVectors, i3)
  32. Vec3.fromArray(v, binormalVectors, i3)
  33. Vec3.fromArray(controlPoint, controlPoints, i3)
  34. const width = widthValues[i]
  35. const height = heightValues[i]
  36. const tt = di * i - 0.5;
  37. const ff = 1 + (waveFactor - 1) * (Math.cos(2 * Math.PI * tt) + 1);
  38. const w = ff * width, h = ff * height;
  39. for (let j = 0; j < radialSegments; ++j) {
  40. const t = 2 * Math.PI * j / radialSegments;
  41. add3AndScale2(surfacePoint, u, v, controlPoint, h * Math.cos(t), w * Math.sin(t))
  42. add2AndScale2(normalVector, u, v, w * Math.cos(t), h * Math.sin(t))
  43. Vec3.normalize(normalVector, normalVector)
  44. ChunkedArray.add3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]);
  45. ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
  46. }
  47. }
  48. for (let i = 0; i < linearSegments; ++i) {
  49. for (let j = 0; j < radialSegments; ++j) {
  50. ChunkedArray.add3(
  51. indices,
  52. vertexCount + i * radialSegments + (j + 1) % radialSegments,
  53. vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments,
  54. vertexCount + i * radialSegments + j
  55. );
  56. ChunkedArray.add3(
  57. indices,
  58. vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments,
  59. vertexCount + (i + 1) * radialSegments + j,
  60. vertexCount + i * radialSegments + j
  61. );
  62. }
  63. }
  64. if (startCap) {
  65. const offset = 0
  66. const centerVertex = vertices.elementCount
  67. Vec3.fromArray(u, normalVectors, offset)
  68. Vec3.fromArray(v, binormalVectors, offset)
  69. Vec3.fromArray(controlPoint, controlPoints, offset)
  70. Vec3.cross(normalVector, v, u)
  71. ChunkedArray.add3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]);
  72. ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
  73. const width = widthValues[0]
  74. const height = heightValues[0]
  75. vertexCount = vertices.elementCount
  76. for (let i = 0; i < radialSegments; ++i) {
  77. const t = 2 * Math.PI * i / radialSegments;
  78. add3AndScale2(surfacePoint, u, v, controlPoint, height * Math.cos(t), width * Math.sin(t))
  79. ChunkedArray.add3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]);
  80. ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
  81. ChunkedArray.add3(
  82. indices,
  83. vertexCount + (i + 1) % radialSegments,
  84. vertexCount + i,
  85. centerVertex
  86. );
  87. }
  88. }
  89. if (endCap) {
  90. const offset = linearSegments * 3
  91. const centerVertex = vertices.elementCount
  92. Vec3.fromArray(u, normalVectors, offset)
  93. Vec3.fromArray(v, binormalVectors, offset)
  94. Vec3.fromArray(controlPoint, controlPoints, offset)
  95. Vec3.cross(normalVector, u, v)
  96. ChunkedArray.add3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]);
  97. ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
  98. const width = widthValues[linearSegments]
  99. const height = heightValues[linearSegments]
  100. vertexCount = vertices.elementCount
  101. for (let i = 0; i < radialSegments; ++i) {
  102. const t = 2 * Math.PI * i / radialSegments
  103. add3AndScale2(surfacePoint, u, v, controlPoint, height * Math.cos(t), width * Math.sin(t))
  104. ChunkedArray.add3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]);
  105. ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
  106. ChunkedArray.add3(
  107. indices,
  108. vertexCount + i,
  109. vertexCount + (i + 1) % radialSegments,
  110. centerVertex
  111. );
  112. }
  113. }
  114. const addedVertexCount = (linearSegments + 1) * radialSegments + (startCap ? radialSegments + 1 : 0) + (endCap ? radialSegments + 1 : 0)
  115. ChunkedArray.addRepeat(groups, addedVertexCount, currentGroup)
  116. }