Home Reference Source Repository

js/SceneKit/SCNTorus.js

  1. 'use strict'
  2.  
  3. import SCNGeometry from './SCNGeometry'
  4. import SCNGeometryElement from './SCNGeometryElement'
  5. import SCNGeometryPrimitiveType from './SCNGeometryPrimitiveType'
  6. import SCNGeometrySource from './SCNGeometrySource'
  7. import SCNMaterial from './SCNMaterial'
  8. import SCNVector3 from './SCNVector3'
  9.  
  10. /**
  11. * A torus, or ring-shaped geometry.
  12. * @access public
  13. * @extends {SCNGeometry}
  14. * @see https://developer.apple.com/documentation/scenekit/scntorus
  15. */
  16. export default class SCNTorus extends SCNGeometry {
  17. // Creating a Torus
  18.  
  19. /**
  20. * Creates a torus geometry with the specified ring radius and pipe radius.
  21. * @access public
  22. * @constructor
  23. * @param {number} ringRadius - The major radius of the torus, defining its circular ring in the x- and z-axis dimensions of its local coordinate space.
  24. * @param {number} pipeRadius - The minor radius of the torus, defining the pipe that encircles the ring.
  25. * @desc The torus is centered in its local coordinate system. For example, if you create a torus whose ring radius is 5.0 and pipe radius is 1.0, it extends from -6.0 to 6.0 (with a hole through the center from -4.0 to 4.0) in the x- and z-axes and from -1.0 to 1.0 in the y-axis.
  26. * @see https://developer.apple.com/documentation/scenekit/scntorus/1523833-init
  27. */
  28. constructor(ringRadius = 0.5, pipeRadius = 0.25) {
  29. super([], [])
  30.  
  31. // Adjusting a Torus’ Dimensions
  32.  
  33. /**
  34. * The major radius of the torus, defining a circle in the x- and z-axis dimensions. Animatable.
  35. * @type {number}
  36. * @see https://developer.apple.com/documentation/scenekit/scntorus/1522906-ringradius
  37. */
  38. this.ringRadius = ringRadius
  39.  
  40. /**
  41. * The minor radius of the torus, defining the pipe that encircles the torus ring. Animatable.
  42. * @type {number}
  43. * @see https://developer.apple.com/documentation/scenekit/scntorus/1522623-piperadius
  44. */
  45. this.pipeRadius = pipeRadius
  46.  
  47.  
  48. // Configuring Torus Properties
  49.  
  50. /**
  51. * The number of subdivisions around the torus ring. Animatable.
  52. * @type {number}
  53. * @see https://developer.apple.com/documentation/scenekit/scntorus/1523598-ringsegmentcount
  54. */
  55. this.ringSegmentCount = 48
  56.  
  57. /**
  58. * The number of subdivisions around the torus pipe. Animatable.
  59. * @type {number}
  60. * @see https://developer.apple.com/documentation/scenekit/scntorus/1522807-pipesegmentcount
  61. */
  62. this.pipeSegmentCount = 24
  63.  
  64. this._createGeometry()
  65. this.materials.push(new SCNMaterial())
  66. }
  67.  
  68. _createGeometry() {
  69. const sourceData = []
  70. const indexData = []
  71. const vectorCount = (this.ringSegmentCount + 1) * (this.pipeSegmentCount + 1)
  72.  
  73. for(let ri=0; ri<=this.ringSegmentCount; ri++){
  74. const r = 2.0 * ri * Math.PI / this.ringSegmentCount
  75. const sinr = Math.sin(r)
  76. const cosr = Math.cos(r)
  77. const cx = -sinr * this.ringRadius
  78. const cz = -cosr * this.ringRadius
  79. const tx = ri / this.ringSegmentCount
  80.  
  81. for(let pi=0; pi<=this.pipeSegmentCount; pi++){
  82. const pr = 2.0 * pi * Math.PI / this.pipeSegmentCount
  83. const sinp = Math.sin(pr)
  84. const cosp = Math.cos(pr)
  85. const x = cx + this.pipeRadius * sinr * cosp
  86. const y = -this.pipeRadius * sinp
  87. const z = cz + this.pipeRadius * cosr * cosp
  88.  
  89. // vertex
  90. sourceData.push(x, y, z)
  91.  
  92. // normal
  93. sourceData.push(sinr * cosp, -sinp, cosr * cosp)
  94.  
  95. // texcoord
  96. const tz = 1.0 - pi / this.pipeSegmentCount
  97. sourceData.push(tx, tz)
  98. }
  99. }
  100.  
  101. const vertexSource = new SCNGeometrySource(
  102. sourceData, // data
  103. SCNGeometrySource.Semantic.vertex, // semantic
  104. vectorCount, // vectorCount
  105. true, // floatComponents
  106. 3, // componentsPerVector
  107. 4, // bytesPerComponent
  108. 0, // offset
  109. 32 // sride
  110. )
  111.  
  112. const normalSource = new SCNGeometrySource(
  113. sourceData, // data
  114. SCNGeometrySource.Semantic.normal, // semantic
  115. vectorCount, // vectorCount
  116. true, // floatComponents
  117. 3, // componentsPerVector
  118. 4, // bytesPerComponent
  119. 12, // offset
  120. 32 // stride
  121. )
  122.  
  123. const texcoordSource = new SCNGeometrySource(
  124. sourceData, // data
  125. SCNGeometrySource.Semantic.texcoord, // semantic
  126. vectorCount, // vectorCount
  127. true, // floatComponents
  128. 2, // componentsPerVector
  129. 4, // bytesPerComponent
  130. 24, // offset
  131. 32 // stride
  132. )
  133.  
  134. const indexLen = this.ringSegmentCount * this.pipeSegmentCount
  135. let base = 0
  136. for(let i=0; i<indexLen; i++){
  137. const i2 = base + this.pipeSegmentCount + 1
  138. indexData.push(base, i2+1, base+1)
  139. indexData.push(base, i2, i2+1)
  140. base += 1
  141. if((i+1) % this.pipeSegmentCount === 0){
  142. base += 1
  143. }
  144. }
  145.  
  146. const element = new SCNGeometryElement(indexData, SCNGeometryPrimitiveType.triangles)
  147.  
  148. this._geometryElements = [element]
  149. this._geometrySources = [vertexSource, normalSource, texcoordSource]
  150. this.boundingBox = {
  151. min: new SCNVector3(-this.radius, -this.radius, -this.radius),
  152. max: new SCNVector3(this.radius, this.radius, this.radius)
  153. }
  154. }
  155. }