box.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. )
  9. // NewCube creates a cube geometry with the specified size.
  10. func NewCube(size float32) *Geometry {
  11. return NewSegmentedCube(size, 1)
  12. }
  13. // NewSegmentedCube creates a segmented cube geometry with the specified size and number of segments.
  14. func NewSegmentedCube(size float32, segments int) *Geometry {
  15. return NewSegmentedBox(size, size, size, segments, segments, segments)
  16. }
  17. // NewBox creates a box geometry with the specified width, height, and length.
  18. func NewBox(width, height, length float32) *Geometry {
  19. return NewSegmentedBox(width, height, length, 1, 1, 1)
  20. }
  21. // NewSegmentedBox creates a segmented box geometry with the specified width, height, length, and number of segments in each dimension.
  22. func NewSegmentedBox(width, height, length float32, widthSegments, heightSegments, lengthSegments int) *Geometry {
  23. box := NewGeometry()
  24. // Validate arguments
  25. if widthSegments <= 0 || heightSegments <= 0 || lengthSegments <= 0 {
  26. panic("Invalid argument(s). All segment quantities should be greater than zero.")
  27. }
  28. // Create buffers
  29. positions := math32.NewArrayF32(0, 16)
  30. normals := math32.NewArrayF32(0, 16)
  31. uvs := math32.NewArrayF32(0, 16)
  32. indices := math32.NewArrayU32(0, 16)
  33. // Internal function to build each of the six box planes
  34. buildPlane := func(u, v string, udir, vdir int, width, height, length float32, materialIndex uint) {
  35. offset := positions.Len() / 3
  36. gridX := widthSegments
  37. gridY := heightSegments
  38. var w string
  39. if (u == "x" && v == "y") || (u == "y" && v == "x") {
  40. w = "z"
  41. } else if (u == "x" && v == "z") || (u == "z" && v == "x") {
  42. w = "y"
  43. gridY = lengthSegments
  44. } else if (u == "z" && v == "y") || (u == "y" && v == "z") {
  45. w = "x"
  46. gridX = lengthSegments
  47. }
  48. var normal math32.Vector3
  49. if length > 0 {
  50. normal.SetByName(w, 1)
  51. } else {
  52. normal.SetByName(w, -1)
  53. }
  54. wHalf := width / 2
  55. hHalf := height / 2
  56. gridX1 := gridX + 1
  57. gridY1 := gridY + 1
  58. segmentWidth := width / float32(gridX)
  59. segmentHeight := height / float32(gridY)
  60. // Generate the plane vertices, normals, and uv coordinates
  61. for iy := 0; iy < gridY1; iy++ {
  62. for ix := 0; ix < gridX1; ix++ {
  63. var vector math32.Vector3
  64. vector.SetByName(u, (float32(ix)*segmentWidth-wHalf)*float32(udir))
  65. vector.SetByName(v, (float32(iy)*segmentHeight-hHalf)*float32(vdir))
  66. vector.SetByName(w, length)
  67. positions.AppendVector3(&vector)
  68. normals.AppendVector3(&normal)
  69. uvs.Append(float32(ix)/float32(gridX), float32(1)-(float32(iy)/float32(gridY)))
  70. }
  71. }
  72. // Generate the indices for the vertices, normals and uv coordinates
  73. gstart := indices.Size()
  74. for iy := 0; iy < gridY; iy++ {
  75. for ix := 0; ix < gridX; ix++ {
  76. a := ix + gridX1*iy
  77. b := ix + gridX1*(iy+1)
  78. c := (ix + 1) + gridX1*(iy+1)
  79. d := (ix + 1) + gridX1*iy
  80. indices.Append(uint32(a+offset), uint32(b+offset), uint32(d+offset), uint32(b+offset), uint32(c+offset), uint32(d+offset))
  81. }
  82. }
  83. gcount := indices.Size() - gstart
  84. box.AddGroup(gstart, gcount, int(materialIndex))
  85. }
  86. wHalf := width / 2
  87. hHalf := height / 2
  88. lHalf := length / 2
  89. buildPlane("z", "y", -1, -1, length, height, wHalf, 0) // px
  90. buildPlane("z", "y", 1, -1, length, height, -wHalf, 1) // nx
  91. buildPlane("x", "z", 1, 1, width, length, hHalf, 2) // py
  92. buildPlane("x", "z", 1, -1, width, length, -hHalf, 3) // ny
  93. buildPlane("x", "y", 1, -1, width, height, lHalf, 4) // pz
  94. buildPlane("x", "y", -1, -1, width, height, -lHalf, 5) // nz
  95. box.SetIndices(indices)
  96. box.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
  97. box.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
  98. box.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
  99. // Update bounding box
  100. box.boundingBox.Min = math32.Vector3{-wHalf, -hHalf, -lHalf}
  101. box.boundingBox.Max = math32.Vector3{wHalf, hHalf, lHalf}
  102. box.boundingBoxValid = true
  103. // Update bounding sphere
  104. box.boundingSphere.Radius = math32.Sqrt(math32.Pow(width/2, 2) + math32.Pow(height/2, 2) + math32.Pow(length/2, 2))
  105. box.boundingSphereValid = true
  106. // Update area
  107. box.area = 2*width + 2*height + 2*length
  108. box.areaValid = true
  109. // Update volume
  110. box.volume = width * height * length
  111. box.volumeValid = true
  112. return box
  113. }