【OpenGL】多重采样案例MSAA

 示例图暂缺(目前运行exe失败,后期补充)

本文比较难,个人来说还不是完全弄懂。

#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); 
}

 处理曝光效果的顶点着色器如上,大致内容就是转换顶点空间和获得纹理坐标以及传给片段着色器的漫反射颜色值

#version 150 
// color.fs
// outputs 1 color interpolated from VS
// 


in vec4 vFragColor; 
in vec2 vTexCoord; 

uniform sampler2D textureUnit0; 
uniform vec4 vColor;

out vec4 oColor;
out vec4 oBright;

void main(void) 
{ 
	const float bloomLimit = 1.0;
    
    oColor =  vFragColor;
    
    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;
}

 专门获取一个自定义颜色图和亮度图的片段着色器 和 前一个案例HDR_Bloom一样

#version 150 
// hdr_exposure.fs
// Scale floating point texture to 0.0 - 1.0 based 
// on the specified exposure
// Resolve multisample buffer based on input sample count
// 

in vec2 vTexCoord;

uniform sampler2DMS origImage;
uniform samplerBuffer sampleWeightSampler; 
uniform int sampleCount; // 0-based, 0=1sample, 1=2samples, etc
uniform int useWeightedResolve; // 0-false, 1-true
uniform float exposure;

out vec4 oColor;

// do all tone mapping in a separate function
vec4 toneMap(vec4 vHdrColor)
{
	vec4 vLdrColor;
	vLdrColor = 1.0 - exp2(-vHdrColor * exposure);
	vLdrColor.a = 1.0f;
	return vLdrColor;
}

void main(void) 
{ 
    // Calculate un-normalized texture coordinates
	vec2 tmp = floor(textureSize2DMS(origImage) * vTexCoord); 

    // Find both the weighted and unweighted colors
	vec4 vColor = vec4(0.0, 0.0, 0.0, 1.0);
	vec4 vWeightedColor = vec4(0.0, 0.0, 0.0, 1.0);
	
	for (int i = 0; i <= sampleCount; i++)
	{
	    // Get the weight for this sample from the texBo, this changes
	    // based on the number of samples
	    float weight = texelFetch(sampleWeightSampler, i).r;
	    
	    // tone-map the HDR texel before it is weighted
	    vec4 sample = toneMap(texelFetch(origImage, ivec2(tmp), i));
	    
		vWeightedColor += sample * weight;
		vColor += sample;
	}

    // now, decide on the type of resolve to perform
    oColor = vWeightedColor;
	
	// if the user selected the unweighed resolve, output the 
	// equally weighted value
	if (useWeightedResolve != 0)
	{
	    oColor = vColor / (sampleCount+1);    
	}

    oColor.a = 1.0f;
    
}

 处理多重采样的片段着色器,先映射纹理坐标到多重采样图像范围(它变为整数)接着从sampleWeightSampler纹理缓冲区获取权值,权值是位像素距离归一化数值,一共进行sampleCount次采样权值 并且也同样地进行从origImage多重采样纹理获取颜色值,并累加到vColor上,累加到vWeightedColor会乘上对应的位像素权值,最终以useWeightedResolve不为0则以vColor求平均值输出,否则则是输出vWeightedColor。关于这种乘以权值的操作是称之为卷积的,它最终所有数值相加到一起会是一个不超过1范围的值。

#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;
}

 与color.fs区别在于,oColor是HDR图像颜色。

C++代码如下:

#pragma comment(lib, "gltools.lib")
#include <stdio.h>
#include <iostream>
#include <ImfRgbaFile.h>            // OpenEXR headers
#include <ImfArray.h>

#include <GLTools.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <GL\glu.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#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 vLtGrey[] = { 0.75f, 0.75f, 0.75f, 1.0f };
static GLfloat vLightPos[] = { -2.0f, 3.0f, -2.0f, 1.0f };
static GLfloat vSkyBlue[] = { 0.260f, 0.476f, 0.925f, 1.0f };

