diff --git a/assets/shader/deferred/deferred.fs b/assets/shader/deferred/deferred.fs index 4335b90..5e5e2c6 100644 --- a/assets/shader/deferred/deferred.fs +++ b/assets/shader/deferred/deferred.fs @@ -10,11 +10,10 @@ in vec3 pos; in vec3 norm; in vec2 tex; -out vec4 FragColor; -out vec3 position; -out vec3 albedo; -out vec3 normal; -out vec3 material; +layout (location = 0) out vec3 albedo; +layout (location = 1) out vec3 normal; +layout (location = 2) out vec3 material; +layout (location = 3) out vec3 position; void main() { position = pos; @@ -23,6 +22,5 @@ void main() { 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); } + diff --git a/assets/shader/screen/screen.fs b/assets/shader/screen/screen.fs new file mode 100644 index 0000000..f98a12d --- /dev/null +++ b/assets/shader/screen/screen.fs @@ -0,0 +1,20 @@ +#version 460 core + +uniform sampler2D albedo; +uniform sampler2D depth; +uniform sampler2D normal; +uniform sampler2D material; +uniform sampler2D position; + +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); +} + +void main() { + FragColor = texture(position, tex); +} \ No newline at end of file diff --git a/assets/shader/screen/screen.vs b/assets/shader/screen/screen.vs new file mode 100644 index 0000000..d28abfa --- /dev/null +++ b/assets/shader/screen/screen.vs @@ -0,0 +1,13 @@ +#version 460 core + +layout (location = 0) in vec3 _pos; +layout (location = 1) in vec2 _tex; + +out vec3 pos; +out vec2 tex; + +void main() { + gl_Position = vec4(_pos.xy, 0, 1); + pos = _pos; + tex = _tex; +} \ No newline at end of file diff --git a/main.go b/main.go index 845710d..71e9925 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "os" "runtime" + "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/shader" "git.tek.govt.hu/dowerx/opengl-deferred/types/texture" @@ -70,6 +71,21 @@ func main() { } defer deferredShader.Delete() + vertexSource, err = os.ReadFile("assets/shader/screen/screen.vs") + if err != nil { + panic(err) + } + fragmentSource, err = os.ReadFile("assets/shader/screen/screen.fs") + if err != nil { + panic(err) + } + + screenShader, err := shader.New(string(vertexSource), string(fragmentSource)) + if err != nil { + panic(err) + } + defer screenShader.Delete() + // geometry cube, err := geometry.LoadOBJ("assets/geometries/suzanne.obj") if err != nil { @@ -77,6 +93,12 @@ func main() { } defer cube.Delete() + screen, err := geometry.Screen() + if err != nil { + panic(err) + } + defer screen.Delete() + // textures albedo, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_albedo.tif") if err != nil { @@ -108,35 +130,22 @@ func main() { } defer metalic.Delete() + // gbuffer + gbuff, err := gbuffer.New(WIDTH, HEIGHT) + if err != nil { + panic(err) + } + defer gbuff.Delete() + gbuff.Bind() + // 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) - angle := 0.0 previousTime := glfw.GetTime() for !window.ShouldClose() { - gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) - // rotate time := glfw.GetTime() elapsed := time - previousTime @@ -144,11 +153,47 @@ func main() { angle += elapsed model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) + + // first pass + // bind textures + gbuff.Bind() + + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + + 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) - // render + 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) cube.Draw() + // second pass + gl.BindFramebuffer(gl.FRAMEBUFFER, 0) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_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) + + screen.Draw() + window.SwapBuffers() glfw.PollEvents() } diff --git a/types/gbuffer/gbuffer.go b/types/gbuffer/gbuffer.go new file mode 100644 index 0000000..6a1aa9d --- /dev/null +++ b/types/gbuffer/gbuffer.go @@ -0,0 +1,109 @@ +package gbuffer + +import ( + "errors" + + "github.com/go-gl/gl/v4.6-core/gl" +) + +type GBuffer struct { + framebuffer uint32 + depth uint32 + colorAttachments [4]uint32 // albedo, normal, material, position +} + +var attachments = []uint32{ + gl.COLOR_ATTACHMENT0, + gl.COLOR_ATTACHMENT1, + gl.COLOR_ATTACHMENT2, + gl.COLOR_ATTACHMENT3, +} + +func (b *GBuffer) Bind() { + gl.BindFramebuffer(gl.FRAMEBUFFER, b.framebuffer) + gl.DrawBuffers(int32(len(b.colorAttachments)), &attachments[0]) +} + +func (b *GBuffer) BindTextures() { + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, b.colorAttachments[0]) + + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, b.depth) + + gl.ActiveTexture(gl.TEXTURE2) + gl.BindTexture(gl.TEXTURE_2D, b.colorAttachments[1]) + + gl.ActiveTexture(gl.TEXTURE3) + gl.BindTexture(gl.TEXTURE_2D, b.colorAttachments[2]) + + gl.ActiveTexture(gl.TEXTURE4) + gl.BindTexture(gl.TEXTURE_2D, b.colorAttachments[3]) +} + +func (b *GBuffer) Delete() { + gl.DeleteFramebuffers(1, &b.framebuffer) + for i, _ := range b.colorAttachments { + gl.DeleteTextures(1, &b.colorAttachments[i]) + + } + gl.DeleteTextures(1, &b.depth) +} + +func New(width int, height int) (buffer GBuffer, _ error) { + gl.GenFramebuffers(1, &buffer.framebuffer) + gl.BindFramebuffer(gl.FRAMEBUFFER, buffer.framebuffer) + + // albedo + gl.GenTextures(1, &buffer.colorAttachments[0]) + gl.BindTexture(gl.TEXTURE_2D, buffer.colorAttachments[0]) + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(width), int32(height), 0, gl.RGB, gl.UNSIGNED_BYTE, nil) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.BindTexture(gl.TEXTURE_2D, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, buffer.colorAttachments[0], 0) + + // depth + gl.GenTextures(1, &buffer.depth) + gl.BindTexture(gl.TEXTURE_2D, buffer.depth) + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, int32(width), int32(height), 0, gl.DEPTH_COMPONENT, gl.FLOAT, nil) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.BindTexture(gl.TEXTURE_2D, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, buffer.depth, 0) + + // normal + gl.GenTextures(1, &buffer.colorAttachments[1]) + gl.BindTexture(gl.TEXTURE_2D, buffer.colorAttachments[1]) + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(width), int32(height), 0, gl.RGB, gl.UNSIGNED_BYTE, nil) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.BindTexture(gl.TEXTURE_2D, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, buffer.colorAttachments[1], 0) + + // material + gl.GenTextures(1, &buffer.colorAttachments[2]) + gl.BindTexture(gl.TEXTURE_2D, buffer.colorAttachments[2]) + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(width), int32(height), 0, gl.RGB, gl.UNSIGNED_BYTE, nil) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.BindTexture(gl.TEXTURE_2D, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, buffer.colorAttachments[2], 0) + + // position + gl.GenTextures(1, &buffer.colorAttachments[3]) + gl.BindTexture(gl.TEXTURE_2D, buffer.colorAttachments[3]) + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, int32(width), int32(height), 0, gl.RGB, gl.FLOAT, nil) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.BindTexture(gl.TEXTURE_2D, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT3, gl.TEXTURE_2D, buffer.colorAttachments[3], 0) + + if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { + return buffer, errors.New("failed to create framebuffer") + } + + gl.BindFramebuffer(gl.FRAMEBUFFER, 0) + + return buffer, nil +} diff --git a/types/geometry/geometry.go b/types/geometry/geometry.go index f8e5b35..8bdc3ba 100644 --- a/types/geometry/geometry.go +++ b/types/geometry/geometry.go @@ -76,3 +76,18 @@ func LoadOBJ(path string) (geometries Geometry, err error) { return new(o.Coord, o.Indices) } + +func Screen() (Geometry, error) { + return new( + []float32{ + // xyz uv ijk + -1, -1, 0, 0, 0, 0, 0, 0, + 1, -1, 0, 1, 0, 0, 0, 0, + -1, 1, 0, 0, 1, 0, 0, 0, + 1, 1, 0, 1, 1, 0, 0, 0, + }, + []int{ + 0, 1, 2, + 1, 3, 2, + }) +}