forked from g3n/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sphere.go
87 lines (71 loc) · 2.89 KB
/
sphere.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Copyright 2016 The G3N Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package geometry
import (
"github.com/adamlenda/engine/gls"
"github.com/adamlenda/engine/math32"
"math"
)
// NewSphere creates a sphere geometry with the specified radius and number of radial segments in each dimension.
func NewSphere(radius float64, widthSegments, heightSegments int) *Geometry {
return NewSphereSector(radius, widthSegments, heightSegments, 0, math.Pi*2, 0, math.Pi)
}
// NewSphereSector creates a sphere sector geometry with the specified radius, number of radial segments in each dimension, elevation
// start angle in radians, elevation size angle in radians, sector start angle in radians, and sector size angle in radians.
func NewSphereSector(radius float64, widthSegments, heightSegments int, phiStart, phiLength, thetaStart, thetaLength float64) *Geometry {
s := NewGeometry()
thetaEnd := thetaStart + thetaLength
vertexCount := (widthSegments + 1) * (heightSegments + 1)
// Create buffers
positions := math32.NewArrayF32(vertexCount*3, vertexCount*3)
normals := math32.NewArrayF32(vertexCount*3, vertexCount*3)
uvs := math32.NewArrayF32(vertexCount*2, vertexCount*2)
indices := math32.NewArrayU32(0, vertexCount)
index := 0
vertices := make([][]uint32, 0)
var normal math32.Vector3
for y := 0; y <= heightSegments; y++ {
verticesRow := make([]uint32, 0)
v := float64(y) / float64(heightSegments)
for x := 0; x <= widthSegments; x++ {
u := float64(x) / float64(widthSegments)
px := -radius * math.Cos(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
py := radius * math.Cos(thetaStart+v*thetaLength)
pz := radius * math.Sin(phiStart+u*phiLength) * math.Sin(thetaStart+v*thetaLength)
normal.Set(float32(px), float32(py), float32(pz)).Normalize()
positions.Set(index*3, float32(px), float32(py), float32(pz))
normals.SetVector3(index*3, &normal)
uvs.Set(index*2, float32(u), float32(v))
verticesRow = append(verticesRow, uint32(index))
index++
}
vertices = append(vertices, verticesRow)
}
for y := 0; y < heightSegments; y++ {
for x := 0; x < widthSegments; x++ {
v1 := vertices[y][x+1]
v2 := vertices[y][x]
v3 := vertices[y+1][x]
v4 := vertices[y+1][x+1]
if y != 0 || thetaStart > 0 {
indices.Append(v1, v2, v4)
}
if y != heightSegments-1 || thetaEnd < math.Pi {
indices.Append(v2, v3, v4)
}
}
}
s.SetIndices(indices)
s.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
s.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
s.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
r := float32(radius)
// Update bounding sphere
s.boundingSphere.Radius = 3
s.boundingSphereValid = true
// Update bounding box
s.boundingBox = math32.Box3{math32.Vector3{-r, -r, -r}, math32.Vector3{r, r, r}}
s.boundingBoxValid = true
return s
}