protected unsafe override void DoInitialize() { base.DoInitialize(); // pbr: generate a 2D LUT from the BRDF equations used. // then re-configure capture framebuffer object and render screen-space quad with BRDF shader. // pbr: setup framebuffer var captureFBO = new Framebuffer(512, 512); captureFBO.Bind(); var captureRBO = new Renderbuffer(512, 512, GL.GL_DEPTH_COMPONENT24); captureFBO.Attach(FramebufferTarget.Framebuffer, captureRBO, AttachmentLocation.Depth); captureFBO.Attach(FramebufferTarget.Framebuffer, this.texBRDF, 0u); captureFBO.CheckCompleteness(); captureFBO.Unbind(); RenderMethod method = this.RenderUnit.Methods[0]; ViewportSwitch viewportSwitch = new ViewportSwitch(0, 0, 512, 512); viewportSwitch.On(); captureFBO.Bind(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); method.Render(); captureFBO.Unbind(); viewportSwitch.Off(); captureFBO.Dispose(); this.texBRDF.GetImage(512, 512).Save(string.Format("texBRDF.png")); }
protected unsafe override void DoInitialize() { base.DoInitialize(); // pbr: run a quasi monte-carlo simulation on the environment lighting to create a prefilter (cube)map. const uint maxMipLevels = 5; var viewport = new ViewportSwitch(); for (int mip = 0; mip < maxMipLevels; ++mip) { // reisze framebuffer according to mip-level size. int mipWidth = (int)(128 * Math.Pow(0.5, mip)); int mipHeight = (int)(128 * Math.Pow(0.5, mip)); var captureFBO = new Framebuffer(mipWidth, mipHeight); captureFBO.Bind(); var captureRBO = new Renderbuffer(mipWidth, mipHeight, GL.GL_DEPTH_COMPONENT24); captureFBO.Attach(FramebufferTarget.Framebuffer, captureRBO, AttachmentLocation.Depth); captureFBO.CheckCompleteness(); captureFBO.Unbind(); viewport.Width = mipWidth; viewport.Height = mipHeight; viewport.On(); // NOTE: I added '/ 10' to make it a clearer visual effect. float roughness = (float)mip / (float)(maxMipLevels - 1) / 5; RenderMethod method = this.RenderUnit.Methods[0]; ShaderProgram program = method.Program; program.SetUniform("roughness", roughness); program.SetUniform("projection", captureProjection); program.SetUniform("environmentMap", this.envCubemap); for (uint i = 0; i < 6; ++i) { program.SetUniform("view", captureViews[i]); CubemapFace face = (CubemapFace)(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); uint location = 0; //int level = 0; captureFBO.Bind(); captureFBO.Attach(FramebufferTarget.Framebuffer, location, face, this.prefilterMap, mip); captureFBO.CheckCompleteness(); captureFBO.Unbind(); captureFBO.Bind(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); method.Render(); captureFBO.Unbind(); this.prefilterMap.GetImage(face, mipWidth, mipHeight, mip).Save(string.Format("prefilter.{0}.mip{1}.png", face, mip)); } viewport.Off(); captureFBO.Dispose(); } }
protected unsafe override void DoInitialize() { base.DoInitialize(); ViewportSwitch viewportSwitch = new ViewportSwitch(0, 0, 512, 512); // pbr: setup framebuffer var captureFBO = new Framebuffer(512, 512); captureFBO.Bind(); var captureRBO = new Renderbuffer(512, 512, GL.GL_DEPTH_COMPONENT24); captureFBO.Attach(FramebufferTarget.Framebuffer, captureRBO, AttachmentLocation.Depth); captureFBO.CheckCompleteness(); captureFBO.Unbind(); // pbr: convert HDR equirectangular environment map to cubemap equivalent RenderMethod method = this.RenderUnit.Methods[0]; ShaderProgram program = method.Program; program.SetUniform("equirectangularMap", this.texHDR); program.SetUniform("projection", captureProjection); viewportSwitch.On(); for (uint i = 0; i < 6; ++i) { program.SetUniform("view", captureViews[i]); CubemapFace face = (CubemapFace)(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); uint location = 0; int level = 0; captureFBO.Bind(); captureFBO.Attach(FramebufferTarget.Framebuffer, location, face, this.environmentMap, level); captureFBO.CheckCompleteness(); captureFBO.Unbind(); captureFBO.Bind(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); method.Render(); captureFBO.Unbind(); this.environmentMap.GetImage(face, 512, 512).Save(string.Format("texEnvCubemap.{0}.mip{1}.png", face, 0)); } viewportSwitch.Off(); captureFBO.Dispose(); this.environmentMap.Bind(); glGenerateMipmap(GL.GL_TEXTURE_CUBE_MAP); this.environmentMap.Unbind(); }
protected override void DoInitialize() { // init textures. this.envCubeMap = LoadEnvCubeMap(); this.irradianceMap = LoadIrradianceMap(); this.prefliterMap = LoadPrefliterMap(); this.brdfLUTTexture = LoadBRDFTexture(); //this.hdrTexture = LoadHdrEnvironmentMap(@"Texture\hdr\newport_loft.hdr"); this.hdrTexture = LoadHDRTexture(@"Texture\hdr\newport_loft.hdr"); //{ // Bitmap bitmap = LoadHdrFormFreeImage(@"Texture\hdr\newport_loft.hdr"); // var storage = new TexImageBitmap(bitmap, GL.GL_RGB16F); // var texture = new Texture(storage, // new TexParameteri(TexParameter.PropertyName.TextureWrapS, (int)GL.GL_CLAMP_TO_EDGE), // new TexParameteri(TexParameter.PropertyName.TextureWrapT, (int)GL.GL_CLAMP_TO_EDGE), // new TexParameteri(TexParameter.PropertyName.TextureMinFilter, (int)GL.GL_LINEAR), // new TexParameteri(TexParameter.PropertyName.TextureMagFilter, (int)GL.GL_LINEAR)); // texture.Initialize(); // this.hdrTexture = texture; //} this.albedoMap = LoadTexture(@"Texture\agedplanks1-albedo.png"); this.albedoMap.TextureUnitIndex = 3; this.normalMap = LoadTexture(@"Texture\agedplanks1-normal4-ue.png"); this.normalMap.TextureUnitIndex = 4; this.metallicMap = LoadTexture(@"Texture\agedplanks1-ao.png"); this.metallicMap.TextureUnitIndex = 5; this.roughnessMap = LoadTexture(@"Texture\agedplanks1-roughness.png"); this.roughnessMap.TextureUnitIndex = 6; this.aoMap = LoadTexture(@"Texture\agedplanks1-ao.png"); this.aoMap.TextureUnitIndex = 7; this.pbrProgram.SetUniform("albedoMap", this.albedoMap); this.pbrProgram.SetUniform("normalMap", this.normalMap); this.pbrProgram.SetUniform("metallicMap", this.metallicMap); this.pbrProgram.SetUniform("roughnessMap", this.roughnessMap); this.pbrProgram.SetUniform("aoMap", this.aoMap); //设置投影矩阵 mat4 captureProjection = glm.perspective((float)(Math.PI / 2), 1.0f, 0.1f, 20.0f); mat4[] captureView = { glm.lookAt(new vec3(0, 0, 0), new vec3(1.0f, 0.0f, 0.0f), new vec3(0.0f, -1.0f, 0.0f)), glm.lookAt(new vec3(0, 0, 0), new vec3(-1.0f, 0.0f, 0.0f), new vec3(0.0f, -1.0f, 0.0f)), glm.lookAt(new vec3(0, 0, 0), new vec3(0.0f, 1.0f, 0.0f), new vec3(0.0f, 0.0f, 1.0f)), glm.lookAt(new vec3(0, 0, 0), new vec3(0.0f, -1.0f, 0.0f), new vec3(0.0f, 0.0f, -1.0f)), glm.lookAt(new vec3(0, 0, 0), new vec3(0.0f, 0.0f, 1.0f), new vec3(0.0f, -1.0f, 0.0f)), glm.lookAt(new vec3(0, 0, 0), new vec3(0.0f, 0.0f, -1.0f), new vec3(0.0f, -1.0f, 0.0f)), }; ViewportSwitch viewportSwitch = new ViewportSwitch(0, 0, 512, 512); //转换HDR Equirectangular environmentMap 为 HDR cubeMap { //创建渲染到CubeMap的FBO var fbo = new Framebuffer(512, 512); fbo.Bind(); var rbo = new Renderbuffer(512, 512, GL.GL_DEPTH_COMPONENT24); fbo.Attach(FramebufferTarget.Framebuffer, rbo, AttachmentLocation.Depth); fbo.CheckCompleteness(); fbo.Unbind(); viewportSwitch.On(); ShaderProgram program = this.equiRectangular2CubemapProgram; program.SetUniform("equirectangularMap", this.hdrTexture); program.SetUniform("ProjMatrix", captureProjection); for (uint i = 0; i < 6; ++i) { fbo.Bind(); CubemapFace face = (CubemapFace)(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); uint location = 0; int level = 0; fbo.Attach(FramebufferTarget.Framebuffer, location, face, envCubeMap, level); fbo.CheckCompleteness(); fbo.Unbind(); fbo.Bind(); program.Bind(); program.SetUniform("ViewMatrix", captureView[i]); program.PushUniforms(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); renderCube(); program.Unbind(); fbo.Unbind(); envCubeMap.GetImage(face, fbo.Width, fbo.Height).Save( string.Format("envCubeMap.{0}.png", face)); } viewportSwitch.Off(); fbo.Dispose(); } //创建一个irradianceMap { var fbo = new Framebuffer(irradianceMapLength, irradianceMapLength); fbo.Bind(); var rbo = new Renderbuffer(irradianceMapLength, irradianceMapLength, GL.GL_DEPTH_COMPONENT24); fbo.Attach(FramebufferTarget.Framebuffer, rbo, AttachmentLocation.Depth); fbo.CheckCompleteness(); fbo.Unbind(); //pbr:通过卷积来创建一张irradianceMap来解决diffueIntegral viewportSwitch.Width = irradianceMapLength; viewportSwitch.Height = irradianceMapLength; viewportSwitch.On(); ShaderProgram program = this.irradianceProgram; program.SetUniform("environmentMap", envCubeMap); program.SetUniform("ProjMatrix", captureProjection); for (uint i = 0; i < 6; ++i) { fbo.Bind(); CubemapFace face = (CubemapFace)(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); uint location = 0; int level = 0; fbo.Attach(FramebufferTarget.Framebuffer, location, face, irradianceMap, level); fbo.CheckCompleteness(); fbo.Unbind(); //vec3 color = System.Drawing.Color.SkyBlue.ToVec3(); vec3 color = System.Drawing.Color.Black.ToVec3(); fbo.Bind(); program.Bind(); program.SetUniform("ViewMatrix", captureView[i]); program.PushUniforms(); GL.Instance.ClearColor(color.x, color.y, color.z, 1); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); renderCube(); program.Unbind(); fbo.Unbind(); irradianceMap.GetImage(face, fbo.Width, fbo.Height).Save( string.Format("irradianceMap.fill.{0}.png", face)); } viewportSwitch.Off(); fbo.Dispose(); } //对环境光用蒙特卡洛积分来创建一个prefliterMap贴图 { ShaderProgram program = this.prefliterProgram; program.SetUniform("environmentMap", envCubeMap); program.SetUniform("ProjMatrix", captureProjection); const int maxMipLevels = 5; for (int level = 0; level < maxMipLevels; level++) { int mipWidth = (int)(128 * Math.Pow(0.5, level)); int mipHeight = (int)(128 * Math.Pow(0.5, level)); var fbo = new Framebuffer(mipWidth, mipHeight); fbo.Bind(); var rbo = new Renderbuffer(mipWidth, mipHeight, GL.GL_DEPTH_COMPONENT24); fbo.Attach(FramebufferTarget.Framebuffer, rbo, AttachmentLocation.Depth); fbo.CheckCompleteness(); fbo.Unbind(); viewportSwitch.Width = mipWidth; viewportSwitch.Height = mipHeight; viewportSwitch.On(); float roughness = (float)level / (float)(maxMipLevels - 1); program.SetUniform("roughness", roughness); for (uint j = 0; j < 6; j++) { program.SetUniform("ViewMatrix", captureView[level]); fbo.Bind(); CubemapFace face = (CubemapFace)(GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + j); uint location = 0; fbo.Attach(FramebufferTarget.Framebuffer, location, face, prefliterMap, level); fbo.CheckCompleteness(); fbo.Unbind(); fbo.Bind(); program.Bind(); program.PushUniforms(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); renderCube(); program.Unbind(); fbo.Unbind(); prefliterMap.GetImage(face, fbo.Width, fbo.Height, level).Save( string.Format("prefliterMap.{0}.{1}.png", level, face)); } viewportSwitch.Off(); fbo.Dispose(); } program.Unbind(); } { var fbo = new Framebuffer(512, 512); fbo.Bind(); var rbo = new Renderbuffer(512, 512, GL.GL_DEPTH_COMPONENT24); fbo.Attach(FramebufferTarget.Framebuffer, rbo, AttachmentLocation.Depth); fbo.Attach(FramebufferTarget.Framebuffer, brdfLUTTexture, 0u); fbo.CheckCompleteness(); fbo.Unbind(); fbo.Bind(); viewportSwitch.Width = 512; viewportSwitch.Height = 512; viewportSwitch.On(); ShaderProgram program = this.brdfProgram; program.Bind(); program.PushUniforms(); GL.Instance.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); renderQuad(); program.Unbind(); viewportSwitch.Off(); fbo.Unbind(); fbo.Dispose(); brdfLUTTexture.GetImage(fbo.Width, fbo.Height).Save( string.Format("BRDF.GetImage.png")); } }