static const GLenum windowBuff[] = { GL_BACK_LEFT };
static const GLenum fboBuffs[] = { GL_COLOR_ATTACHMENT0 };

GLsizei	 screenWidth;			// Desired window or desktop width
GLsizei  screenHeight;			// Desired window or desktop height

GLboolean bFullScreen;			// Request to run full screen
GLboolean bAnimated;			// Request for continual updates

GLMatrixStack		modelViewMatrix;		// Modelview Matrix
GLMatrixStack		projectionMatrix;		// Projection Matrix
GLFrustum			viewFrustum;			// View Frustum
GLGeometryTransform	transformPipeline;		// Geometry Transform Pipeline
GLFrame				cameraFrame;			// Camera frame
GLBatch             screenQuad;
M3DMatrix44f        orthoMatrix;

GLBatch				floorBatch;
GLBatch				windowBatch;
GLBatch				windowBorderBatch;
GLBatch				windowGridBatch;

GLuint				flatColorProg;
GLuint				texReplaceProg;
GLuint				hdrResolve;
GLuint				blurProg;

GLuint              hdrFBO[1];
GLuint              brightPassFBO[4];
GLuint				textures[1];
GLuint				hdrTextures[1];
GLuint              texBOTexture;
GLuint				windowTexture;
GLfloat				exposure;
GLint				sampleCount;
GLint               lastSampleCount;
GLuint				sampleWeightBuf;
GLfloat				sampleWeights[8][8];
GLuint              useWeightedResolve;

void GenerateOrtho2DMat(GLuint imageWidth, GLuint imageHeight);
bool LoadOpenEXRImage(char *fileName, GLint textureName, GLuint &texWidth, GLuint &texHeight);
void SetupTexReplaceProg(GLfloat *vLightPos, GLfloat *vColor);
void SetupFlatColorProg(GLfloat *vLightPos, GLfloat *vColor);
void SetupHDRProg();

///
// Load in a BMP file as a texture. Allows specification of the filters and the wrap mode
bool 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);

	// 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);

	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);
	return true;
}



