basic rendering, buggy monkey

This commit is contained in:
BENEDEK László 2024-10-12 01:02:12 +02:00
parent 6046cea17c
commit 6c9218f8f5
11 changed files with 3917 additions and 50 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
opengl-deferred

View File

@ -0,0 +1,2 @@
# Blender 3.4.1 MTL File: 'None'
# www.blender.org

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,28 @@
#version 460 core #version 460 core
layout (location = 0) in vec3 _pos; uniform sampler2D s_albedo;
layout (location = 1) in vec3 _norm; uniform sampler2D s_normal;
layout (location = 2) in vec2 _tex; uniform sampler2D s_specular;
layout (location = 3) in uint _id; uniform sampler2D s_roughness;
uniform sampler2D s_metalic;
layout (std140) uniform matrices in vec3 pos;
{ in vec3 norm;
mat4 projection; in vec2 tex;
mat4 camera;
}
uniform mat4 model; out vec4 FragColor;
out vec3 position;
out vec3 pos; out vec3 albedo;
out vec3 norm; out vec3 normal;
out vec2 tex; out vec3 material;
out vec2 id;
void main() { void main() {
gl_Position = projection * camera * model * vec4(_pos, 1.0); position = pos;
pos = vec3(model * vec4(_pos, 1.0)); albedo = texture(s_albedo, tex).rgb;
norm = _norm; normal = texture(s_normal, tex).rgb;
tex = _tex; material.x = texture(s_specular, tex).x;
id = _id; material.y = texture(s_roughness, tex).y;
material.z = texture(s_metalic, tex).z;
FragColor = texture(s_albedo, tex);
} }

View File

@ -1,32 +1,21 @@
#version 460 #version 460 core
struct material_t { layout (location = 0) in vec3 _pos;
sampler2D albedo; layout (location = 1) in vec3 _norm;
sampler2D normal; layout (location = 2) in vec2 _tex;
sampler2D specular; layout (location = 3) in uint _id;
sampler2D rougness;
sampler2D metalic;
};
layout (std140) buffer material_buffer { uniform mat4 projection;
material_t materials[]; uniform mat4 camera;
}; uniform mat4 model;
in vec3 pos; out vec3 pos;
in vec3 norm; out vec3 norm;
in vec2 tex; out vec2 tex;
in uint id;
out vec3 position;
out vec3 albedo;
out vec3 normal;
out vec3 material;
void main() { void main() {
position = pos; gl_Position = projection * camera * model * vec4(_pos, 1.0);
albedo = texture(materials[id].albedo, tex).rgb; pos = vec3(model * vec4(_pos, 1.0));
normal = texture(materials[id].normal, tex).rgb; norm = _norm;
material.x = texture(materials[id].specular, tex).x; tex = _tex;
material.y = texture(materials[id].rougness, tex).y;
material.z = texture(materials[id].metalic, tex).z;
} }

1
go.mod
View File

@ -6,4 +6,5 @@ require (
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-gl/mathgl v1.1.0 // indirect github.com/go-gl/mathgl v1.1.0 // indirect
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f // indirect
) )

1
go.sum
View File

@ -4,5 +4,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/mathgl v1.1.0 h1:0lzZ+rntPX3/oGrDzYGdowSLC2ky8Osirvf5uAwfIEA= github.com/go-gl/mathgl v1.1.0 h1:0lzZ+rntPX3/oGrDzYGdowSLC2ky8Osirvf5uAwfIEA=
github.com/go-gl/mathgl v1.1.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ= github.com/go-gl/mathgl v1.1.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f h1:FO4MZ3N56GnxbqxGKqh+YTzUWQ2sDwtFQEZgLOxh9Jc=
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

94
main.go
View File

