瀏覽代碼

Merge pull request #212 from uzudil/fbo3

postprocessing idea
Daniel Salvadori 4 年之前
父節點
當前提交
216f7825db
共有 3 個文件被更改,包括 130 次插入0 次删除
  1. 9 0
      gls/gls-desktop.go
  2. 2 0
      gls/gls.go
  3. 119 0
      renderer/postprocessor.go

+ 9 - 0
gls/gls-desktop.go

@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build !wasm
 // +build !wasm
 
 package gls
@@ -484,6 +485,7 @@ func (gs *GLS) GenFramebuffer() uint32 {
 
 	var fb uint32
 	C.glGenFramebuffers(1, (*C.GLuint)(&fb))
+	gs.stats.Fbos++
 	return fb
 }
 
@@ -492,6 +494,7 @@ func (gs *GLS) GenRenderbuffer() uint32 {
 
 	var rb uint32
 	C.glGenRenderbuffers(1, (*C.GLuint)(&rb))
+	gs.stats.Rbos++
 	return rb
 }
 
@@ -545,6 +548,12 @@ func (gs *GLS) FramebufferTexture3D(attachment uint, textarget uint, tex uint32,
 	C.glFramebufferTexture3D(FRAMEBUFFER, C.GLenum(attachment), C.GLenum(textarget), C.GLuint(tex), 0, C.GLint(layer))
 }
 
