sphere.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. "math"
  7. "github.com/g3n/engine/gls"
  8. "github.com/g3n/engine/math32"
  9. )
  10. // NewSphere creates a sphere geometry with the specified radius and number of radial segments in each dimension.
  11. func NewSphere(radius float64, widthSegments, heightSegments int) *Geometry {
  12. return NewSphereSector(radius, widthSegments, heightSegments, 0, math.Pi*2, 0, math.Pi)
  13. }
  14. // NewSphereSector creates a sphere sector geometry with the specified radius, number of radial segments in each dimension, elevation
  15. // start angle in radians, elevation size angle in radians, sector start angle in radians, and sector size angle in radians.
  16. func NewSphereSector(radius float64, widthSegments, heightSegments int, phiStart, phiLength, thetaStart, thetaLength float64) *Geometry {
  17. s := NewGeometry()
  18. thetaEnd := thetaStart + thetaLength
  19. vertexCount := (widthSegments + 1) * (heightSegments + 1)
  20. // Create buffers
  21. positions := math32.NewArrayF32(vertexCount*3, vertexCount*3)
  22. normals := math32.NewArrayF32(vertexCount*3, vertexCount*3)
  23. uvs := math32.NewArrayF32(vertexCount*2, vertexCount*2)
  24. indices := math32.NewArrayU32(0, vertexCount)
  25. index := 0
  26. vertices := make([][]uint32, 0)
  27. var normal math32.Vector3
  28. for y := 0; y <= heightSegments; y++ {
  29. verticesRow := make([]uint32, 0)
  30. v := float64(y) / float64(heightSegments)
  31. for x := 0; x <= widthSegments; x++ {
  32. u := float64(x) / float64(widthSegments)
  33. px := -radius * math.Cos(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
  34. py := radius * math.Cos(thetaStart+v*thetaLength)
  35. pz := radius * math.Sin(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
  36. normal.Set(float32(px), float32(py), float32(pz)).Normalize()
  37. positions.Set(index*3, float32(px), float32(py), float32(pz))
  38. normals.SetVector3(index*3, &normal)
  39. uvs.Set(index*2, float32(u), float32(v))
  40. verticesRow = append(verticesRow, uint32(index))
  41. index++
  42. }
  43. vertices = append(vertices, verticesRow)
  44. }
  45. for y := 0; y < heightSegments; y++ {
  46. for x := 0; x < widthSegments; x++ {
  47. v1 := vertices[y][x+1]
  48. v2 := vertices[y][x]
  49. v3 := vertices[y+1][x]
  50. v4 := vertices[y+1][x+1]
  51. if y != 0 || thetaStart > 0 {
  52. indices.Append(v1, v2, v4)
  53. }
  54. if y != heightSegments-1 || thetaEnd < math.Pi {
  55. indices.Append(v2, v3, v4)
  56. }
  57. }
  58. }
  59. s.SetIndices(indices)
  60. s.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
  61. s.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
  62. s.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
  63. r := float32(radius)
  64. // Update bounding sphere
  65. s.boundingSphere.Radius = 3
  66. s.boundingSphereValid = true
  67. // Update bounding box
  68. s.boundingBox = math32.Box3{math32.Vector3{-r, -r, -r}, math32.Vector3{r, r, r}}
  69. s.boundingBoxValid = true
  70. return s
  71. }