///
// 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;

	// 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, 1.00f, 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, 1.00f, 1.00f);
	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, 1.00f);
	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;
	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();

	const float gridWidth = (float)0.01;
	const int gridLineCount = 24;
	windowGridBatch.Begin(GL_TRIANGLES, gridLineCount * 2 * 6);
	// bottom horizontal

	for (int i = 0; i < gridLineCount; i++)
	{
		float offset = 2 * ((float)(i + 1) / (float)(gridLineCount + 1));
		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(-1.0f, offset + gridWidth, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(-1.0f, offset - gridWidth, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(1.0f, offset - gridWidth, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(1.0f, offset - gridWidth, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(1.0f, offset + gridWidth, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(-1.0f, offset + gridWidth, 0.01f);
	}

	//  Verticals
	for (int i = 0; i < gridLineCount; i++)
	{
		float offset = 2 * ((float)(i + 1) / (float)(gridLineCount + 1)) - 1.0;
		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset + gridWidth, 0.0f, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset - gridWidth, 0.0f, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset - gridWidth, 2.0f, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset - gridWidth, 2.0f, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset + gridWidth, 2.0, 0.01f);

		windowGridBatch.Normal3f(0.0f, 0.0f, 1.0f);
		windowGridBatch.Vertex3f(offset + 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_MULTISAMPLE, hdrTextures[0]);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB16F, screenWidth, screenHeight, GL_FALSE);

	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);

	// Create window texture
	glGenTextures(1, &windowTexture);
	glBindTexture(GL_TEXTURE_2D, windowTexture);
	GLuint texWidth = 0;
	GLuint texHeight = 0;
	// Load HDR image from EXR file
	LoadOpenEXRImage(const_cast<char*>("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
	hdrResolve = gltLoadShaderPairWithAttributes("basic.vs", "hdr_exposure.fs", 3,
		GLT_ATTRIBUTE_VERTEX, "vVertex",
		GLT_ATTRIBUTE_NORMAL, "vNormal",
		GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0");
	glBindFragDataLocation(hdrResolve, 0, "oColor");
	glLinkProgram(hdrResolve);

	// Uncomment the line below to get the correct behavior.
	floorBatch.Draw();

	// Get the location of each multisample sample
	int sampleCount = 0;
	glGetIntegerv(GL_SAMPLES, &sampleCount);

	float positions[64]; // Enough for at least 32 samples
	for (int i = 0; i < sampleCount; i++)
	{
		glGetMultisamplefv(GL_SAMPLE_POSITION, i, &positions[i * 2]);
	}

	// Limit sample count to 8x
	//assert(sampleCount >= 8);
	sampleCount = 8;

	float invertedSampleDistances[8];
	// The maxDist is used for doing the distance inversion
	// You could use the actual max dist a sample could be, but that
	// would mean that sample would receive a weighting of 0, use 1.0 instead.
	//float maxDist = sqrt(0.5*0.5*2);
	float maxDist = 1.0f;

	// calculate the distance of each sample from the center,
	// then invert it so that samples closer to the center recieve more weight
	for (int i = 0; i < 8; i++)
	{
		double xDist = positions[i * 2] - 0.5;
		double yDist = positions[i * 2 + 1] - 0.5;
		invertedSampleDistances[i] = maxDist - sqrt(xDist*xDist + yDist * yDist);
	}

	// zero out sample weights array
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			sampleWeights[i][j] = 0.0f;
		}
	}

	// First array is easy, 1 sample so that samples weight is 1
	sampleWeights[0][0] = 1.0f;

	// Add up the distances to get the total used for calculating weights
	for (int i = 1; i < 8; i++)
	{
		float totalWeight = 0.0f;
		for (int j = 0; j <= i; j++)
			totalWeight += invertedSampleDistances[j];

		// Invert to get the factor used for each sample, the sum of all sample weights is always 1.0
		float perSampleFactor = 1 / totalWeight;
		for (int j = 0; j <= i; j++)
			sampleWeights[i][j] = invertedSampleDistances[j] * perSampleFactor;
	}

	// Setup a texture buffer object for holding the sample weights
	glGenBuffers(1, &sampleWeightBuf);
	glBindBuffer(GL_TEXTURE_BUFFER_ARB, sampleWeightBuf);
	glBufferData(GL_TEXTURE_BUFFER_ARB, sizeof(float) * 8, sampleWeights, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_TEXTURE_BUFFER_ARB, 0);

	// Load the texBO into texture 1
	glActiveTexture(GL_TEXTURE1);
	glGenTextures(1, &texBOTexture);
	glBindTexture(GL_TEXTURE_BUFFER_ARB, texBOTexture);
	glTexBufferARB(GL_TEXTURE_BUFFER_ARB, GL_R32F, sampleWeightBuf);
	glActiveTexture(GL_TEXTURE0);

	// 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<Imf::Rgba> 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(1, &texBOTexture);
	glDeleteTextures(1, &windowTexture);

	// cleanup buffers
	glDeleteBuffers(1, &sampleWeightBuf);

	// Cleanup FBOs
	glDeleteFramebuffers(1, hdrFBO);
}
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(hdrResolve);

	// Set projection matrix
	glUniformMatrix4fv(glGetUniformLocation(hdrResolve, "pMatrix"),
		1, GL_FALSE, transformPipeline.GetProjectionMatrix());

	// Set MVP matrix
	glUniformMatrix4fv(glGetUniformLocation(hdrResolve, "mvMatrix"),
		1, GL_FALSE, transformPipeline.GetModelViewMatrix());

	// Set user controled uniforms
	glUniform1fv(glGetUniformLocation(hdrResolve, "exposure"), 1, &exposure);

	// Set texture uniforms
	glUniform1i(glGetUniformLocation(hdrResolve, "origImage"), 0);
	glUniform1i(glGetUniformLocation(hdrResolve, "sampleWeightSampler"), 1);

	// Setup MS sepcific uniforms
	glUniform1i(glGetUniformLocation(hdrResolve, "sampleCount"), sampleCount);
	glUniform1i(glGetUniformLocation(hdrResolve, "useWeightedResolve"), useWeightedResolve);

	// Now setup the right textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, hdrTextures[0]);

	// Check if sample weight buffer needs to be updated
	if (sampleCount != lastSampleCount)
	{
		glBindBuffer(GL_TEXTURE_BUFFER_ARB, sampleWeightBuf);
		void *data = glMapBufferRange(GL_TEXTURE_BUFFER_ARB, 0, sizeof(float) * 8,
			(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT));
		memcpy(data, (void*)sampleWeights[sampleCount], sizeof(float) * 8);
		glUnmapBuffer(GL_TEXTURE_BUFFER_ARB);
		lastSampleCount = sampleCount;
	}

	gltCheckErrors(hdrResolve);
}

///
// 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_MULTISAMPLE, hdrTextures[0]);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB16F, screenWidth, screenHeight, GL_FALSE);

	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 + smallLinear) < 20.0f)
			exposure += smallLinear;
	}
	// Decrease the scene exposure
	if (key == GLUT_KEY_DOWN)
	{
		if ((exposure - smallLinear) > 0.01f)
			exposure -= smallLinear;
	}
}


