170 lines
3.9 KiB
Go
170 lines
3.9 KiB
Go
package geometry
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/go-gl/gl/v4.6-core/gl"
|
|
"github.com/go-gl/mathgl/mgl32"
|
|
"github.com/udhos/gwob"
|
|
)
|
|
|
|
// attributes:
|
|
// position 3 * float
|
|
// texture 2 * float
|
|
// normal 3 * float
|
|
// tangent 3 * float
|
|
|
|
type Geometry struct {
|
|
vao uint32
|
|
vbo uint32
|
|
ebo uint32
|
|
size int32
|
|
}
|
|
|
|
func (g Geometry) Draw() {
|
|
gl.BindVertexArray(g.vao)
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, g.vbo)
|
|
gl.DrawElementsWithOffset(gl.TRIANGLES, g.size, gl.UNSIGNED_INT, 0)
|
|
}
|
|
|
|
func (g Geometry) Delete() {
|
|
gl.DeleteVertexArrays(1, &g.vao)
|
|
gl.DeleteBuffers(1, &g.ebo)
|
|
gl.DeleteBuffers(1, &g.vbo)
|
|
}
|
|
|
|
func new(coords []float32, indicies []int) (Geometry, error) {
|
|
var geometry Geometry
|
|
|
|
unsignedIndicies := make([]uint32, len(indicies))
|
|
for i, v := range indicies {
|
|
unsignedIndicies[i] = uint32(v)
|
|
}
|
|
|
|
// vao
|
|
gl.GenVertexArrays(1, &geometry.vao)
|
|
gl.BindVertexArray(geometry.vao)
|
|
|
|
// vbo
|
|
gl.GenBuffers(1, &geometry.vbo)
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, geometry.vbo)
|
|
gl.BufferData(gl.ARRAY_BUFFER, len(coords)*4, gl.Ptr(coords), gl.STATIC_DRAW)
|
|
|
|
var i uint32 = 0
|
|
|
|
// attributes
|
|
// position
|
|
gl.VertexAttribPointerWithOffset(i, 3, gl.FLOAT, false, 11*4, 0)
|
|
gl.EnableVertexAttribArray(i)
|
|
i++
|
|
|
|
// texture
|
|
gl.VertexAttribPointerWithOffset(i, 2, gl.FLOAT, false, 11*4, 3*4)
|
|
gl.EnableVertexAttribArray(i)
|
|
i++
|
|
|
|
// normal
|
|
gl.VertexAttribPointerWithOffset(2, 3, gl.FLOAT, false, 11*4, 5*4)
|
|
gl.EnableVertexAttribArray(i)
|
|
i++
|
|
|
|
// tangent
|
|
gl.VertexAttribPointerWithOffset(i, 3, gl.FLOAT, false, 11*4, 8*4)
|
|
gl.EnableVertexAttribArray(i)
|
|
i++
|
|
|
|
// ebo
|
|
gl.GenBuffers(1, &geometry.ebo)
|
|
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.ebo)
|
|
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(unsignedIndicies)*4, gl.Ptr(unsignedIndicies), gl.STATIC_DRAW)
|
|
geometry.size = int32(len(indicies))
|
|
|
|
return geometry, nil
|
|
}
|
|
|
|
func LoadOBJ(path string) (geometry Geometry, err error) {
|
|
o, err := gwob.NewObjFromFile(path, &gwob.ObjParserOptions{})
|
|
if err != nil {
|
|
return geometry, err
|
|
}
|
|
|
|
if !o.NormCoordFound {
|
|
return geometry, errors.New("missing normals in OBJ")
|
|
}
|
|
|
|
if !o.TextCoordFound {
|
|
return geometry, errors.New("missing texture UVs in OBJ")
|
|
}
|
|
|
|
// add tangent
|
|
coords := make([]float32, 0, len(o.Coord)*11)
|
|
tangents := make([][3]float32, len(o.Coord)/8)
|
|
|
|
// iterate faces
|
|
for i := 0; i < len(o.Indices); i += 3 {
|
|
i0 := o.Indices[i+0]
|
|
i1 := o.Indices[i+1]
|
|
i2 := o.Indices[i+2]
|
|
|
|
// positions
|
|
v0 := o.Coord[i0*8 : i0*8+3]
|
|
v1 := o.Coord[i1*8 : i1*8+3]
|
|
v2 := o.Coord[i2*8 : i2*8+3]
|
|
|
|
// UVs
|
|
uv0 := o.Coord[i0*8+3 : i0*8+5]
|
|
uv1 := o.Coord[i1*8+3 : i1*8+5]
|
|
uv2 := o.Coord[i2*8+3 : i2*8+5]
|
|
|
|
// edges
|
|
edge1 := [3]float32{v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]}
|
|
edge2 := [3]float32{v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]}
|
|
|
|
// UV deltas
|
|
delta1 := [2]float32{uv1[0] - uv0[0], uv1[1] - uv0[1]}
|
|
delta2 := [2]float32{uv2[0] - uv0[0], uv2[1] - uv0[1]}
|
|
|
|
// calculate tangents
|
|
f := 1.0 / (delta1[0]*delta2[1] - delta2[0]*delta1[1])
|
|
tangent := [3]float32{
|
|
f * (delta2[1]*edge1[0] - delta1[1]*edge2[0]),
|
|
f * (delta2[1]*edge1[1] - delta1[1]*edge2[1]),
|
|
f * (delta2[1]*edge1[2] - delta1[1]*edge2[2]),
|
|
}
|
|
|
|
tangents[i0] = mgl32.Vec3(tangents[i0]).Add(tangent)
|
|
tangents[i1] = mgl32.Vec3(tangents[i1]).Add(tangent)
|
|
tangents[i2] = mgl32.Vec3(tangents[i2]).Add(tangent)
|
|
}
|
|
|
|
// build coords
|
|
for i := 0; i < len(o.Coord)/8; i++ {
|
|
pos := o.Coord[i*8 : i*8+3]
|
|
uv := o.Coord[i*8+3 : i*8+5]
|
|
norm := o.Coord[i*8+5 : i*8+8]
|
|
tan := mgl32.Vec3(tangents[i]).Normalize()
|
|
|
|
coords = append(coords, pos...)
|
|
coords = append(coords, uv...)
|
|
coords = append(coords, norm...)
|
|
coords = append(coords, tan[0:3]...)
|
|
}
|
|
|
|
return new(coords, o.Indices)
|
|
}
|
|
|
|
func Screen() (Geometry, error) {
|
|
return new(
|
|
[]float32{
|
|
// xyz, uv, nrm, tan
|
|
-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
|
-1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
|
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
[]int{
|
|
0, 1, 2,
|
|
1, 3, 2,
|
|
})
|
|
}
|