zworld/plugins/geometry/cylinder/cylinder.go
2024-01-14 22:56:06 +08:00

106 lines
2.6 KiB
Go

package cylinder
import (
"zworld/engine/object"
"zworld/engine/object/mesh"
"zworld/engine/renderapi/color"
"zworld/engine/renderapi/material"
"zworld/engine/renderapi/vertex"
"zworld/plugins/math"
"zworld/plugins/math/vec3"
)
type Cylinder struct {
object.Object
Mesh *Mesh
}
func NewObject(args Args) *Cylinder {
return object.New("Cylinder", &Cylinder{
Mesh: New(args),
})
}
// A Cylinder is a forward rendered colored cyllinder mesh
type Mesh struct {
*mesh.Static
Args
}
type Args struct {
Mat *material.Def
Radius float32
Height float32
Segments int
Color color.T
}
func New(args Args) *Mesh {
if args.Mat == nil {
args.Mat = material.ColoredForward()
}
cyllinder := object.NewComponent(&Mesh{
Static: mesh.New(args.Mat),
Args: args,
})
// this should not run on the main thread
cyllinder.generate()
return cyllinder
}
func (c *Mesh) generate() {
// vertex order: clockwise
data := make([]vertex.C, 2*2*3*c.Segments)
hh := c.Height / 2
sangle := 2 * math.Pi / float32(c.Segments)
color := c.Color.Vec4()
// top
top := vec3.New(0, hh, 0)
bottom := vec3.New(0, -hh, 0)
for i := 0; i < c.Segments; i++ {
o := 12 * i // segment vertex offset
right := sangle * (float32(i) + 0.5)
left := sangle * (float32(i) + 1.5)
topRight := vec3.New(math.Cos(right), 0, -math.Sin(right)).Scaled(c.Radius)
topRight.Y = hh
topLeft := vec3.New(math.Cos(left), 0, -math.Sin(left)).Scaled(c.Radius)
topLeft.Y = hh
bottomRight := vec3.New(math.Cos(right), 0, -math.Sin(right)).Scaled(c.Radius)
bottomRight.Y = -hh
bottomLeft := vec3.New(math.Cos(left), 0, -math.Sin(left)).Scaled(c.Radius)
bottomLeft.Y = -hh
// top face
data[o+0] = vertex.C{P: topLeft, N: vec3.Up, C: color}
data[o+1] = vertex.C{P: top, N: vec3.Up, C: color}
data[o+2] = vertex.C{P: topRight, N: vec3.Up, C: color}
// bottom face
data[o+3] = vertex.C{P: bottomRight, N: vec3.Down, C: color}
data[o+4] = vertex.C{P: bottom, N: vec3.Down, C: color}
data[o+5] = vertex.C{P: bottomLeft, N: vec3.Down, C: color}
// calculate segment normal
nv1 := topRight.Sub(bottomLeft)
nv2 := bottomRight.Sub(bottomLeft)
n := vec3.Cross(nv1, nv2)
// side face 1
data[o+6] = vertex.C{P: topRight, N: n, C: color}
data[o+7] = vertex.C{P: bottomLeft, N: n, C: color}
data[o+8] = vertex.C{P: topLeft, N: n, C: color}
// side face 2
data[o+9] = vertex.C{P: bottomRight, N: n, C: color}
data[o+10] = vertex.C{P: bottomLeft, N: n, C: color}
data[o+11] = vertex.C{P: topRight, N: n, C: color}
}
key := object.Key("cylinder", c)
mesh := vertex.NewTriangles(key, data, []uint16{})
c.VertexData.Set(mesh)
}