opengl-deferred/types/geometry/geometry.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,
})
}