From 29e8eff82ac7782efc6c7e37977b10ec1c3e739a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BENEDEK=20L=C3=A1szl=C3=B3?= Date: Sat, 12 Oct 2024 14:31:15 +0200 Subject: [PATCH] lights --- .gitignore | 4 +- assets/shader/deferred/deferred.vs | 4 +- assets/shader/screen/screen.fs | 61 ++++++++++++++++++++++++++---- main.go | 42 +++++++++++++------- types/light/light.go | 20 ++++++++++ types/shader/shader.go | 32 +++++++++++++++- 6 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 types/light/light.go diff --git a/.gitignore b/.gitignore index 4729799..1d541c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -opengl-deferred \ No newline at end of file +opengl-deferred +assets/textures +assets/geometries \ No newline at end of file diff --git a/assets/shader/deferred/deferred.vs b/assets/shader/deferred/deferred.vs index af352a6..d102aee 100644 --- a/assets/shader/deferred/deferred.vs +++ b/assets/shader/deferred/deferred.vs @@ -5,7 +5,7 @@ layout (location = 1) in vec2 _tex; layout (location = 2) in vec3 _norm; uniform mat4 projection; -uniform mat4 camera; +uniform mat4 view; uniform mat4 model; out vec3 pos; @@ -13,7 +13,7 @@ out vec3 norm; out vec2 tex; void main() { - gl_Position = projection * camera * model * vec4(_pos, 1.0); + gl_Position = projection * view * model * vec4(_pos, 1.0); pos = vec3(model * vec4(_pos, 1.0)); norm = _norm; tex = _tex; diff --git a/assets/shader/screen/screen.fs b/assets/shader/screen/screen.fs index f98a12d..e970ddf 100644 --- a/assets/shader/screen/screen.fs +++ b/assets/shader/screen/screen.fs @@ -1,20 +1,65 @@ #version 460 core -uniform sampler2D albedo; -uniform sampler2D depth; -uniform sampler2D normal; -uniform sampler2D material; -uniform sampler2D position; +// gbuffer textures +uniform sampler2D s_albedo; +uniform sampler2D s_depth; +uniform sampler2D s_normal; +uniform sampler2D s_material; +uniform sampler2D s_position; +// lights +#define MAX_LIGHT_COUNT 100 +#define POINT 0 +#define SPOT 1 +#define DIRECTIONAL 2 +#define AMBIENT 3 + +struct light_t { + vec3 color; + vec3 position; + vec3 direction; + float intensity; + int type; +}; + +uniform light_t lights[MAX_LIGHT_COUNT]; +uniform int light_count; + +uniform vec3 view_pos; + +// from vertex shader in vec3 pos; in vec2 tex; out vec4 FragColor; -float map(float value, float min1, float max1, float min2, float max2) { - return min2 + (value - min1) * (max2 - min2) / (max1 - min1); +vec3 albedo; +float depth; +vec3 normal; +vec3 material; // specular, roughness, metalic +vec3 position; + +vec3 calc_light(light_t light) { + vec3 light_dir = normalize(light.position - position); + vec3 view_dir = normalize(view_pos - position); + vec3 reflect_dir = reflect(-light_dir, normal); + + float diffuse = max(dot(normal, light_dir), 0.0); + float specular = pow(max(dot(view_dir, reflect_dir), 0.0), 1 - material.y) * material.x; + + return (diffuse + specular) * light.intensity * light.color / max(pow(length(light.position - position), 2), 1); } void main() { - FragColor = texture(position, tex); + albedo = texture(s_albedo, tex).rgb; + depth = texture(s_depth, tex).x; + normal = (texture(s_normal, tex).rgb * 2) - 1; + material = texture(s_material, tex).xyz; + position = texture(s_position, tex).xyz; + + vec3 light_result; + for (int i = 0; i < light_count; i++) { + light_result += calc_light(lights[i]); + } + FragColor = vec4(albedo * light_result, 1); } \ No newline at end of file diff --git a/main.go b/main.go index 71e9925..d3b4fb7 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "git.tek.govt.hu/dowerx/opengl-deferred/types/gbuffer" "git.tek.govt.hu/dowerx/opengl-deferred/types/geometry" + "git.tek.govt.hu/dowerx/opengl-deferred/types/light" "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" @@ -15,8 +16,8 @@ import ( ) const ( - WIDTH = 640 - HEIGHT = 480 + WIDTH = 800 + HEIGHT = 600 TITLE = "opengl-deferred" FOV = 45.0 ) @@ -48,7 +49,7 @@ func main() { } gl.Enable(gl.DEPTH_TEST) - // gl.Enable(gl.CULL_FACE) + gl.Enable(gl.CULL_FACE) gl.DepthFunc(gl.LESS) gl.ClearColor(0, 0, 0, 0) @@ -87,7 +88,7 @@ func main() { defer screenShader.Delete() // geometry - cube, err := geometry.LoadOBJ("assets/geometries/suzanne.obj") + cube, err := geometry.LoadOBJ("assets/geometries/cube.obj") if err != nil { panic(err) } @@ -130,6 +131,11 @@ func main() { } defer metalic.Delete() + // lights + lights := []light.Light{ + {Color: [3]float32{1, 1, 1}, Position: mgl32.Vec3{3, 3, 3}, Intensity: 10, Type: light.POINT}, + } + // gbuffer gbuff, err := gbuffer.New(WIDTH, HEIGHT) if err != nil { @@ -140,8 +146,8 @@ func main() { // 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() + viewPositon := mgl32.Vec3{3, 3, 3} + view := mgl32.LookAtV(viewPositon, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0}) angle := 0.0 previousTime := glfw.GetTime() @@ -152,10 +158,12 @@ func main() { previousTime = time angle += elapsed - model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) + model := mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) // first pass // bind textures + gl.Enable(gl.DEPTH_TEST) + gbuff.Bind() gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) @@ -169,7 +177,7 @@ func main() { // transfer uniforms deferredShader.Use() deferredShader.Mat4("projection", projection) - deferredShader.Mat4("camera", camera) + deferredShader.Mat4("view", view) deferredShader.Mat4("model", model) deferredShader.Int("s_albedo", 0) @@ -180,17 +188,23 @@ func main() { cube.Draw() // second pass + gl.Disable(gl.DEPTH_TEST) gl.BindFramebuffer(gl.FRAMEBUFFER, 0) - gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + gl.Clear(gl.COLOR_BUFFER_BIT) gbuff.BindTextures() screenShader.Use() - screenShader.Int("albedo", 0) - screenShader.Int("depth", 1) - screenShader.Int("normal", 2) - screenShader.Int("material", 3) - screenShader.Int("position", 4) + screenShader.Int("s_albedo", 0) + screenShader.Int("s_depth", 1) + screenShader.Int("s_normal", 2) + screenShader.Int("s_material", 3) + screenShader.Int("s_position", 4) + screenShader.Vec3("view_pos", &viewPositon[0]) + + for _, light := range lights { + screenShader.Light(&light) + } screen.Draw() diff --git a/types/light/light.go b/types/light/light.go new file mode 100644 index 0000000..de702cf --- /dev/null +++ b/types/light/light.go @@ -0,0 +1,20 @@ +package light + +import "github.com/go-gl/mathgl/mgl32" + +const MAX_LIGHT_COUNT = 100 + +const ( + POINT int32 = iota + SPOT int32 = iota + DIRECTIONAL int32 = iota + AMBIENT int32 = iota +) + +type Light struct { + Color mgl32.Vec3 + Position mgl32.Vec3 + Direction mgl32.Vec3 + Intensity float32 + Type int32 +} diff --git a/types/shader/shader.go b/types/shader/shader.go index cfb0f15..45568d1 100644 --- a/types/shader/shader.go +++ b/types/shader/shader.go @@ -2,19 +2,23 @@ package shader import ( "errors" + "fmt" "strings" + "git.tek.govt.hu/dowerx/opengl-deferred/types/light" "github.com/go-gl/gl/v4.6-core/gl" "github.com/go-gl/mathgl/mgl32" ) type Shader struct { - program uint32 - uniforms map[string]int32 + program uint32 + uniforms map[string]int32 + lightCount int32 } func (s *Shader) Use() { gl.UseProgram(s.program) + s.lightCount = 0 } func (s *Shader) Delete() { @@ -40,6 +44,30 @@ func (s *Shader) Int(name string, val int32) { gl.Uniform1i(s.getUniformLocation(name), val) } +func (s *Shader) Float(name string, val float32) { + gl.Uniform1f(s.getUniformLocation(name), val) +} + +func (s *Shader) Vec3(name string, val *float32) { + gl.Uniform3fv(s.getUniformLocation(name), 1, val) +} + +func (s *Shader) Light(l *light.Light) error { + if s.lightCount >= light.MAX_LIGHT_COUNT { + return errors.New("too many lights") + } + + s.Vec3(fmt.Sprintf("lights[%d].color", s.lightCount), &l.Color[0]) + s.Vec3(fmt.Sprintf("lights[%d].position", s.lightCount), &l.Position[0]) + s.Vec3(fmt.Sprintf("lights[%d].direction", s.lightCount), &l.Direction[0]) + s.Float(fmt.Sprintf("lights[%d].intensity", s.lightCount), l.Intensity) + s.Int(fmt.Sprintf("lights[%d].type", s.lightCount), l.Type) + s.lightCount++ + s.Int("light_count", s.lightCount) + + return nil +} + func compileShader(source string, shaderType uint32) (uint32, error) { shader := gl.CreateShader(shaderType)