|
|
@@ -0,0 +1,205 @@
|
|
|
+// 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.
|
|
|
+// TODO: UVs, Caps
|
|
|
+
|
|
|
+package geometry
|
|
|
+
|
|
|
+import (
|
|
|
+ "github.com/g3n/engine/math32"
|
|
|
+ "github.com/g3n/engine/gls"
|
|
|
+ "math"
|
|
|
+)
|
|
|
+
|
|
|
+func CalculateNormals(indices math32.ArrayU32, positions, normals math32.ArrayF32) math32.ArrayF32 {
|
|
|
+ var x1x2, y1y2, z1z2, x3x2, y3y2, z3z2, x, y, z, l float32
|
|
|
+ var x1, y1, z1, x2, y2, z2, x3, y3, z3 int // position indexes
|
|
|
+
|
|
|
+ for i := 0; i < len(indices) / 3; i++ {
|
|
|
+ x1 = int(indices[i * 3] * uint32(3))
|
|
|
+ y1 = x1 + 1
|
|
|
+ z1 = x1 + 2
|
|
|
+ x2 = int(indices[i * 3 + 1] * uint32(3))
|
|
|
+ y2 = x2 + 1
|
|
|
+ z2 = x2 + 2
|
|
|
+ x3 = int(indices[i * 3 + 2] * uint32(3))
|
|
|
+ y3 = x3 + 1
|
|
|
+ z3 = x3 + 2
|
|
|
+
|
|
|
+ x1x2 = positions[x1] - positions[x2]
|
|
|
+ y1y2 = positions[y1] - positions[y2]
|
|
|
+ z1z2 = positions[z1] - positions[z2]
|
|
|
+ x3x2 = positions[x3] - positions[x2]
|
|
|
+ y3y2 = positions[y3] - positions[y2]
|
|
|
+ z3z2 = positions[z3] - positions[z2]
|
|
|
+
|
|
|
+ x = y1y2 * z3z2 - z1z2 * y3y2
|
|
|
+ y = z1z2 * x3x2 - x1x2 * z3z2
|
|
|
+ z = x1x2 * y3y2 - y1y2 * x3x2
|
|
|
+
|
|
|
+ l = float32(math.Sqrt(float64(x) * float64(x) + float64(y) * float64(y) + float64(z) * float64(z)))
|
|
|
+ if l == 0 {
|
|
|
+ l = 1.0
|
|
|
+ }
|
|
|
+
|
|
|
+ normals[x1] += x / l
|
|
|
+ normals[y1] += y / l
|
|
|
+ normals[z1] += z / l
|
|
|
+ normals[x2] += x / l
|
|
|
+ normals[y2] += y / l
|
|
|
+ normals[z2] += z / l
|
|
|
+ normals[x3] += x / l
|
|
|
+ normals[y3] += y / l
|
|
|
+ normals[z3] += z / l
|
|
|
+ }
|
|
|
+ for i := 0; i < len(normals) / 3; i++ {
|
|
|
+ x = normals[i * 3]
|
|
|
+ y = normals[i * 3 + 1]
|
|
|
+ z = normals[i * 3 + 2]
|
|
|
+ l = float32(math.Sqrt(float64(x) * float64(x) + float64(y) * float64(y) + float64(z) * float64(z)))
|
|
|
+ if l == 0 {
|
|
|
+ l = 1.0
|
|
|
+ }
|
|
|
+ normals[i * 3] = x / l
|
|
|
+ normals[i * 3 + 1] = y / l
|
|
|
+ normals[i * 3 + 2] = z / l
|
|
|
+ }
|
|
|
+ return normals
|
|
|
+}
|
|
|
+
|
|
|
+func NewRibbon(paths [][]math32.Vector3, close bool) *Geometry {
|
|
|
+ /*
|
|
|
+ if len(paths) < 3 {
|
|
|
+ close = false
|
|
|
+ }
|
|
|
+ */
|
|
|
+ c := NewGeometry()
|
|
|
+
|
|
|
+ var ls, is []int // path lengths, path indexes
|
|
|
+ positions := math32.NewArrayF32(0, 0)
|
|
|
+ indices := math32.NewArrayU32(0, 0)
|
|
|
+
|
|
|
+ i := 0
|
|
|
+ for p := 0; p < len(paths); p++ {
|
|
|
+ path := paths[p]
|
|
|
+ l := len(path)
|
|
|
+ ls = append(ls, l)
|
|
|
+ is = append(is, i)
|
|
|
+ for j := 0; j < l; j++ {
|
|
|
+ positions.AppendVector3(&path[j])
|
|
|
+ }
|
|
|
+ i += l
|
|
|
+ }
|
|
|
+
|
|
|
+ l1 := ls[0] - 1 // path1 length
|
|
|
+ l2 := ls[1] - 1 // path2 length
|
|
|
+ min := l2
|
|
|
+ if l1 < l2 {
|
|
|
+ min = l1
|
|
|
+ }
|
|
|
+ p := 0
|
|
|
+ i = 0
|
|
|
+ for i <= min && p < len(ls) - 1 {
|
|
|
+ t := is[p+1] - is[p]
|
|
|
+
|
|
|
+ indices.Append(uint32(i), uint32(i+t), uint32(i+1))
|
|
|
+ indices.Append(uint32(i+t+1), uint32(i+1), uint32(i+t))
|
|
|
+ i++
|
|
|
+ if i == min {
|
|
|
+ if close {
|
|
|
+ indices.Append(uint32(i), uint32(i+t), uint32(is[p]))
|
|
|
+ indices.Append(uint32(is[p]+t), uint32(is[p]), uint32(i+t))
|
|
|
+ }
|
|
|
+ p++
|
|
|
+ if p == len(ls) - 1 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ l1 = ls[p] - 1
|
|
|
+ l2 = ls[p+1] - 1
|
|
|
+ i = is[p]
|
|
|
+ if l1 < l2 {
|
|
|
+ min = l1 + i
|
|
|
+ } else {
|
|
|
+ min = l2 + i
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ normals := math32.NewArrayF32(positions.Size(), positions.Size())
|
|
|
+ normals = CalculateNormals(indices, positions, normals)
|
|
|
+
|
|
|
+ c.SetIndices(indices)
|
|
|
+ c.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
|
|
|
+ c.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
|
|
|
+
|
|
|
+ return c
|
|
|
+}
|
|
|
+
|
|
|
+func NewTube(path []math32.Vector3, radius float32, radialSegments int, close bool) *Geometry {
|
|
|
+ l := len(path)
|
|
|
+
|
|
|
+ var tangents, normals, binormals []math32.Vector3
|
|
|
+ tangents = make([]math32.Vector3, l)
|
|
|
+ normals = make([]math32.Vector3, l)
|
|
|
+ binormals = make([]math32.Vector3, l)
|
|
|
+
|
|
|
+ tangents[0] = *path[1].Clone().Sub(&path[0])
|
|
|
+ tangents[0].Normalize()
|
|
|
+ tangents[l-1] = *path[l-1].Clone().Sub(&path[l-2])
|
|
|
+ tangents[l-1].Normalize()
|
|
|
+
|
|
|
+ var tmpVertex *math32.Vector3
|
|
|
+ if (tangents[0].X != 1) {
|
|
|
+ tmpVertex = math32.NewVector3(1, 0, 0)
|
|
|
+ } else if (tangents[0].Y != 1) {
|
|
|
+ tmpVertex = math32.NewVector3(0, 1, 0)
|
|
|
+ } else if (tangents[0].Z != 1) {
|
|
|
+ tmpVertex = math32.NewVector3(0, 0, 1)
|
|
|
+ }
|
|
|
+
|
|
|
+ normals[0] = *tangents[0].Clone().Cross(tmpVertex)
|
|
|
+ normals[0].Normalize()
|
|
|
+ binormals[0] = *tangents[0].Clone().Cross(&normals[0])
|
|
|
+ binormals[0].Normalize()
|
|
|
+
|
|
|
+ for i := 1; i < l; i++ {
|
|
|
+ prev := *path[i].Clone().Sub(&path[i-1])
|
|
|
+ if (i < l-1) {
|
|
|
+ cur := *path[i+1].Clone().Sub(&path[i])
|
|
|
+ tangents[i] = *prev.Clone().Add(&cur)
|
|
|
+ tangents[i].Normalize()
|
|
|
+
|
|
|
+ }
|
|
|
+ normals[i] = *binormals[i-1].Clone().Cross(&tangents[i])
|
|
|
+ normals[i].Normalize()
|
|
|
+ binormals[i] = *tangents[i].Clone().Cross(&normals[i])
|
|
|
+ binormals[i].Normalize()
|
|
|
+ }
|
|
|
+
|
|
|
+ pi2 := math.Pi * 2
|
|
|
+ step := pi2 / float64(radialSegments)
|
|
|
+
|
|
|
+ var radialPaths [][]math32.Vector3
|
|
|
+ for i := 0; i < l; i++ {
|
|
|
+ var radialPath []math32.Vector3
|
|
|
+ var ang float32
|
|
|
+ for ang = 0.0; ang < float32(pi2); ang += float32(step) {
|
|
|
+ matrix := math32.NewMatrix4()
|
|
|
+ matrix.MakeRotationAxis(&tangents[i], ang)
|
|
|
+
|
|
|
+ x := normals[i].X
|
|
|
+ y := normals[i].Y
|
|
|
+ z := normals[i].Z
|
|
|
+ rw := 1 / (x * matrix[3] + y * matrix[7] + z * matrix[11] + matrix[15])
|
|
|
+ newX := (x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12]) * rw
|
|
|
+ newY := (x * matrix[1] + y * matrix[5] + z * matrix[9] + matrix[13]) * rw
|
|
|
+ newZ := (x * matrix[2] + y * matrix[6] + z * matrix[10] + matrix[14]) * rw
|
|
|
+
|
|
|
+ rotated := math32.NewVector3(newX, newY, newZ).MultiplyScalar(radius).Add(&path[i])
|
|
|
+ radialPath = append(radialPath, *rotated)
|
|
|
+ }
|
|
|
+ radialPaths = append(radialPaths, radialPath)
|
|
|
+ }
|
|
|
+
|
|
|
+ return NewRibbon(radialPaths, close)
|
|
|
+}
|