cylinder.go 7.4 KB

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