【OpenGL】hdr_bloom 泛光示例程序
发布日期:2021-05-10 02:21:15 浏览次数:20 分类:精选文章

本文共 29227 字,大约阅读时间需要 97 分钟。

①HDRFBO分别有2个浮点纹理,其中一个纹理捆绑到第一个颜色缓冲区绑定点,第二个纹理绑定到第二个颜色缓冲区绑定点,它们的内容都交给texReplaceProg着色器(basic.vs、tex_replace.fs)渲染,着色器主要内容就是照常渲染场景输出给第一个颜色缓冲区,而第二个颜色缓冲区内容是视野中明亮区域。具体代码如下:

#version 150 // tex_replace.fs// outputs 1 color using texture replace// in vec2 vTexCoord; uniform sampler2D textureUnit0; uniform vec4 vColor;out vec4 oColor;out vec4 oBright;void main(void) {	const float bloomLimit = 1.0;     oColor =  vColor*texture(textureUnit0, vTexCoord);    oColor.a = 1.0;        vec3 brightColor = max(vColor.rgb - vec3(bloomLimit), vec3(0.0));    float bright = dot(brightColor, vec3(1.0));    bright = smoothstep(0.0, 0.5, bright);    oBright.rgb = mix(vec3(0.0), vColor.rgb, bright).rgb;    oBright.a = 1.0;}

其中,bloomLimit是固定值1.0,它是为了将HDR图像的颜色值小于1.0部分全部视为0,而大于1.0部分映射到都会整体-1。接着就是将3个分量相加得到亮度值,亮度值会被映射回[0,1]之间,其中小于0的会变为0,大于0.5的就视为1,接着用这个[0,1]范围的亮度值进行插值(黑色,HDR颜色),即亮度为0时 为黑色,亮度为1时 为HDR颜色,将这个最终得到的颜色输出给第二个颜色缓冲区以备使用。

到此我们得到了HDR原图像纹理对象和明亮区域图像,即代码中的hdrTextures[0]和brightBlurTextures[0]纹理对象存储着。

②brightPassFBO数组 一共有4个用于渲染模糊区域图像的FBO,它们分别都捆绑到了第一个颜色缓冲区绑定点,分别用纹理对象brightBlurTextures1~4来进行捆绑,着色器blurProg(basic.vs、blur.fs)进行渲染,结果是输出给第一个颜色缓冲区的。

#version 150 // blur.fs// outputs 1 color using a gaussian blur of the input texture// in vec4 vFragColor; in vec2 vTexCoord; uniform sampler2D textureUnit0;uniform vec2 tc_offset[25]; out vec4 oColor;void main(void) { 	vec4 sample[25];    for (int i = 0; i < 25; i++)    {        sample[i] = texture(textureUnit0, vTexCoord.st + tc_offset[i]);    }//   1  4  7  4 1//   4 16 26 16 4//   7 26 41 26 7 / 273//   4 16 26 16 4//   1  4  7  4 1    oColor = (                   (1.0  * (sample[0] + sample[4] + sample[20] + sample[24])) +                   (4.0  * (sample[1] + sample[3] + sample[5] + sample[9] +                            sample[15] + sample[19] + sample[21] + sample[23])) +                   (7.0  * (sample[2] + sample[10] + sample[14] + sample[22])) +                   (16.0 * (sample[6] + sample[8] + sample[16] + sample[18])) +                   (26.0 * (sample[7] + sample[11] + sample[13] + sample[17])) +                   (41.0 * sample[12])                   ) / 273.0;}

tc_offset[i]是一个对周围25个片段的偏移量,最终通过它获取周围25个像素的颜色值进行卷积得到oColor即一个2D纹理(全是模糊值)最终经过4次这样的采样,但每一次得到的模糊图像都是在前一个基础上进行的,每一次都会将图像缩小1/3再进行得到模糊图。

③将FBO恢复回默认FBO,将这些结果融合起来,即1张原图图像、1张亮度图、4张模糊图。使用hdrBloomProg着色器(basic.vs、hdr_exposure.fs)进行渲染。

