basic rendering, buggy monkey
This commit is contained in:
parent
6046cea17c
commit
6c9218f8f5
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
opengl-deferred
|
2
assets/geometries/suzanne.mtl
Normal file
2
assets/geometries/suzanne.mtl
Normal file
@ -0,0 +1,2 @@
|
||||
# Blender 3.4.1 MTL File: 'None'
|
||||
# www.blender.org
|
3485
assets/geometries/suzanne.obj
Normal file
3485
assets/geometries/suzanne.obj
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,27 +1,28 @@
|
||||
#version 460 core
|
||||
|
||||
layout (location = 0) in vec3 _pos;
|
||||
layout (location = 1) in vec3 _norm;
|
||||
layout (location = 2) in vec2 _tex;
|
||||
layout (location = 3) in uint _id;
|
||||
uniform sampler2D s_albedo;
|
||||
uniform sampler2D s_normal;
|
||||
uniform sampler2D s_specular;
|
||||
uniform sampler2D s_roughness;
|
||||
uniform sampler2D s_metalic;
|
||||
|
||||
layout (std140) uniform matrices
|
||||
{
|
||||
mat4 projection;
|
||||
mat4 camera;
|
||||
}
|
||||
in vec3 pos;
|
||||
in vec3 norm;
|
||||
in vec2 tex;
|
||||
|
||||
uniform mat4 model;
|
||||
|
||||
out vec3 pos;
|
||||
out vec3 norm;
|
||||
out vec2 tex;
|
||||
out vec2 id;
|
||||
out vec4 FragColor;
|
||||
out vec3 position;
|
||||
out vec3 albedo;
|
||||
out vec3 normal;
|
||||
out vec3 material;
|
||||
|
||||
void main() {
|
||||
gl_Position = projection * camera * model * vec4(_pos, 1.0);
|
||||
pos = vec3(model * vec4(_pos, 1.0));
|
||||
norm = _norm;
|
||||
tex = _tex;
|
||||
id = _id;
|
||||
position = pos;
|
||||
albedo = texture(s_albedo, tex).rgb;
|
||||
normal = texture(s_normal, tex).rgb;
|
||||
material.x = texture(s_specular, tex).x;
|
||||
material.y = texture(s_roughness, tex).y;
|
||||
material.z = texture(s_metalic, tex).z;
|
||||
|
||||
FragColor = texture(s_albedo, tex);
|
||||
}
|
@ -1,32 +1,21 @@
|
||||
#version 460
|
||||
#version 460 core
|
||||
|
||||
struct material_t {
|
||||
sampler2D albedo;
|
||||
sampler2D normal;
|
||||
sampler2D specular;
|
||||
sampler2D rougness;
|
||||
sampler2D metalic;
|
||||
};
|
||||
layout (location = 0) in vec3 _pos;
|
||||
layout (location = 1) in vec3 _norm;
|
||||
layout (location = 2) in vec2 _tex;
|
||||
layout (location = 3) in uint _id;
|
||||
|
||||
layout (std140) buffer material_buffer {
|
||||
material_t materials[];
|
||||
};
|
||||
uniform mat4 projection;
|
||||
uniform mat4 camera;
|
||||
uniform mat4 model;
|
||||
|
||||
in vec3 pos;
|
||||
in vec3 norm;
|
||||
in vec2 tex;
|
||||
in uint id;
|
||||
|
||||
out vec3 position;
|
||||
out vec3 albedo;
|
||||
out vec3 normal;
|
||||
out vec3 material;
|
||||
out vec3 pos;
|
||||
out vec3 norm;
|
||||
out vec2 tex;
|
||||
|
||||
void main() {
|
||||
position = pos;
|
||||
albedo = texture(materials[id].albedo, tex).rgb;
|
||||
normal = texture(materials[id].normal, tex).rgb;
|
||||
material.x = texture(materials[id].specular, tex).x;
|
||||
material.y = texture(materials[id].rougness, tex).y;
|
||||
material.z = texture(materials[id].metalic, tex).z;
|
||||
gl_Position = projection * camera * model * vec4(_pos, 1.0);
|
||||
pos = vec3(model * vec4(_pos, 1.0));
|
||||
norm = _norm;
|
||||
tex = _tex;
|
||||
}
|
1
go.mod
1
go.mod
@ -6,4 +6,5 @@ require (
|
||||
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/mathgl v1.1.0 // indirect
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f // indirect
|
||||
)
|
||||
|
1
go.sum
1
go.sum
@ -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/mathgl v1.1.0 h1:0lzZ+rntPX3/oGrDzYGdowSLC2ky8Osirvf5uAwfIEA=
|
||||
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
92
main.go
92
main.go
@ -3,20 +3,27 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"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/texture"
|
||||
"github.com/go-gl/gl/v4.6-core/gl"
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
const (
|
||||
WIDTH = 640
|
||||
HEIGHT = 480
|
||||
TITLE = "opengl-deferred"
|
||||
FOV = 45.0
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// init glfw
|
||||
runtime.LockOSThread()
|
||||
if err := glfw.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -34,11 +41,16 @@ func main() {
|
||||
}
|
||||
window.MakeContextCurrent()
|
||||
|
||||
// init glow
|
||||
// init gl
|
||||
if err := gl.Init(); err != nil {
|
||||
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)))
|
||||
|
||||
// load assets
|
||||
@ -58,5 +70,83 @@ func main() {
|
||||
}
|
||||
defer deferredShader.Delete()
|
||||
|
||||
// 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
219
types/geometry/geometry.go
Normal 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
|
||||
}
|
@ -5,11 +5,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/gl/v4.6-core/gl"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
type Shader struct {
|
||||
program uint32
|
||||
uniforms map[string]uint32
|
||||
uniforms map[string]int32
|
||||
}
|
||||
|
||||
func (s *Shader) Use() {
|
||||
@ -20,6 +21,25 @@ func (s *Shader) Delete() {
|
||||
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) {
|
||||
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) {
|
||||
shader.uniforms = make(map[string]uint32)
|
||||
shader.uniforms = make(map[string]int32)
|
||||
|
||||
vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
|
58
types/texture/texture.go
Normal file
58
types/texture/texture.go
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user