void ProcessKeys(unsigned char key, int x, int y)
{
	if (key == 'q' || key == 'Q')
	{
		useWeightedResolve = 0;
	}
	if (key == 'w' || key == 'W')
	{
		useWeightedResolve = 1;
	}

	if (key == '1')
		sampleCount = 0;
	else if (key == '2')
		sampleCount = 1;
	else if (key == '3')
		sampleCount = 2;
	else if (key == '4')
		sampleCount = 3;
	else if (key == '5')
		sampleCount = 4;
	else if (key == '6')
		sampleCount = 5;
	else if (key == '7')
		sampleCount = 6;
	else if (key == '8')
		sampleCount = 7;
}



///
// Render a frame. The owning framework is responsible for buffer swaps,
// flushes, etc.
void RenderScene(void)
{
	// 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);

	// Draw to two textures, the first contains scene data
	// the second contains only the bright areas
	modelViewMatrix.PushMatrix();
	M3DMatrix44f mCamera;
	cameraFrame.GetCameraMatrix(mCamera);
	modelViewMatrix.MultMatrix(mCamera);
	glActiveTexture(GL_TEXTURE0);
	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, vLtGrey);
	windowGridBatch.Draw();
	windowBorderBatch.Draw();

	modelViewMatrix.PopMatrix();
	modelViewMatrix.PopMatrix();

	projectionMatrix.PushMatrix();
	projectionMatrix.LoadMatrix(orthoMatrix);
	modelViewMatrix.PushMatrix();
	modelViewMatrix.LoadIdentity();

	// 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
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);

	// Do the buffer Swap
	glutSwapBuffers();

	// Do it again
	glutPostRedisplay();
}

int main(int argc, char* argv[])
{
	screenWidth = 800;
	screenHeight = 600;
	sampleCount = 0;
	useWeightedResolve = 1;

	gltSetWorkingDirectory(argv[0]);

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(screenWidth, screenHeight);

	glutCreateWindow("HDR MSAA");

	glutReshapeFunc(ChangeSize);
	glutDisplayFunc(RenderScene);
	glutSpecialFunc(SpecialKeys);
	glutKeyboardFunc(ProcessKeys);

	SetupRC();
	glutMainLoop();
	ShutdownRC();
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值