#version 150 // hdr_exposure.fs// Scale floating point texture to 0.0 - 1.0 based // on the specified exposure// in vec2 vTexCoord;uniform sampler2D origImage;uniform sampler2D brightImage;uniform sampler2D blur1;uniform sampler2D blur2;uniform sampler2D blur3;uniform sampler2D blur4;uniform float exposure;uniform float bloomLevel;out vec4 oColor;out vec4 oBright;void main(void) { 	// fetch from HDR & blur textures	vec4 vBaseImage  = texture2D(origImage, vTexCoord); 	vec4 vBrightPass = texture2D(brightImage, vTexCoord); 	vec4 vBlurColor1 = texture2D(blur1, vTexCoord); 	vec4 vBlurColor2 = texture2D(blur2, vTexCoord); 	vec4 vBlurColor3 = texture2D(blur3, vTexCoord); 	vec4 vBlurColor4 = texture2D(blur4, vTexCoord); 		vec4 vBloom = vBrightPass + 				  vBlurColor1 + 				  vBlurColor2 + 				  vBlurColor3 + 				  vBlurColor4;		vec4 vColor = vBaseImage + bloomLevel * vBloom;		// Apply the exposure to this texel	vColor = 1.0 - exp2(-vColor * exposure);	oColor = vColor;    oColor.a = 1.0f;    }

它将亮度图采样出的亮度值 和 4张模糊图采样出的4个模糊值进行相加得到 曝光值,与一个bloomLevel统一值(曝光等级)相乘得到最终曝光颜色,将采样出的原色和曝光颜色叠加得到vColor接着进行一个常规曝光处理(完全看不懂)得到最终的经过曝光处理的颜色输出。

上面的basic.vs代码就是简单的转换了顶点坐标和计算了漫反射颜色(好像也没用到)

