cone-cylinder.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package geometry
  5. import (
  6. "github.com/g3n/engine/gls"
  7. "github.com/g3n/engine/math32"
  8. "math"
  9. )
  10. // NewCone creates a cone geometry with the specified base radius, height,
  11. // number of radial segments, number of height segments, and presence of a bottom cap.
  12. func NewCone(radius, height float64, radialSegments, heightSegments int, bottom bool) *Geometry {
  13. return NewConeSector(radius, height, radialSegments, heightSegments, 0, 2*math.Pi, bottom)
  14. }
  15. // NewConeSector creates a cone sector geometry with the specified base radius, height, number of radial segments,
  16. // number of height segments, sector start angle in radians, sector size angle in radians, and presence of a bottom cap.
  17. func NewConeSector(radius, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, bottom bool) *Geometry {
  18. return NewTruncatedConeSector(0, radius, height, radialSegments, heightSegments, thetaStart, thetaLength, false, bottom)
  19. }
  20. // NewCylinder creates a cylinder geometry with the specified radius, height,
  21. // number of radial segments, number of height segments, and presence of a top and/or bottom cap.
  22. func NewCylinder(radius, height float64, radialSegments, heightSegments int, top, bottom bool) *Geometry {
  23. return NewCylinderSector(radius, height, radialSegments, heightSegments, 0, 2*math.Pi, top, bottom)
  24. }
  25. // NewCylinderSector creates a cylinder sector geometry with the specified radius, height, number of radial segments,
  26. // number of height segments, sector start angle in radians, sector size angle in radians, and presence of a top and/or bottom cap.
  27. func NewCylinderSector(radius, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, top, bottom bool) *Geometry {
  28. return NewTruncatedConeSector(radius, radius, height, radialSegments, heightSegments, thetaStart, thetaLength, top, bottom)
  29. }
  30. // NewTruncatedCone creates a truncated cone geometry with the specified top and bottom radii,
  31. // height, number of radial segments, number of height segments, and presence of a top and/or bottom cap.
  32. func NewTruncatedCone(radiusTop, radiusBottom, height float64, radialSegments, heightSegments int, top, bottom bool) *Geometry {
  33. return NewTruncatedConeSector(radiusTop, radiusBottom, height, radialSegments, heightSegments, 0, 2*math.Pi, top, bottom)
  34. }
  35. // NewTruncatedConeSector creates a truncated cone sector geometry with the specified top and bottom radii, height, number of radial segments,
  36. // number of height segments, sector start angle in radians, sector size angle in radians, and presence of a top and/or bottom cap.
  37. func NewTruncatedConeSector(radiusTop, radiusBottom, height float64, radialSegments, heightSegments int, thetaStart, thetaLength float64, top, bottom bool) *Geometry {
  38. c := NewGeometry()
  39. heightHalf := height / 2
  40. vertices := [][]int{}
  41. uvsOrig := [][]math32.Vector2{}
  42. // Create buffer for vertex positions
  43. positions := math32.NewArrayF32(0, 0)
  44. for y := 0; y <= heightSegments; y++ {
  45. var verticesRow = []int{}
  46. var uvsRow = []math32.Vector2{}
  47. v := float64(y) / float64(heightSegments)
  48. radius := v*(radiusBottom-radiusTop) + radiusTop
  49. for x := 0; x <= radialSegments; x++ {
  50. u := float64(x) / float64(radialSegments)
  51. var vertex math32.Vector3
  52. vertex.X = float32(radius * math.Sin(u*thetaLength+thetaStart))
  53. vertex.Y = float32(-v*height + heightHalf)
  54. vertex.Z = float32(radius * math.Cos(u*thetaLength+thetaStart))
  55. positions.AppendVector3(&vertex)
  56. verticesRow = append(verticesRow, positions.Size()/3-1)
  57. uvsRow = append(uvsRow, math32.Vector2{float32(u), 1.0 - float32(v)})
  58. }
  59. vertices = append(vertices, verticesRow)
  60. uvsOrig = append(uvsOrig, uvsRow)
  61. }
  62. tanTheta := (radiusBottom - radiusTop) / height
  63. var na, nb math32.Vector3
  64. // Create preallocated buffers for normals and uvs and buffer for indices
  65. npos := positions.Size()
  66. normals := math32.NewArrayF32(npos, npos)
  67. uvs := math32.NewArrayF32(2*npos/3, 2*npos/3)
  68. indices := math32.NewArrayU32(0, 0)
  69. for x := 0; x < radialSegments; x++ {
  70. if radiusTop != 0 {
  71. positions.GetVector3(3*vertices[0][x], &na)
  72. positions.GetVector3(3*vertices[0][x+1], &nb)
  73. } else {
  74. positions.GetVector3(3*vertices[1][x], &na)
  75. positions.GetVector3(3*vertices[1][x+1], &nb)
  76. }
  77. na.SetY(float32(math.Sqrt(float64(na.X*na.X+na.Z*na.Z)) * tanTheta)).Normalize()
  78. nb.SetY(float32(math.Sqrt(float64(nb.X*nb.X+nb.Z*nb.Z)) * tanTheta)).Normalize()
  79. for y := 0; y < heightSegments; y++ {
  80. v1 := vertices[y][x]
  81. v2 := vertices[y+1][x]
  82. v3 := vertices[y+1][x+1]
  83. v4 := vertices[y][x+1]
  84. n1 := na
  85. n2 := na
  86. n3 := nb
  87. n4 := nb
  88. uv1 := uvsOrig[y][x]
  89. uv2 := uvsOrig[y+1][x]
  90. uv3 := uvsOrig[y+1][x+1]
  91. uv4 := uvsOrig[y][x+1]
  92. indices.Append(uint32(v1), uint32(v2), uint32(v4))
  93. normals.SetVector3(3*v1, &n1)
  94. normals.SetVector3(3*v2, &n2)
  95. normals.SetVector3(3*v4, &n4)
  96. indices.Append(uint32(v2), uint32(v3), uint32(v4))
  97. normals.SetVector3(3*v2, &n2)
  98. normals.SetVector3(3*v3, &n3)
  99. normals.SetVector3(3*v4, &n4)
  100. uvs.SetVector2(2*v1, &uv1)
  101. uvs.SetVector2(2*v2, &uv2)
  102. uvs.SetVector2(2*v3, &uv3)
  103. uvs.SetVector2(2*v4, &uv4)
  104. }
  105. }
  106. // First group is the body of the cylinder
  107. // without the caps
  108. c.AddGroup(0, indices.Size(), 0)
  109. nextGroup := indices.Size()
  110. // Top cap
  111. if top && radiusTop > 0 {
  112. // Array of vertex indicesOrig to build used to build the faces.
  113. indicesOrig := []uint32{}
  114. nextidx := positions.Size() / 3
  115. // Appends top segments vertices and builds array of its indicesOrig
  116. var uv1, uv2, uv3 math32.Vector2
  117. for x := 0; x < radialSegments; x++ {
  118. uv1 = uvsOrig[0][x]
  119. uv2 = uvsOrig[0][x+1]
  120. uv3 = math32.Vector2{uv2.X, 0}
  121. // Appends CENTER with its own UV.
  122. positions.Append(0, float32(heightHalf), 0)
  123. normals.Append(0, 1, 0)
  124. uvs.AppendVector2(&uv3)
  125. indicesOrig = append(indicesOrig, uint32(nextidx))
  126. nextidx++
  127. // Appends vertex
  128. v := math32.Vector3{}
  129. vi := vertices[0][x]
  130. positions.GetVector3(3*vi, &v)
  131. positions.AppendVector3(&v)
  132. normals.Append(0, 1, 0)
  133. uvs.AppendVector2(&uv1)
  134. indicesOrig = append(indicesOrig, uint32(nextidx))
  135. nextidx++
  136. }
  137. // Appends copy of first vertex (center)
  138. var vertex, normal math32.Vector3
  139. var uv math32.Vector2
  140. positions.GetVector3(3*int(indicesOrig[0]), &vertex)
  141. normals.GetVector3(3*int(indicesOrig[0]), &normal)
  142. uvs.GetVector2(2*int(indicesOrig[0]), &uv)
  143. positions.AppendVector3(&vertex)
  144. normals.AppendVector3(&normal)
  145. uvs.AppendVector2(&uv)
  146. indicesOrig = append(indicesOrig, uint32(nextidx))
  147. nextidx++
  148. // Appends copy of second vertex (v1) USING LAST UV2
  149. positions.GetVector3(3*int(indicesOrig[1]), &vertex)
  150. normals.GetVector3(3*int(indicesOrig[1]), &normal)
  151. positions.AppendVector3(&vertex)
  152. normals.AppendVector3(&normal)
  153. uvs.AppendVector2(&uv2)
  154. indicesOrig = append(indicesOrig, uint32(nextidx))
  155. nextidx++
  156. // Append faces indicesOrig
  157. for x := 0; x < radialSegments; x++ {
  158. pos := 2 * x
  159. i1 := indicesOrig[pos]
  160. i2 := indicesOrig[pos+1]
  161. i3 := indicesOrig[pos+3]
  162. indices.Append(uint32(i1), uint32(i2), uint32(i3))
  163. }
  164. // Second group is optional top cap of the cylinder
  165. c.AddGroup(nextGroup, indices.Size()-nextGroup, 1)
  166. nextGroup = indices.Size()
  167. }
  168. // Bottom cap
  169. if bottom && radiusBottom > 0 {
  170. // Array of vertex indicesOrig to build used to build the faces.
  171. indicesOrig := []uint32{}
  172. nextidx := positions.Size() / 3
  173. // Appends top segments vertices and builds array of its indicesOrig
  174. var uv1, uv2, uv3 math32.Vector2
  175. for x := 0; x < radialSegments; x++ {
  176. uv1 = uvsOrig[heightSegments][x]
  177. uv2 = uvsOrig[heightSegments][x+1]
  178. uv3 = math32.Vector2{uv2.X, 1}
  179. // Appends CENTER with its own UV.
  180. positions.Append(0, float32(-heightHalf), 0)
  181. normals.Append(0, -1, 0)
  182. uvs.AppendVector2(&uv3)
  183. indicesOrig = append(indicesOrig, uint32(nextidx))
  184. nextidx++
  185. // Appends vertex
  186. v := math32.Vector3{}
  187. vi := vertices[heightSegments][x]
  188. positions.GetVector3(3*vi, &v)
  189. positions.AppendVector3(&v)
  190. normals.Append(0, -1, 0)
  191. uvs.AppendVector2(&uv1)
  192. indicesOrig = append(indicesOrig, uint32(nextidx))
  193. nextidx++
  194. }
  195. // Appends copy of first vertex (center)
  196. var vertex, normal math32.Vector3
  197. var uv math32.Vector2
  198. positions.GetVector3(3*int(indicesOrig[0]), &vertex)
  199. normals.GetVector3(3*int(indicesOrig[0]), &normal)
  200. uvs.GetVector2(2*int(indicesOrig[0]), &uv)
  201. positions.AppendVector3(&vertex)
  202. normals.AppendVector3(&normal)
  203. uvs.AppendVector2(&uv)
  204. indicesOrig = append(indicesOrig, uint32(nextidx))
  205. nextidx++
  206. // Appends copy of second vertex (v1) USING LAST UV2
  207. positions.GetVector3(3*int(indicesOrig[1]), &vertex)
  208. normals.GetVector3(3*int(indicesOrig[1]), &normal)
  209. positions.AppendVector3(&vertex)
  210. normals.AppendVector3(&normal)
  211. uvs.AppendVector2(&uv2)
  212. indicesOrig = append(indicesOrig, uint32(nextidx))
  213. nextidx++
  214. // Appends faces indicesOrig
  215. for x := 0; x < radialSegments; x++ {
  216. pos := 2 * x
  217. i1 := indicesOrig[pos]
  218. i2 := indicesOrig[pos+3]
  219. i3 := indicesOrig[pos+1]
  220. indices.Append(uint32(i1), uint32(i2), uint32(i3))
  221. }
  222. // Third group is optional bottom cap of the cylinder
  223. c.AddGroup(nextGroup, indices.Size()-nextGroup, 2)
  224. }
  225. c.SetIndices(indices)
  226. c.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
  227. c.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
  228. c.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
  229. return c
  230. }