+// CheckFramebufferStatus get the framebuffer status
+func (gs *GLS) CheckFramebufferStatus() uint32 {
+	res := C.glCheckFramebufferStatus(C.GLenum(FRAMEBUFFER))
+	return uint32(res)
+}
+
 // ReadBuffer sets the buffer for reading using ReadPixels.
 // Attachment is one of COLOR_ATTACHMENT0, DEPTH_ATTACHMENT, or STENCIL_ATTACHMENT.
 func (gs *GLS) ReadBuffer(attachment uint) {

+ 2 - 0
gls/gls.go

@@ -34,6 +34,8 @@ type Stats struct {
 	UnilocMiss uint64 // Cumulative number of uniform location cache misses
 	Unisets    uint64 // Cumulative number of uniform sets
 	Drawcalls  uint64 // Cumulative number of draw calls
+	Fbos       uint64 // Number of frame buffer objects
+	Rbos       uint64 // Number of render buffer objects
 }
 
 const (

+ 119 - 0
renderer/postprocessor.go

@@ -0,0 +1,119 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package renderer implements the scene renderer.
+package renderer
+
+import "github.com/g3n/engine/gls"
+
+type Postprocessor struct {
+	Width    int32
+	Height   int32
+	Fbo      uint32
+	Tex      uint32
+	Vao      uint32
+	Prg      *gls.Program
+	screen   []float32
+	Renderer *Renderer
+}
+
+func (r *Renderer) CreatePostprocessor(width, height int32, vertexShaderSource, fragmentShaderSource string) *Postprocessor {
+	pp := &Postprocessor{
+		Width:    width,
+		Height:   height,
+		Renderer: r,
+		screen: []float32{
+			// xyz		color		texture coords
+			-1, 1, 0, 1, 1, 1, 0, 1,
+			-1, -1, 0, 1, 1, 1, 0, 0,
+			1, -1, 0, 1, 1, 1, 1, 0,
+			1, 1, 0, 1, 1, 1, 1, 1,
+			-1, 1, 0, 1, 1, 1, 0, 1,
+			1, -1, 0, 1, 1, 1, 1, 0,
+		},
+	}
+
+	pp.Fbo = r.gs.GenFramebuffer()
+	r.gs.BindFramebuffer(pp.Fbo)
+
+	// set up a texture to render into
+	pp.Tex = r.gs.GenTexture()
+	r.gs.BindTexture(gls.TEXTURE_2D, pp.Tex)
+	r.gs.TexImage2D(gls.TEXTURE_2D, 0, gls.RGB, width, height, gls.RGB, gls.UNSIGNED_BYTE, nil)
+	r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_WRAP_S, gls.CLAMP_TO_EDGE)
+	r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_WRAP_T, gls.CLAMP_TO_EDGE)
+	r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_MIN_FILTER, gls.NEAREST)
+	r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_MAG_FILTER, gls.NEAREST)
+	r.gs.BindTexture(gls.TEXTURE_2D, 0)
+	r.gs.FramebufferTexture2D(gls.COLOR_ATTACHMENT0, gls.TEXTURE_2D, pp.Tex)
+
+	// attach depth and stencil buffers
+	rbo := r.gs.GenRenderbuffer()
+	r.gs.BindRenderbuffer(rbo)
+	r.gs.RenderbufferStorage(gls.DEPTH24_STENCIL8, int(width), int(height))
+	r.gs.BindRenderbuffer(0)
+	r.gs.FramebufferRenderbuffer(gls.DEPTH_STENCIL_ATTACHMENT, rbo)
+
+	// check the framebuffer status
+	if r.gs.CheckFramebufferStatus() != gls.FRAMEBUFFER_COMPLETE {
+		log.Fatal("Can't create frame buffer")
+	}
+	r.gs.BindFramebuffer(0)
+
+	// create the "screen" quad
+	vbo := r.gs.GenBuffer()
+	r.gs.BindBuffer(gls.ARRAY_BUFFER, vbo)
+	r.gs.BufferData(gls.ARRAY_BUFFER, 4*len(pp.screen), pp.screen, gls.STATIC_DRAW)
+
+	pp.Vao = r.gs.GenVertexArray()
+	r.gs.BindVertexArray(pp.Vao)
+	r.gs.BindBuffer(gls.ARRAY_BUFFER, vbo)
+	var offset uint32
+
+	// position attribute
+	r.gs.VertexAttribPointer(0, 3, gls.FLOAT, false, 8*4, offset)
+	r.gs.EnableVertexAttribArray(0)
+	offset += 3 * 4
+
+	// color attribute
+	r.gs.VertexAttribPointer(1, 3, gls.FLOAT, false, 8*4, offset)
+	r.gs.EnableVertexAttribArray(1)
+	offset += 3 * 4
+
+	// texture coord attribute
+	r.gs.VertexAttribPointer(2, 2, gls.FLOAT, false, 8*4, offset)
+	r.gs.EnableVertexAttribArray(2)
+	offset += 2 * 4
+
+	// the screen shaders
+	pp.Prg = r.gs.NewProgram()
+	pp.Prg.AddShader(gls.VERTEX_SHADER, vertexShaderSource)
+	pp.Prg.AddShader(gls.FRAGMENT_SHADER, fragmentShaderSource)
+	err := pp.Prg.Build()
+	if err != nil {
+		log.Fatal("can't create shader: %e", err)
+	}
+
+	return pp
+}
+
+func (pp *Postprocessor) Render(fbwidth, fbheight int, render func()) {
+	// render into the low-res texture
+	gs := pp.Renderer.gs
+	gs.Viewport(0, 0, pp.Width, pp.Height)
+	gs.BindFramebuffer(pp.Fbo)
+	gs.Enable(gls.DEPTH_TEST)
+	render()
+
+	// show texture on screen
+	gs.Viewport(0, 0, int32(fbwidth), int32(fbheight))
+	gs.BindFramebuffer(0)
+	gs.ClearColor(1, 1, 1, 1)
+	gs.Clear(gls.COLOR_BUFFER_BIT)
+	gs.UseProgram(pp.Prg)
+	gs.Disable(gls.DEPTH_TEST)
+	gs.BindTexture(gls.TEXTURE_2D, pp.Tex)
+	gs.BindVertexArray(pp.Vao)
+	gs.DrawArrays(gls.TRIANGLES, 0, int32(len(pp.screen)/8))
+}