@ -3,20 +3,27 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"runtime"
"git.tek.govt.hu/dowerx/opengl-deferred/types/geometry"
"git.tek.govt.hu/dowerx/opengl-deferred/types/shader" "git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
"git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
"github.com/go-gl/gl/v4.6-core/gl" "github.com/go-gl/gl/v4.6-core/gl"
"github.com/go-gl/glfw/v3.3/glfw" "github.com/go-gl/glfw/v3.3/glfw"
"github.com/go-gl/mathgl/mgl32"
) )
const ( const (
WIDTH = 640 WIDTH = 640
HEIGHT = 480 HEIGHT = 480
TITLE = "opengl-deferred" TITLE = "opengl-deferred"
FOV = 45.0
) )
func main() { func main() {
// init glfw // init glfw
runtime.LockOSThread()
if err := glfw.Init(); err != nil { if err := glfw.Init(); err != nil {
panic(err) panic(err)
} }
@ -34,11 +41,16 @@ func main() {
} }
window.MakeContextCurrent() window.MakeContextCurrent()
// init glow // init gl
if err := gl.Init(); err != nil { if err := gl.Init(); err != nil {
panic(err) panic(err)
} }
gl.Enable(gl.DEPTH_TEST)
gl.Enable(gl.CULL_FACE)
gl.DepthFunc(gl.LESS)
gl.ClearColor(0, 0, 0, 0)
fmt.Println("OpenGL version:", gl.GoStr(gl.GetString(gl.VERSION))) fmt.Println("OpenGL version:", gl.GoStr(gl.GetString(gl.VERSION)))
// load assets // load assets
@ -58,5 +70,83 @@ func main() {
} }
defer deferredShader.Delete() defer deferredShader.Delete()
deferredShader.Use() // geometry
geometries, err := geometry.LoadOBJ("assets/geometries/suzanne.obj")
if err != nil {
panic(err)
}
defer func() {
for _, geometry := range geometries {
geometry.Delete()
}
}()
// textures
albedo, err := texture.Load("assets/textures/demo.png")
if err != nil {
panic(err)
}
defer albedo.Delete()
normal, err := texture.Load("assets/textures/demo.png")
if err != nil {
panic(err)
}
defer normal.Delete()
specular, err := texture.Load("assets/textures/demo.png")
if err != nil {
panic(err)
}
defer specular.Delete()
roughness, err := texture.Load("assets/textures/demo.png")
if err != nil {
panic(err)
}
defer roughness.Delete()
metalic, err := texture.Load("assets/textures/demo.png")
if err != nil {
panic(err)
}
defer metalic.Delete()
// transformations
projection := mgl32.Perspective(mgl32.DegToRad(FOV), float32(WIDTH)/HEIGHT, 0.1, 10)
camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
model := mgl32.Ident4()
// set textures
albedo.Bind(gl.TEXTURE0)
normal.Bind(gl.TEXTURE1)
specular.Bind(gl.TEXTURE2)
roughness.Bind(gl.TEXTURE3)
metalic.Bind(gl.TEXTURE4)
// transfer uniforms
deferredShader.Use()
deferredShader.Mat4("projection", projection)
deferredShader.Mat4("camera", camera)
deferredShader.Mat4("model", model)
deferredShader.Int("s_albedo", 0)
deferredShader.Int("s_normal", 1)
deferredShader.Int("s_specular", 2)
deferredShader.Int("s_roughness", 3)
deferredShader.Int("s_metalic", 4)
for !window.ShouldClose() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
// render
for _, g := range geometries {
g.Draw()
}
window.SwapBuffers()
glfw.PollEvents()
}
defer fmt.Println("exiting...")
} }

219
types/geometry/geometry.go Normal file
View File

@ -0,0 +1,219 @@
package geometry
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"github.com/go-gl/gl/v4.6-core/gl"
)
// attributes:
// position 3 * float
// normal 3 * float
// texture coordinates 2 * 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)
}
type vec struct {
Values []float32
}
type point struct {
Vertex int
Normal int
Uv int
}
type face struct {
Points [3]point
}
func new(vertices []vec, normals []vec, uvs []vec, faces []face) (Geometry, error) {
fmt.Println(len(vertices), len(normals), len(uvs), len(faces))
i := 0
points := make(map[point]int)
indicies := []uint{}
for _, face := range faces {
for _, point := range face.Points {
if val, ok := points[point]; !ok {
points[point] = i
indicies = append(indicies, uint(i))
i++
} else {
indicies = append(indicies, uint(val))
}
}
}
rPoints := make(map[int]point)
for k, v := range points {
rPoints[v] = k
}
buffer := make([]float32, len(rPoints)*8)
for i := 0; i < len(rPoints); i++ {
v := rPoints[i]
buffer[i*8+0] = vertices[v.Vertex].Values[0]
buffer[i*8+1] = vertices[v.Vertex].Values[1]
buffer[i*8+2] = vertices[v.Vertex].Values[2]
buffer[i*8+3] = normals[v.Normal].Values[0]
buffer[i*8+4] = normals[v.Normal].Values[1]
buffer[i*8+5] = normals[v.Normal].Values[2]
buffer[i*8+6] = uvs[v.Uv].Values[0]
buffer[i*8+7] = uvs[v.Uv].Values[1]
}
var geometry Geometry
// 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(buffer)*4, gl.Ptr(buffer), gl.STATIC_DRAW)
// attributes
gl.VertexAttribPointerWithOffset(0, 3, gl.FLOAT, false, 8*4, 0)
gl.EnableVertexAttribArray(0)
gl.VertexAttribPointerWithOffset(1, 3, gl.FLOAT, false, 8*4, 3*4)
gl.EnableVertexAttribArray(1)
gl.VertexAttribPointerWithOffset(2, 2, gl.FLOAT, false, 8*4, 6*4)
gl.EnableVertexAttribArray(2)
// ebo
gl.GenBuffers(1, &geometry.ebo)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.ebo)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indicies)*4, gl.Ptr(indicies), gl.STATIC_DRAW)
geometry.size = int32(len(indicies))
return geometry, nil
}
func LoadOBJ(path string) (geometries []Geometry, err error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
var vertices []vec
var normals []vec
var uvs []vec
var faces []face
scanner := bufio.NewScanner(file)
for scanner.Scan() {
switch scanner.Text()[0:2] {
case "# ":
continue
case "mt":
fmt.Println("material ignored")
continue
case "o ":
if len(vertices) != 0 {
geometry, err := new(vertices, normals, uvs, faces)
if err != nil {
return nil, err
}
geometries = append(geometries, geometry)
}
case "v ":
parts := strings.Split(scanner.Text(), " ")
vertex := vec{}
for i := 1; i < 4; i++ {
value, err := strconv.ParseFloat(parts[i], 32)
if err != nil {
return nil, err
}
vertex.Values = append(vertex.Values, float32(value))
}
vertices = append(vertices, vertex)
case "vn":
parts := strings.Split(scanner.Text(), " ")
normal := vec{}
for i := 1; i < 4; i++ {
value, err := strconv.ParseFloat(parts[i], 32)
if err != nil {
return nil, err
}
normal.Values = append(normal.Values, float32(value))
}
normals = append(normals, normal)
case "vt":
parts := strings.Split(scanner.Text(), " ")
uv := vec{}
for i := 1; i < 3; i++ {
value, err := strconv.ParseFloat(parts[i], 32)
if err != nil {
return nil, err
}
uv.Values = append(uv.Values, float32(value))
}
uvs = append(uvs, uv)
case "f ":
parts := strings.Split(scanner.Text(), " ")
face := face{}
for i, part := range parts[1:] {
bits := strings.Split(part, "/")
v, err := strconv.Atoi(bits[0])
if err != nil {
return nil, err
}
t, err := strconv.Atoi(bits[1])
if err != nil {
return nil, err
}
n, err := strconv.Atoi(bits[2])
if err != nil {
return nil, err
}
face.Points[i].Vertex = v - 1
face.Points[i].Normal = n - 1
face.Points[i].Uv = t - 1
}
faces = append(faces, face)
}
}
geometry, err := new(vertices, normals, uvs, faces)
if err != nil {
return nil, err
}
geometries = append(geometries, geometry)
return geometries, err
}

