sphere.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. // Sphere represents a sphere geometry
  11. type Sphere struct {
  12. Geometry
  13. Radius float64
  14. WidthSegments int
  15. HeightSegments int
  16. PhiStart float64
  17. PhiLength float64
  18. ThetaStart float64
  19. ThetaLength float64
  20. }
  21. // NewSphere returns a pointer to a new Sphere geometry object
  22. func NewSphere(radius float64, widthSegments, heightSegments int, phiStart, phiLength, thetaStart, thetaLength float64) *Sphere {
  23. s := new(Sphere)
  24. s.Geometry.Init()
  25. s.Radius = radius
  26. s.WidthSegments = widthSegments
  27. s.HeightSegments = heightSegments
  28. s.PhiStart = phiStart
  29. s.PhiLength = phiLength
  30. s.ThetaStart = thetaStart
  31. thetaEnd := thetaStart + thetaLength
  32. vertexCount := (widthSegments + 1) * (heightSegments + 1)
  33. // Create buffers
  34. positions := math32.NewArrayF32(vertexCount*3, vertexCount*3)
  35. normals := math32.NewArrayF32(vertexCount*3, vertexCount*3)
  36. uvs := math32.NewArrayF32(vertexCount*2, vertexCount*2)
  37. indices := math32.NewArrayU32(0, vertexCount)
  38. index := 0
  39. vertices := make([][]uint32, 0)
  40. var normal math32.Vector3
  41. for y := 0; y <= heightSegments; y++ {
  42. verticesRow := make([]uint32, 0)
  43. v := float64(y) / float64(heightSegments)
  44. for x := 0; x <= widthSegments; x++ {
  45. u := float64(x) / float64(widthSegments)
  46. px := -radius * math.Cos(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
  47. py := radius * math.Cos(thetaStart+v*thetaLength)
  48. pz := radius * math.Sin(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
  49. normal.Set(float32(px), float32(py), float32(pz)).Normalize()
  50. positions.Set(index*3, float32(px), float32(py), float32(pz))
  51. normals.SetVector3(index*3, &normal)
  52. uvs.Set(index*2, float32(u), float32(v))
  53. verticesRow = append(verticesRow, uint32(index))
  54. index++
  55. }
  56. vertices = append(vertices, verticesRow)
  57. }
  58. for y := 0; y < heightSegments; y++ {
  59. for x := 0; x < widthSegments; x++ {
  60. v1 := vertices[y][x+1]
  61. v2 := vertices[y][x]
  62. v3 := vertices[y+1][x]
  63. v4 := vertices[y+1][x+1]
  64. if y != 0 || thetaStart > 0 {
  65. indices.Append(v1, v2, v4)
  66. }
  67. if y != heightSegments-1 || thetaEnd < math.Pi {
  68. indices.Append(v2, v3, v4)
  69. }
  70. }
  71. }
  72. s.SetIndices(indices)
  73. s.AddVBO(gls.NewVBO(positions).AddAttrib(VertexPosition, 3))
  74. s.AddVBO(gls.NewVBO(normals).AddAttrib(VertexNormal, 3))
  75. s.AddVBO(gls.NewVBO(uvs).AddAttrib(VertexTexcoord, 2))
  76. r := float32(radius)
  77. // Update bounding sphere
  78. s.boundingSphere.Radius = 3
  79. s.boundingSphereValid = true
  80. // Update bounding box
  81. s.boundingBox = math32.Box3{math32.Vector3{-r, -r, -r}, math32.Vector3{r, r, r}}
  82. s.boundingBoxValid = true
  83. return s
  84. }