//SaveTexture2D take a Texture2D and a filename and saves it as a png image. func SaveTexture2D(t gl2.Texture2D, filename string) error { file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0666) defer file.Close() if err != nil { return err } lasttex := GetCurrentTexture2D() defer lasttex.Bind() t.Bind() width, height := int(t.Width(0)), int(t.Height(0)) nrgba := image.NewRGBA(image.Rect(0, 0, width, height)) D(width, height) var pixels []byte internalformat := t.InternalFormat(0) if internalformat == gl.RGBA8 { pixels = make([]byte, width*height*4) t.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&pixels[0])) for x := 0; x < len(pixels); x += 4 { nrgba.SetRGBA((x/4)%width, height-(x/4)/width, color.RGBA{pixels[x], pixels[x+1], pixels[x+2], 255}) } } else { fmt.Errorf("unsupported texture type") } png.Encode(file, nrgba) return nil }
//Aggregate performs the lighting calculation per pixel. This is essentially a special post process pass. func (gb *GBuffer) Aggregate(cam *Camera, plights []*PointLight, shadowmat glm.Mat4, tex gl2.Texture2D, f1, f2, f3 float32) { gb.AggregateFramebuffer.framebuffer.Bind(gl2.FRAMEBUFFER) gb.AggregateFramebuffer.program.Use() gb.CookRoughnessValue.Uniform1f(f1) gb.CookF0.Uniform1f(f2) gb.CookK.Uniform1f(f3) gl.ActiveTexture(gl2.TEXTURE0) gb.DiffuseTex.Bind() gb.AggregateFramebuffer.DiffUni.Uniform1i(0) gl.ActiveTexture(gl2.TEXTURE1) gb.NormalTex.Bind() gb.AggregateFramebuffer.NormalUni.Uniform1i(1) gl.ActiveTexture(gl2.TEXTURE2) gb.PositionTex.Bind() gb.AggregateFramebuffer.PosUni.Uniform1i(2) gl.ActiveTexture(gl2.TEXTURE3) gb.DepthTex.Bind() gb.AggregateFramebuffer.DepthUni.Uniform1i(3) //point lights gb.NumPointLightUni.Uniform1i(int32(len(plights))) plightpos := make([]float32, len(plights)*3) plightcol := make([]float32, len(plights)*3) for i, light := range plights { plightpos[i] = light.X plightpos[i+1] = light.Y plightpos[i+2] = light.Z plightcol[i] = light.R plightcol[i] = light.G plightcol[i] = light.B } if len(plights) != 0 { gb.PointLightPosUni.Uniform3fv(int32(len(plights)), &plightpos[0]) gb.PointLightColUni.Uniform3fv(int32(len(plights)), &plightcol[0]) } gb.CamPosUni.Uniform3fv(1, &cam.Pos[0]) //=====shadow=====// gl.ActiveTexture(gl2.TEXTURE4) tex.Bind() gb.ShadowMapUni.Uniform1i(4) gb.ShadowMatUni.UniformMatrix4fv(1, false, &shadowmat[0]) //================// Fstri() }
//Render takes a texture and feed it to the fragment shader as a fullscreen texture. It will call the next post process pass if there is one. func (ppfb *PostProcessFramebuffer) Render(t gl2.Texture2D) { ppfb.Prog.Use() ppfb.time.Uniform1f(float32(glfw.GetTime())) gl.ActiveTexture(gl2.TEXTURE0) t.Bind() ppfb.source.Uniform1i(0) Fstri() if ppfb.next != nil { ppfb.next.PreRender() ppfb.next.Render(ppfb.Tex) } }
//Render will render the mesh in the different textures. No lighting calculation is performed here. func (gb *GBuffer) Render(cam *Camera, mesh Mesh, tex gl2.Texture2D, t *Transform) { model := t.Mat4() mvp := gb.vp.Mul4(model) gb.MVPUni.UniformMatrix4fv(1, false, &mvp[0]) gb.MUni.UniformMatrix4fv(1, false, &model[0]) normal := model.Inv() gb.NUni.UniformMatrix4fv(1, true, &normal[0]) gl.ActiveTexture(gl2.TEXTURE0) tex.Bind() gb.DiffuseUni.Uniform1i(0) mesh.Bind() mesh.DrawCall() }