View File

@ -5,11 +5,12 @@ import (
"strings" "strings"
"github.com/go-gl/gl/v4.6-core/gl" "github.com/go-gl/gl/v4.6-core/gl"
"github.com/go-gl/mathgl/mgl32"
) )
type Shader struct { type Shader struct {
program uint32 program uint32
uniforms map[string]uint32 uniforms map[string]int32
} }
func (s *Shader) Use() { func (s *Shader) Use() {
@ -20,6 +21,25 @@ func (s *Shader) Delete() {
gl.DeleteProgram(s.program) gl.DeleteProgram(s.program)
} }
func (s *Shader) getUniformLocation(name string) int32 {
if val, ok := s.uniforms[name]; ok {
return val
}
uniform := gl.GetUniformLocation(s.program, gl.Str(name+"\x00"))
s.uniforms[name] = uniform
return uniform
}
func (s *Shader) Mat4(name string, mat mgl32.Mat4) {
gl.UniformMatrix4fv(s.getUniformLocation(name), 1, false, &mat[0])
}
func (s *Shader) Int(name string, val int32) {
gl.Uniform1i(s.getUniformLocation(name), val)
}
func compileShader(source string, shaderType uint32) (uint32, error) { func compileShader(source string, shaderType uint32) (uint32, error) {
shader := gl.CreateShader(shaderType) shader := gl.CreateShader(shaderType)
@ -44,7 +64,7 @@ func compileShader(source string, shaderType uint32) (uint32, error) {
} }
func New(vertexSource string, fragmantSource string) (shader Shader, _ error) { func New(vertexSource string, fragmantSource string) (shader Shader, _ error) {
shader.uniforms = make(map[string]uint32) shader.uniforms = make(map[string]int32)
vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER) vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER)
if err != nil { if err != nil {

58
types/texture/texture.go Normal file
View File

@ -0,0 +1,58 @@
package texture
import (
"errors"
"image"
"image/draw"
_ "image/png"
"os"
"github.com/go-gl/gl/v4.6-core/gl"
)
type Texture struct {
texture uint32
}
func (t Texture) Bind(slot uint32) {
gl.ActiveTexture(slot)
gl.BindTexture(gl.TEXTURE_2D, t.texture)
}
func (t Texture) Delete() {
gl.DeleteTextures(1, &t.texture)
}
func Load(path string) (texture Texture, _ error) {
file, err := os.Open(path)
if err != nil {
return texture, err
}
img, _, err := image.Decode(file)
if err != nil {
return texture, err
}
rgba := image.NewRGBA(img.Bounds())
if rgba.Stride != rgba.Rect.Size().X*4 {
return texture, errors.New("unsupported stride")
}
draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)
gl.GenTextures(1, &texture.texture)
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, texture.texture)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
gl.TexImage2D(
gl.TEXTURE_2D, 0, gl.RGBA,
int32(rgba.Rect.Size().X),
int32(rgba.Rect.Size().Y),
0, gl.RGBA, gl.UNSIGNED_BYTE,
gl.Ptr(rgba.Pix))
return texture, nil
}