#version 150 // hdr_bloom.vs// outputs MVP transformed position // passes texture coordinates through// color is * by normal and passed on.in vec3 vVertex;in vec3 vNormal;in vec2 vTexCoord0;uniform mat4 mvMatrix;uniform mat4 pMatrix;uniform vec3 vLightPos;uniform vec4 vColor;out vec4 vFragColor;out vec2 vTexCoord;void main(void) { 	mat3 mNormalMatrix;	mNormalMatrix[0] = normalize(mvMatrix[0].xyz);	mNormalMatrix[1] = normalize(mvMatrix[1].xyz);	mNormalMatrix[2] = normalize(mvMatrix[2].xyz);		vec3 vNorm = normalize(mNormalMatrix * vNormal);		vec4 ecPosition;	vec3 ecPosition3;	ecPosition = mvMatrix * vec4(vVertex, 1.0);	ecPosition3 = ecPosition.xyz /ecPosition.w;	vec3 vLightDir = normalize(vLightPos - ecPosition3);	float fDot = max(0.0, dot(vNorm, vLightDir)); 	vFragColor.rgb = vColor.rgb * fDot;	vFragColor.a = vColor.a;	vTexCoord = vTexCoord0;	mat4 mvpMatrix;	mvpMatrix = pMatrix * mvMatrix;	gl_Position = mvpMatrix * vec4(vVertex, 1.0); }
#include 
#include
#include
// OpenEXR headers#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __APPLE__#include
#else#define FREEGLUT_STATIC#include
#endif#ifdef _WIN32#pragma comment (lib, "half.lib") #pragma comment (lib, "Iex.lib")#pragma comment (lib, "IlmImf.lib")#pragma comment (lib, "IlmThread.lib")#pragma comment (lib, "Imath.lib")#pragma comment (lib, "zlib.lib")#endif#pragma warning( disable : 4244)static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };static GLfloat vWhiteX2[] = { 2.0f, 2.0f, 2.0f, 2.0f };static GLfloat vGrey[] = { 0.5f, 0.5f, 0.5f, 1.0f };static GLfloat vLightPos[] = { -2.0f, 3.0f, -2.0f, 1.0f };static GLfloat vSkyBlue[] = { 0.160f, 0.376f, 0.925f, 1.0f};static const GLenum windowBuff[] = { GL_BACK_LEFT };static const GLenum fboBuffs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };GLsizei screenWidth; // Desired window or desktop widthGLsizei screenHeight; // Desired window or desktop heightGLboolean bFullScreen; // Request to run full screenGLboolean bAnimated; // Request for continual updatesGLMatrixStack modelViewMatrix; // Modelview MatrixGLMatrixStack projectionMatrix; // Projection MatrixGLFrustum viewFrustum; // View FrustumGLGeometryTransform transformPipeline; // Geometry Transform PipelineGLFrame cameraFrame; // Camera frameGLBatch screenQuad;M3DMatrix44f orthoMatrix; GLBatch floorBatch;GLBatch windowBatch;GLBatch windowBorderBatch;GLBatch windowGridBatch;GLuint flatColorProg;GLuint texReplaceProg;GLuint hdrBloomProg;GLuint blurProg;GLuint hdrFBO[1];GLuint brightPassFBO[4];GLuint textures[1];GLuint hdrTextures[1];GLuint brightBlurTextures[5];GLuint windowTexture;GLfloat exposure;GLfloat bloomLevel;GLfloat texCoordOffsets[5*5*2];void UpdateMode(void);void GenerateOrtho2DMat(GLuint imageWidth, GLuint imageHeight);bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);bool LoadOpenEXRImage(char *fileName, GLint textureName, GLuint &texWidth, GLuint &texHeight);void GenTexCoordOffsets(GLuint width, GLuint height);void SetupTexReplaceProg(GLfloat *vLightPos, GLfloat *vColor);void SetupFlatColorProg(GLfloat *vLightPos, GLfloat *vColor);void SetupHDRProg();void SetupBlurProg();///// Load in a BMP file as a texture. Allows specification of the filters and the wrap modebool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) { GLbyte *pBits; GLint iWidth, iHeight; pBits = gltReadBMPBits(szFileName, &iWidth, &iHeight); if(pBits == NULL) return false; // Set Wrap modes glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, pBits); // Do I need to generate mipmaps? if(minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST) glGenerateMipmap(GL_TEXTURE_2D); return true;}void GenTexCoordOffsets(GLuint width, GLuint height){ float xInc = 1.0f / (GLfloat)(width); float yInc = 1.0f / (GLfloat)(height); for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { texCoordOffsets[(((i*5)+j)*2)+0] = (-2.0f * xInc) + ((GLfloat)i * xInc); texCoordOffsets[(((i*5)+j)*2)+1] = (-2.0f * yInc) + ((GLfloat)j * yInc); } }}///// OpenGL related startup code is safe to put here. Load textures, etc.void SetupRC(void){ GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); } glEnable(GL_DEPTH_TEST); exposure = 1.0f; bloomLevel = 0.5; // Light Blue glClearColor(vSkyBlue[0], vSkyBlue[1], vSkyBlue[2], vSkyBlue[3]); // Load geometry GLfloat alpha = 0.25f; floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1); floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha); floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f); floorBatch.Normal3f(0.0, 1.0f, 0.0f); floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f); floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha); floorBatch.MultiTexCoord2f(0, 10.0f, 0.0f); floorBatch.Normal3f(0.0, 1.0f, 0.0f); floorBatch.Vertex3f(20.0f, -0.41f, 20.0f); floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha); floorBatch.MultiTexCoord2f(0, 10.0f, 10.0f); floorBatch.Normal3f(0.0, 1.0f, 0.0f); floorBatch.Vertex3f(20.0f, -0.41f, -20.0f); floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha); floorBatch.MultiTexCoord2f(0, 0.0f, 10.0f); floorBatch.Normal3f(0.0, 1.0f, 0.0f); floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f); floorBatch.End(); windowBatch.Begin(GL_TRIANGLE_FAN, 4, 1); windowBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f); windowBatch.MultiTexCoord2f(0, 0.0f, 0.0f); windowBatch.Normal3f( 0.0f, 1.0f, 0.0f); windowBatch.Vertex3f(-1.0f, 0.0f, 0.0f); windowBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f); windowBatch.MultiTexCoord2f(0, 1.0f, 0.0f); windowBatch.Normal3f(0.0f, 1.0f, 0.0f); windowBatch.Vertex3f(1.0f, 0.0f, 0.0f); windowBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f); windowBatch.MultiTexCoord2f(0, 1.0f, 1.0f); windowBatch.Normal3f(0.0f, 1.0f, 0.0f); windowBatch.Vertex3f(1.0f, 2.0f, 0.0f); windowBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f); windowBatch.MultiTexCoord2f(0, 0.0f, 1.0f); windowBatch.Normal3f( 0.0f, 1.0f, 0.0f); windowBatch.Vertex3f(-1.0f, 2.0f, 0.0f); windowBatch.End(); const float width = 0.2f; const float gridWidth = (float)0.05; windowBorderBatch.Begin(GL_TRIANGLE_STRIP, 13); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01f, width, 0.01f); windowBorderBatch.Normal3f(0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01f, 0.0f, 0.01f); windowBorderBatch.Normal3f(0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01f, width, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01f, 0.0f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01-width, 0.0f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01f, 2.0f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01-width, 2.0f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(1.01f, 2.0-width, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01f, 2.f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01f, 2.0-width, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01+width, 2.f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01f, 0.0f, 0.01f); windowBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowBorderBatch.Vertex3f(-1.01+width, 0.0f, 0.01f); windowBorderBatch.End(); windowGridBatch.Begin(GL_TRIANGLES, 24); // bottom horizontal windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 0.7+gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 0.7-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 0.7-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 0.7-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 0.7+gridWidth, 0.01f); windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 0.7+gridWidth, 0.01f); // Top horizontal windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 1.3+gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 1.3-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 1.3-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 1.3-gridWidth, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(1.0f, 1.3+gridWidth, 0.01f); windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-1.0f, 1.3+gridWidth, 0.01f); // Left Vertical windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3+gridWidth, 0.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3-gridWidth, 0.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3-gridWidth, 2.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3-gridWidth, 2.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3+gridWidth, 2.0, 0.01f); windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(-0.3+gridWidth, 0.0f, 0.01f); // Right Vertical windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3+gridWidth, 0.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3-gridWidth, 0.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3-gridWidth, 2.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3-gridWidth, 2.0f, 0.01f); windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3+gridWidth, 2.0, 0.01f); windowGridBatch.Normal3f( 0.0f, 0.0f, 1.0f); windowGridBatch.Vertex3f(0.3+gridWidth, 0.0f, 0.01f); windowGridBatch.End(); glGenTextures(1, textures); glBindTexture(GL_TEXTURE_2D, textures[0]); LoadBMPTexture("marble.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT); // Setup HDR render texture glGenTextures(1, hdrTextures); glBindTexture(GL_TEXTURE_2D, hdrTextures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth, screenHeight, 0, GL_RGBA, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // create textures for bloom effect glGenTextures(5, brightBlurTextures); int i = 0; for (i=0; i<5; i++) { glBindTexture(GL_TEXTURE_2D, brightBlurTextures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth, screenHeight, 0, GL_RGBA, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } // Attach HDR texture to fbo // Create and bind an FBO glGenFramebuffers(1,hdrFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, hdrFBO[0]); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdrTextures[0], 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, brightBlurTextures[0], 0); // Create FBOs for bloom effect glGenFramebuffers(4,brightPassFBO); for (i=0; i<4; i++) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, brightPassFBO[i]); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brightBlurTextures[i+1], 0); } // Create window texture glGenTextures(1, &windowTexture); glBindTexture(GL_TEXTURE_2D, windowTexture); GLuint texWidth = 0; GLuint texHeight = 0; // Load HDR image from EXR file LoadOpenEXRImage("window.exr", windowTexture, texWidth, texHeight); // Load flat color shader flatColorProg = gltLoadShaderPairWithAttributes("basic.vs", "color.fs", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0"); glBindFragDataLocation(flatColorProg, 0, "oColor"); glBindFragDataLocation(flatColorProg, 1, "oBright"); glLinkProgram(flatColorProg); // Load texture replace shader texReplaceProg = gltLoadShaderPairWithAttributes("basic.vs", "tex_replace.fs", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0"); glBindFragDataLocation(texReplaceProg, 0, "oColor"); glBindFragDataLocation(texReplaceProg, 1, "oBright"); glLinkProgram(texReplaceProg); // Load bloom shader hdrBloomProg = gltLoadShaderPairWithAttributes("basic.vs", "hdr_exposure.fs", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0"); glBindFragDataLocation(hdrBloomProg, 0, "oColor"); glLinkProgram(hdrBloomProg); // Load blur shader blurProg = gltLoadShaderPairWithAttributes("basic.vs", "blur.fs", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0"); glBindFragDataLocation(blurProg, 0, "oColor"); glLinkProgram(blurProg); glUseProgram(blurProg); // Setup tex coords to be used for fetching HDR kernel data GenTexCoordOffsets(screenWidth, screenHeight); glUniform2fv(glGetUniformLocation(blurProg, "tc_offset"), 25, &texCoordOffsets[0]); // Make sure all went well gltCheckErrors(flatColorProg); gltCheckErrors(texReplaceProg); gltCheckErrors(hdrBloomProg); gltCheckErrors(blurProg); // Reset framebuffer binding glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);}// Take a file name/location and load an OpenEXR// Load the image into the "texture" texture object and pass back the texture sizes// bool LoadOpenEXRImage(char *fileName, GLint textureName, GLuint &texWidth, GLuint &texHeight){ // The OpenEXR uses exception handling to report errors or failures // Do all work in a try block to catch any thrown exceptions. try { Imf::Array2D
pixels; Imf::RgbaInputFile file (fileName); Imath::Box2i dw = file.dataWindow(); texWidth = dw.max.x - dw.min.x + 1; texHeight = dw.max.y - dw.min.y + 1; pixels.resizeErase (texHeight, texWidth); file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * texWidth, 1, texWidth); file.readPixels (dw.min.y, dw.max.y); GLfloat* texels = (GLfloat*)malloc(texWidth * texHeight * 3 * sizeof(GLfloat)); GLfloat* pTex = texels; // Copy OpenEXR into local buffer for loading into a texture for (unsigned int v = 0; v < texHeight; v++) { for (unsigned int u = 0; u < texWidth; u++) { Imf::Rgba texel = pixels[texHeight - v - 1][u]; pTex[0] = texel.r; pTex[1] = texel.g; pTex[2] = texel.b; pTex += 3; } } // Bind texture, load image, set tex state glBindTexture(GL_TEXTURE_2D, textureName); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, texWidth, texHeight, 0, GL_RGB, GL_FLOAT, texels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); free(texels); } catch(Iex::BaseExc & e) { std::cerr << e.what() << std::endl; // // Handle exception. // } return true;}///// Do your cleanup here. Free textures, display lists, buffer objects, etc.void ShutdownRC(void){ // Make sure default FBO is bound glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // Cleanup textures for (int i=0; i<5;i++) { glActiveTexture(GL_TEXTURE0+i); glBindTexture(GL_TEXTURE_2D, 0); } glDeleteTextures(1, textures); glDeleteTextures(1, hdrTextures); glDeleteTextures(5, brightBlurTextures); glDeleteTextures(1, &windowTexture); // Cleanup FBOs glDeleteFramebuffers(1, hdrFBO); glDeleteFramebuffers(1, brightPassFBO);}void SetupFlatColorProg(GLfloat *vLightPos, GLfloat *vColor){ glUseProgram(flatColorProg); // Set projection matrix glUniformMatrix4fv(glGetUniformLocation(flatColorProg, "pMatrix"), 1, GL_FALSE, transformPipeline.GetProjectionMatrix()); // Set MVP matrix glUniformMatrix4fv(glGetUniformLocation(flatColorProg, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); // Set Light Pos glUniform3fv(glGetUniformLocation(flatColorProg, "vLightPos"), 1, vLightPos); // Set Color glUniform4fv(glGetUniformLocation(flatColorProg, "vColor"), 1, vColor); gltCheckErrors(flatColorProg);}void SetupTexReplaceProg(GLfloat *vLightPos, GLfloat *vColor){ glUseProgram(texReplaceProg); // Set projection matrix glUniformMatrix4fv(glGetUniformLocation(texReplaceProg, "pMatrix"), 1, GL_FALSE, transformPipeline.GetProjectionMatrix()); // Set MVP matrix glUniformMatrix4fv(glGetUniformLocation(texReplaceProg, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); // Set Light Pos glUniform3fv(glGetUniformLocation(texReplaceProg, "vLightPos"), 1, vLightPos); // Set Color glUniform4fv(glGetUniformLocation(texReplaceProg, "vColor"), 1, vColor); // Set Tex Unit glUniform1i(glGetUniformLocation(texReplaceProg, "textureUnit0"), 0); gltCheckErrors(texReplaceProg);}void SetupHDRProg(){ glUseProgram(hdrBloomProg); // Set projection matrix glUniformMatrix4fv(glGetUniformLocation(hdrBloomProg, "pMatrix"), 1, GL_FALSE, transformPipeline.GetProjectionMatrix()); // Set MVP matrix glUniformMatrix4fv(glGetUniformLocation(hdrBloomProg, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); // Set user controled uniforms glUniform1fv(glGetUniformLocation(hdrBloomProg, "exposure"), 1, &exposure); glUniform1fv(glGetUniformLocation(hdrBloomProg, "bloomLevel"), 1, &bloomLevel); // Set texture uniforms glUniform1i(glGetUniformLocation(hdrBloomProg, "origImage"), 0); glUniform1i(glGetUniformLocation(hdrBloomProg, "brightImage"), 1); glUniform1i(glGetUniformLocation(hdrBloomProg, "blur1"), 2); glUniform1i(glGetUniformLocation(hdrBloomProg, "blur2"), 3); glUniform1i(glGetUniformLocation(hdrBloomProg, "blur3"), 4); glUniform1i(glGetUniformLocation(hdrBloomProg, "blur4"), 5); // Now setup the right textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdrTextures[0]); for (int i=0; i<5; i++) { glActiveTexture(GL_TEXTURE1+i); glBindTexture(GL_TEXTURE_2D, brightBlurTextures[i]); } gltCheckErrors(hdrBloomProg);} void SetupBlurProg(){ // Set the program to the cur glUseProgram(blurProg); // Set projection matrix glUniformMatrix4fv(glGetUniformLocation(blurProg, "pMatrix"), 1, GL_FALSE, transformPipeline.GetProjectionMatrix()); // Set MVP matrix glUniformMatrix4fv(glGetUniformLocation(blurProg, "mvMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewMatrix()); glUniform1i(glGetUniformLocation(blurProg, "textureUnit0"), 0); gltCheckErrors(blurProg);}///// This is called at least once and before any rendering occurs. If the screen// is a resizeable window, then this will also get called whenever the window// is resized.void ChangeSize(int nWidth, int nHeight){ glViewport(0, 0, nWidth, nHeight); transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); modelViewMatrix.LoadIdentity(); // update screen sizes screenWidth = nWidth; screenHeight = nHeight; glBindTexture(GL_TEXTURE_2D, hdrTextures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth, screenHeight, 0, GL_RGBA, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, brightBlurTextures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth, screenHeight, 0, GL_RGBA, GL_FLOAT, NULL); for(int i=1; i<5; i++) { glBindTexture(GL_TEXTURE_2D, brightBlurTextures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth/(i*3.0), screenHeight/(i*3.0), 0, GL_RGBA, GL_FLOAT, NULL); } // Setup tex coords to be used for fetching HDR kernel data glUseProgram(blurProg); GenTexCoordOffsets(screenWidth, screenHeight); glUniform2fv(glGetUniformLocation(blurProg, "tc_offset"), 25, texCoordOffsets); GenerateOrtho2DMat(nWidth, nHeight); glUseProgram(0);}///// Create a matrix that maps geometry to the screen. 1 unit in the x directionequals one pixel // of width, same with the y direction.//void GenerateOrtho2DMat(GLuint imageWidth, GLuint imageHeight){ float right = (float)imageWidth; float quadWidth = right; float left = 0.0f; float top = (float)imageHeight; float quadHeight = top; float bottom = 0.0f; // set ortho matrix orthoMatrix[0] = (float)(2 / (right)); orthoMatrix[1] = 0.0; orthoMatrix[2] = 0.0; orthoMatrix[3] = 0.0; orthoMatrix[4] = 0.0; orthoMatrix[5] = (float)(2 / (top)); orthoMatrix[6] = 0.0; orthoMatrix[7] = 0.0; orthoMatrix[8] = 0.0; orthoMatrix[9] = 0.0; orthoMatrix[10] = (float)(-2 / (1.0 - 0.0)); orthoMatrix[11] = 0.0; orthoMatrix[12] = -1.0f; orthoMatrix[13] = -1.0f; orthoMatrix[14] = -1.0f; orthoMatrix[15] = 1.0; // set screen quad vertex array screenQuad.Reset(); screenQuad.Begin(GL_TRIANGLE_STRIP, 4, 1); screenQuad.Color4f(0.0f, 1.0f, 0.0f, 1.0f); screenQuad.MultiTexCoord2f(0, 0.0f, 0.0f); screenQuad.Vertex3f(0.0f, 0.0f, 0.0f); screenQuad.Color4f(0.0f, 1.0f, 0.0f, 1.0f); screenQuad.MultiTexCoord2f(0, 1.0f, 0.0f); screenQuad.Vertex3f(right, 0.0f, 0.0f); screenQuad.Color4f(0.0f, 1.0f, 0.0f, 1.0f); screenQuad.MultiTexCoord2f(0, 0.0f, 1.0f); screenQuad.Vertex3f(0.0f, top, 0.0f); screenQuad.Color4f(0.0f, 1.0f, 0.0f, 1.0f); screenQuad.MultiTexCoord2f(0, 1.0f, 1.0f); screenQuad.Vertex3f(right, top, 0.0f); screenQuad.End();}///// Update the camera based on user input, toggle display modes// void SpecialKeys(int key, int x, int y){ static CStopWatch timer; float fTime = timer.GetElapsedSeconds(); float linear = fTime / 100; float smallLinear = fTime / 1000; // Increase the scene exposure if(key == GLUT_KEY_UP) { if((exposure + linear) < 20.0f) exposure += linear; } // Decrease the scene exposure if(key == GLUT_KEY_DOWN) { if((exposure - linear) > 0.01f) exposure -= linear; } // Decrease amount of bloom effect if(key == GLUT_KEY_LEFT) { if((bloomLevel - smallLinear) > 0.00f) bloomLevel -= smallLinear; } // Increase amount of bloom effect if(key == GLUT_KEY_RIGHT) { if((bloomLevel + smallLinear) < 1.5f) bloomLevel += smallLinear; }}///// Render a frame. The owning framework is responsible for buffer swaps,// flushes, etc.void RenderScene(void){ int i =0; // first render the scene in HDR to fbo glBindFramebuffer(GL_DRAW_FRAMEBUFFER, hdrFBO[0]); glDrawBuffers(1, &fboBuffs[0]); glClearColor(vSkyBlue[0], vSkyBlue[1], vSkyBlue[2], vSkyBlue[3]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawBuffers(1, &fboBuffs[1]); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw to two textures, the first contains scene data // the second contains only the bright areas glDrawBuffers(2, fboBuffs); modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble // Draw the floor SetupTexReplaceProg(vLightPos, vWhite); floorBatch.Draw(); // Draw the window modelViewMatrix.PushMatrix(); modelViewMatrix.Translate(0.0f, -0.4f, -4.0f); modelViewMatrix.Rotate(10.0, 0.0, 1.0, 0.0); glBindTexture(GL_TEXTURE_2D, windowTexture); // Window Tex // First draw the window contents from texture SetupTexReplaceProg(vLightPos, vWhiteX2); windowBatch.Draw(); // Now draw the border and the grid SetupFlatColorProg(vLightPos, vGrey); windowGridBatch.Draw(); windowBorderBatch.Draw(); modelViewMatrix.PopMatrix(); modelViewMatrix.PopMatrix(); projectionMatrix.PushMatrix(); projectionMatrix.LoadMatrix(orthoMatrix); modelViewMatrix.PushMatrix(); modelViewMatrix.LoadIdentity(); // Take the data from the brightness texture and // blur it in 4 consecutive passes to textures of // decreasing size SetupBlurProg(); for (i =0; i<4; i++) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, brightPassFBO[i]); // draws into brightBlurTextures[i+1] glDrawBuffers(1, &fboBuffs[0]); glViewport(0, 0, screenWidth/((i+1)*3.0), screenHeight/((i+1)*3.0)); glBindTexture(GL_TEXTURE_2D, brightBlurTextures[i]); screenQuad.Draw(); } // Combine original scene with blurred bright textures // to create the bloom effect glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffers(1,windowBuff); glViewport(0, 0, screenWidth, screenHeight); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); SetupHDRProg(); screenQuad.Draw(); modelViewMatrix.PopMatrix(); projectionMatrix.PopMatrix(); // Put the texture units back the way they were for (i=5; i>-1; i--) { glActiveTexture(GL_TEXTURE0+i); glBindTexture(GL_TEXTURE_2D, 0); } // Do the buffer Swap glutSwapBuffers(); // Do it again glutPostRedisplay();}int main(int argc, char* argv[]){ screenWidth = 800; screenHeight = 600; bFullScreen = false; bAnimated = true; bloomLevel = 0.0; cameraFrame.MoveUp(0.50); gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(screenWidth,screenHeight); glutCreateWindow("HDR Bloom"); glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); glutSpecialFunc(SpecialKeys); SetupRC(); glutMainLoop(); ShutdownRC(); return 0;}

 

上一篇:【OpenGL】多重采样案例MSAA
下一篇:【OpenGL】HDR相关——hdr_imaging示例程序

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月09日 03时27分37秒