【OpenGL】样本遮罩OIT示例——解决透明物体之间的渲染顺序问题

 不开启OIT 仅做多重采样混合处理

可见,蓝色本应在紫色后面的,但却显示在了紫色前面。(产生半透明物体顺序错乱问题,OpenGL没有Unity一样对半透明物体进行远到近渲染的,但OIT就是从GPU上对物体进行远到近渲染)

开启OIT 

OIT个人看法:将场景整个渲染到一个自定义FBO缓冲区对应的2个绑定点贴图 即 多重采样颜色图 和 多重采样深度图 (多重采样是指创建贴图时 采用了GL_TEXTURE_2D_MULTISAMPLE 参数),接着在同一个片段着色器里进行对这2个图采样多次,拿到深度值数组后进行排序,最终会从深度大到小的顺序(即远到近)进行样本颜色值rgb叠加,最终输出。

案例中也有使用样本遮罩,个人目前还看不出它发挥的作用。

1、将所有几何图形绘制到一个多重采样缓冲区。所有不透明的对象都被进行遮罩到样本0,每个半透明物体都使用样本遮罩来渲染到唯一的样本。

	// User selected order independant transparency
    if (mode == USER_OIT)
    {
        // Use OIT, setup sample masks
        glSampleMaski(0, 0x01);
        glEnable(GL_SAMPLE_MASK);

		// Prevent depth test from culling covered surfaces
        glDepthFunc(GL_ALWAYS);
    }


.... ... 
  glBindTexture(GL_TEXTURE_2D, textures[1]); 
          shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
          bckgrndCylBatch.Draw();

... ...
            shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGrey);
            diskBatch.Draw();

代码设置遮罩为0x01 十六进制数,即0000 0001。开启样本遮罩。开启深度检测。最先开始进行的是不透明物体的渲染. (bckgrndCylBatch , diskBatch)

   glSampleMaski(0, 0x02);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtYellow);
        glass1Batch.Draw();

...

  glSampleMaski(0, 0x04);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtGreen);
        glass2Batch.Draw();

...

        glSampleMaski(0, 0x08);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtMagenta);
        glass3Batch.Draw();

... 
        glSampleMaski(0, 0x10);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtBlue);
        glass4Batch.Draw();

...

        glSampleMaski(0, 0x20);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtPink);
        glass4Batch.Draw();

渲染半透明的5个glass,分别设置不同的样本遮罩。当所有的表面都各自绘制到唯一的样本位置时,它们必须进行组合。但是使用常规的多重采样解析是做不到的!因此,我们使用自定义的解析着色器来代替。每个样本的颜色值和深度值首先被提取到一个数组中,然后进行分析以确定片段的颜色。

#version 150 
// oitResolve.fs
// 

in vec2 vTexCoord;

uniform sampler2DMS origImage;
uniform sampler2DMS origDepth;

out vec4 oColor;

void main(void) 
{ 
    const int sampleCount = 8;
    	
    vec4  vColor[sampleCount];
	float vDepth[sampleCount];
	int   vSurfOrder[sampleCount];
	int   i = 0;
	
    // Calculate un-normalized texture coordinates
	vec2 tmp = floor(textureSize2DMS(origDepth) * vTexCoord); 
		
    // First, get sample data and init the surface order
	for (i = 0; i < sampleCount; i++)
	{
		vSurfOrder[i] = i;
        vColor[i] = texelFetch(origImage, ivec2(tmp), i);
	    vDepth[i] = texelFetch(origDepth, ivec2(tmp), i).r;
	}
	
	// Sort depth values, largest to front and smallest to back
	// Must run through array (size^2-size) times, or early-exit
	// if any pass shows all samples to be in order
	for (int j = 0; j < sampleCount; j++)
    {
		bool bFinished = true;
        for (i = 0; i < (sampleCount-1); i++)
	    {
	        float temp1 = vDepth[vSurfOrder[i]];
	        float temp2 = vDepth[vSurfOrder[i+1]];
    	    
	        if (temp2 < temp1)
	        {
	            // swap values
	            int tempIndex   = vSurfOrder[i];
	            vSurfOrder[i]   = vSurfOrder[i+1];
	            vSurfOrder[i+1] = tempIndex;
	            bFinished = false;
	        }
	    }
	    
	    if (bFinished)
            j = 8;
	}
	
	// Now, sum all colors in order from front to back. Apply alpha.
	bool bFoundFirstColor = false;
	vec4 summedColor = vec4(0.0, 0.0, 0.0, 0.0);
	for (i = (sampleCount-1); i >= 0; i--)
    {
		int surfIndex = vSurfOrder[i];
		if(vColor[surfIndex].a > 0.001)
		{
			if (bFoundFirstColor == false)
			{
				// apply 100% of the first color
				summedColor = vColor[surfIndex];
				bFoundFirstColor = true;
			}
			else
			{
				// apply color with alpha
				summedColor.rgb = (summedColor.rgb * (1 - vColor[surfIndex].a))     +
				                  (vColor[surfIndex].rgb * vColor[surfIndex].a);
			}
		}
    }
   
   oColor = summedColor;
   
    int surfIndex = 2;
    float val = vDepth[vSurfOrder[surfIndex]];
    //oColor = vec4(val, val, val, 1.0);
    //oColor = vec4(vColor[vSurfOrder[surfIndex]].rgb, 1.0);
    //oColor = vec4(vColor[0].rgb, 1.0);
    oColor.a = 1.0f;
}

上面片段着色器代码功能是按深度解析多个层次,从外部获得2个统一值:origImage是经过了多重采样处理的场景全部物体颜色图,origDepth是经过了多重采样处理的场景全部物体深度图。首先,根据深度图大小*纹理坐标拿到整数纹理坐标,开始对颜色多重采样纹理和深度多重采样纹理采样sampleCount次将结果分别存于vColor和vDepth以及索引数组vSurfOrder,接着根据深度值vDepth由小到大排序索引数值vSurfOrder,最后从后往前遍历vSurfOrder(即从深度值大的到深度值小的遍历,即先处理远处的再到近处的)叠加样本颜色(仅针对RGB的混合操作GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)【注意着色器使用时并没有开启透明混合的!】最后输出叠加结果颜色到屏幕上。多重采样纹理图的每一个样本像素都有它自身的透明度和深度值、颜色值等独立的信息,可以说是硬件本身帮我们进行了准备了这些数据才得以进行这种再排序深度并重新构建颜色输出的行为。

这样无论半透明物体渲染顺序怎么变,这个着色器都会保证最终输出的结果是正确的样子!(OIT无敌,但是不是for if 多了点儿?消耗挺大的啊)但我们要考虑多重采样缓冲区的样本上限,只能支持处理多重采样缓冲区支持的样本上限个数的透明对象。使用多重采样缓冲区进行OIT时是不允许使用多重采样缓冲区再进行抗锯齿操作了,因为它不会对样本叠加值进行求平均啊!

全文件代码如下:

#version 130 
// basic.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); 
	gl_TexCoord[0] = gl_MultiTexCoord0;
}
#version 150
// oitResolve.fs
// 

in vec2 vTexCoord;

uniform sampler2DMS origImage;
uniform sampler2DMS origDepth;

out vec4 oColor;

void main(void) 
{ 
    const int sampleCount = 8;
    	
    vec4  vColor[sampleCount];
	float vDepth[sampleCount];
	int   vSurfOrder[sampleCount];
	int   i = 0;
	
    // Calculate un-normalized texture coordinates
	vec2 tmp = floor(textureSize(origDepth) * vTexCoord); 
		
    // First, get sample data and init the surface order
	for (i = 0; i < sampleCount; i++)
	{
		vSurfOrder[i] = i;
        vColor[i] = texelFetch(origImage, ivec2(tmp), i);
	    vDepth[i] = texelFetch(origDepth, ivec2(tmp), i).r;
	}
	
	// Sort depth values, largest to front and smallest to back
	// Must run through array (size^2-size) times, or early-exit
	// if any pass shows all samples to be in order
	for (int j = 0; j < sampleCount; j++)
    {
		bool bFinished = true;
        for (i = 0; i < (sampleCount-1); i++)
	    {
	        float temp1 = vDepth[vSurfOrder[i]];
	        float temp2 = vDepth[vSurfOrder[i+1]];
    	    
	        if (temp2 < temp1)
	        {
	            // swap values
	            int tempIndex   = vSurfOrder[i];
	            vSurfOrder[i]   = vSurfOrder[i+1];
	            vSurfOrder[i+1] = tempIndex;
	            bFinished = false;
	        }
	    }
	    
	    if (bFinished)
            j = 8;
	}
	
	// Now, sum all colors in order from front to back. Apply alpha.
	bool bFoundFirstColor = false;
	vec4 summedColor = vec4(0.0, 0.0, 0.0, 0.0);
	for (i = (sampleCount-1); i >= 0; i--)
    {
		int surfIndex = vSurfOrder[i];
		if(vColor[surfIndex].a > 0.001)
		{
			if (bFoundFirstColor == false)
			{
				// apply 100% of the first color
				summedColor = vColor[surfIndex];
				bFoundFirstColor = true;
			}
			else
			{
				// apply color with alpha
				summedColor.rgb = (summedColor.rgb * (1 - vColor[surfIndex].a))     +
				                  (vColor[surfIndex].rgb * vColor[surfIndex].a);
			}
		}
    }
   
   oColor = summedColor;
   
    int surfIndex = 2;
    float val = vDepth[vSurfOrder[surfIndex]];
    //oColor = vec4(val, val, val, 1.0);
    //oColor = vec4(vColor[vSurfOrder[surfIndex]].rgb, 1.0);
    //oColor = vec4(vColor[0].rgb, 1.0);
    oColor.a = 1.0f;
}
#version 150
// msResolve.fs
// 

in vec2 vTexCoord;

uniform sampler2DMS origImage;
uniform int sampleCount;
out vec4 oColor;

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

    // Find both the weighted and unweighted colors
	vec4 vColor = vec4(0.0, 0.0, 0.0, 0.0);
	
	// First, get sample data
	for (int i = 0; i < sampleCount; i++)
	{
	    vColor += texelFetch(origImage, ivec2(tmp), i);
	}

    oColor = vColor / (sampleCount); 
    oColor.a = 1.0f;
}
#pragma comment(lib, "gltools.lib")
#include <stdio.h>
#include <iostream>

#include <GLTools.h>
#include <GLShaderManager.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

#pragma warning( disable : 4305 )

static GLfloat vLtBlue[] = { 0.00f, 0.00f, 1.00f, 0.90f };
static GLfloat vLtPink[] = { 0.40f, 0.00f, 0.20f, 0.50f };
static GLfloat vLtYellow[] = { 0.98f, 0.96f, 0.14f, 0.30f };
static GLfloat vLtMagenta[] = { 0.83f, 0.04f, 0.83f, 0.70f };
static GLfloat vLtGreen[] = { 0.05f, 0.98f, 0.14f, 0.30f };

static GLfloat vGrey[] = { 0.5f, 0.5f, 0.5f, 1.0f };

#define USER_OIT   1 
#define USER_BLEND 2

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


GLShaderManager		shaderManager;			// Shader Manager
GLMatrixStack		modelViewMatrix;		// Modelview Matrix
GLMatrixStack		projectionMatrix;		// Projection Matrix
GLFrustum			viewFrustum;			// View Frustum
GLGeometryTransform	transformPipeline;		// Geometry Transform Pipeline
GLFrame				cameraFrame;			// Camera frame

GLTriangleBatch		bckgrndCylBatch;
GLTriangleBatch		diskBatch;
GLBatch				glass1Batch;
GLBatch				glass2Batch;
GLBatch				glass3Batch;
GLBatch				glass4Batch;
GLBatch             screenQuad;
M3DMatrix44f        orthoMatrix;
GLfloat             worldAngle;

GLint               blendMode;
GLint               mode;

GLuint              msFBO;
GLuint              textures[2];
GLuint		    msTexture[1];
GLuint              depthTextureName;
GLuint              msResolve;
GLuint              oitResolve;
GLuint              flatBlendProg;

void DrawWorld();
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);
void GenerateOrtho2DMat(GLuint imageWidth, GLuint imageHeight);
void SetupResolveProg();
void SetupOITResolveProg();


///
// 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)
		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

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

	// Initialze Shader Manager
	shaderManager.InitializeStockShaders();
	glEnable(GL_DEPTH_TEST);

	gltMakeCylinder(bckgrndCylBatch, 4.0, 4.0, 5.2, 1024, 1);

	gltMakeDisk(diskBatch, 0.0, 1.5, 40, 10);

	glass1Batch.Begin(GL_TRIANGLE_FAN, 4, 1);
	glass1Batch.Vertex3f(-1.0f, -1.0f, 0.0f);
	glass1Batch.Vertex3f(1.0f, -1.0f, 0.0f);
	glass1Batch.Vertex3f(1.0f, 1.0f, 0.0f);
	glass1Batch.Vertex3f(-1.0f, 1.0f, 0.0f);
	glass1Batch.End();

	glass2Batch.Begin(GL_TRIANGLE_FAN, 4, 1);
	glass2Batch.Vertex3f(0.0f, 1.0f, 0.0f);
	glass2Batch.Vertex3f(1.0f, 0.0f, 0.0f);
	glass2Batch.Vertex3f(0.0f, -1.0f, 0.0f);
	glass2Batch.Vertex3f(-1.0f, 0.0f, 0.0f);
	glass2Batch.End();

	glass3Batch.Begin(GL_TRIANGLE_FAN, 3, 1);
	glass3Batch.Vertex3f(0.0f, 1.0f, 0.0f);
	glass3Batch.Vertex3f(1.0f, -1.0f, 0.0f);
	glass3Batch.Vertex3f(-1.0f, -1.0f, 0.0f);
	glass3Batch.End();

	glass4Batch.Begin(GL_TRIANGLE_FAN, 4, 1);
	glass4Batch.Vertex3f(-1.0f, 1.0f, 0.0f);
	glass4Batch.Vertex3f(1.0f, 0.5f, 0.0f);
	glass4Batch.Vertex3f(1.0f, -1.0f, 0.0f);
	glass4Batch.Vertex3f(-1.0f, -0.5f, 0.0f);
	glass4Batch.End();

	glGenTextures(2, textures);
	glBindTexture(GL_TEXTURE_2D, textures[0]);
	LoadBMPTexture("marble.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
	glBindTexture(GL_TEXTURE_2D, textures[1]);
	LoadBMPTexture("start_line.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

	// Create and bind an FBO
	glGenFramebuffers(1, &msFBO);
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, msFBO);

	// Create depth texture
	glGenTextures(1, &depthTextureName);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depthTextureName);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_DEPTH_COMPONENT24, screenWidth, screenHeight, GL_FALSE);

	// Setup HDR render texture
	glGenTextures(1, msTexture);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msTexture[0]);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGBA8, screenWidth, screenHeight, GL_FALSE);

	// Create and bind an FBO
	glGenFramebuffers(1, &msFBO);
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, msFBO);

	// Attach texture to first color attachment and the depth RBO
	glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, msTexture[0], 0);
	glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthTextureName, 0);

	// Reset framebuffer binding
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

	// Load oit resolve shader
	oitResolve = gltLoadShaderPairWithAttributes("basic.vs", "oitResolve.fs", 3,
		GLT_ATTRIBUTE_VERTEX, "vVertex",
		GLT_ATTRIBUTE_NORMAL, "vNormal",
		GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0");
	glBindFragDataLocation(oitResolve, 0, "oColor");
	glLinkProgram(oitResolve);

	// Load multisample resolve shader
	msResolve = gltLoadShaderPairWithAttributes("basic.vs", "msResolve.fs", 3,
		GLT_ATTRIBUTE_VERTEX, "vVertex",
		GLT_ATTRIBUTE_NORMAL, "vNormal",
		GLT_ATTRIBUTE_TEXTURE0, "vTexCoord0");

	glBindFragDataLocation(msResolve, 0, "oColor");
	glLinkProgram(msResolve);

	// Make sure all went well
	gltCheckErrors(oitResolve);
	gltCheckErrors(msResolve);

	int numMasks = 0;
	glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &numMasks);
}


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

	glDeleteTextures(1, msTexture);
	glDeleteTextures(1, &depthTextureName);
	glDeleteTextures(1, textures);

	// Cleanup FBOs
	glDeleteFramebuffers(1, &msFBO);

}


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

	GenerateOrtho2DMat(nWidth, nHeight);

	// update screen sizes
	screenWidth = nWidth;
	screenHeight = nHeight;

	// Resize textures
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depthTextureName);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_DEPTH_COMPONENT24, screenWidth, screenHeight, GL_FALSE);

	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msTexture[0]);
	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGBA8, screenWidth, screenHeight, GL_FALSE);
}


///
// Update the camera based on user input, toggle display modes
// 
void SpecialKeys(int key, int x, int y)
{
	static CStopWatch cameraTimer;
	float fTime = cameraTimer.GetElapsedSeconds();
	cameraTimer.Reset();

	float linear = fTime * 3.0f;
	float angular = fTime * float(m3dDegToRad(60.0f));

	if (key == GLUT_KEY_LEFT)
	{
		worldAngle += angular * 50;
		if (worldAngle > 360)
			worldAngle -= 360;
	}

	if (key == GLUT_KEY_RIGHT)
	{
		worldAngle -= angular * 50;
		if (worldAngle < 360)
			worldAngle += 360;
	}
}
void ProcessKeys(unsigned char key, int x, int y)
{
	if (key == 'o' || key == 'O')
		mode = USER_OIT;
	if (key == 'b' || key == 'B')
		mode = USER_BLEND;

	if (key == '1')
		blendMode = 1;
	if (key == '2')
		blendMode = 2;
	if (key == '3')
		blendMode = 3;
	if (key == '4')
		blendMode = 4;
	if (key == '5')
		blendMode = 5;
	if (key == '6')
		blendMode = 6;
	if (key == '7')
		blendMode = 7;
}



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


void SetupResolveProg()
{
	glUseProgram(msResolve);

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

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

	// Now setup the right textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msTexture[0]);
	glUniform1i(glGetUniformLocation(msResolve, "origImage"), 0);

	glUniform1i(glGetUniformLocation(msResolve, "sampleCount"), 8);

	glActiveTexture(GL_TEXTURE0);

	gltCheckErrors(msResolve);
}

void SetupOITResolveProg()
{
	glUseProgram(oitResolve);

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

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

	// Now setup the right textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msTexture[0]);
	glUniform1i(glGetUniformLocation(oitResolve, "origImage"), 0);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depthTextureName);
	glUniform1i(glGetUniformLocation(oitResolve, "origDepth"), 1);

	glUniform1f(glGetUniformLocation(oitResolve, "sampleCount"), 8);

	glActiveTexture(GL_TEXTURE0);
	gltCheckErrors(oitResolve);
}

///
// Draw the scene 
// 
void DrawWorld()
{
	modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);
	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(-0.3f, 0.f, 0.0f);
	modelViewMatrix.Scale(0.40, 0.8, 0.40);
	modelViewMatrix.Rotate(50.0, 0.0, 10.0, 0.0);
	glSampleMaski(0, 0x02);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtYellow);
	glass1Batch.Draw();
	modelViewMatrix.PopMatrix();

	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(0.4f, 0.0f, 0.0f);
	modelViewMatrix.Scale(0.5, 0.8, 1.0);
	modelViewMatrix.Rotate(-20.0, 0.0, 1.0, 0.0);
	glSampleMaski(0, 0x04);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtGreen);
	glass2Batch.Draw();
	modelViewMatrix.PopMatrix();

	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(1.0f, 0.0f, -0.6f);
	modelViewMatrix.Scale(0.3, 0.9, 1.0);
	modelViewMatrix.Rotate(-40.0, 0.0, 1.0, 0.0);
	glSampleMaski(0, 0x08);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtMagenta);
	glass3Batch.Draw();
	modelViewMatrix.PopMatrix();

	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(-0.8f, 0.0f, -0.60f);
	modelViewMatrix.Scale(0.6, 0.9, 0.40);
	modelViewMatrix.Rotate(60.0, 0.0, 1.0, 0.0);
	glSampleMaski(0, 0x10);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtBlue);
	glass4Batch.Draw();
	modelViewMatrix.PopMatrix();

	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(0.1f, 0.0f, 0.50f);
	modelViewMatrix.Scale(0.4, 0.9, 0.4);
	modelViewMatrix.Rotate(205.0, 0.0, 1.0, 0.0);
	glSampleMaski(0, 0x20);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vLtPink);
	glass4Batch.Draw();
	modelViewMatrix.PopMatrix();
}

///
// Render a frame. The owning framework is responsible for buffer swaps,
// flushes, etc.
void RenderScene(void)
{
	// Bind the FBO with multisample buffers
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, msFBO);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// User selected order independant transparency
	if (mode == USER_OIT)
	{
		// Use OIT, setup sample masks
		glSampleMaski(0, 0x01);
		glEnable(GL_SAMPLE_MASK);

		// Prevent depth test from culling covered surfaces
		glDepthFunc(GL_ALWAYS);
	}

	modelViewMatrix.PushMatrix();
	M3DMatrix44f mCamera;
	cameraFrame.GetCameraMatrix(mCamera);
	modelViewMatrix.MultMatrix(mCamera);

	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(0.0f, -0.4f, -4.0f);
	modelViewMatrix.Rotate(worldAngle, 0.0, 1.0, 0.0);

	// Draw the background and disk to the first sample
	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translate(0.0f, 3.0f, 0.0f);
	modelViewMatrix.Rotate(90.0, 1.0, 0.0, 0.0);
	modelViewMatrix.Rotate(90.0, 0.0, 0.0, 1.0);
	glBindTexture(GL_TEXTURE_2D, textures[1]);
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
	bckgrndCylBatch.Draw();
	modelViewMatrix.PopMatrix();

	modelViewMatrix.Translate(0.0f, -0.3f, 0.0f);
	modelViewMatrix.PushMatrix();
	modelViewMatrix.Rotate(90.0, 1.0, 0.0, 0.0);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGrey);
	diskBatch.Draw();
	modelViewMatrix.PopMatrix();
	modelViewMatrix.Translate(0.0f, 0.1f, 0.0f);

	// User selected blending
	if (mode == USER_BLEND)
	{
		// Setup blend state
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_BLEND);
		switch (blendMode)
		{
		case 1:
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			break;
		case 2:
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA);
			break;
		case 3:
			glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
			break;
		case 4:
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			break;
		case 5:
			glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
			break;
		case 6:
			glBlendFuncSeparate(GL_SRC_ALPHA, GL_DST_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			break;
		case 7:
			glBlendFuncSeparate(GL_SRC_COLOR, GL_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			break;
		default:
			glDisable(GL_BLEND);
		}
	}

	// Now draw the glass pieces
	DrawWorld();

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

	// Clean up all state 
	glDepthFunc(GL_LEQUAL);
	glDisable(GL_BLEND);
	glDisable(GL_SAMPLE_MASK);
	glSampleMaski(0, 0xffffffff);

	// Resolve multisample buffer
	projectionMatrix.PushMatrix();
	projectionMatrix.LoadMatrix(orthoMatrix);
	modelViewMatrix.PushMatrix();
	modelViewMatrix.LoadIdentity();
	// Setup and Clear the default framebuffer
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	glViewport(0, 0, screenWidth, screenHeight);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (mode == USER_OIT)
		SetupOITResolveProg();
	else if (mode == USER_BLEND)
		SetupResolveProg();

	// Draw a full-size quad to resolve the multisample surfaces
	screenQuad.Draw();
	modelViewMatrix.PopMatrix();
	projectionMatrix.PopMatrix();

	// Reset texture state
	glEnable(GL_DEPTH_TEST);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
	glActiveTexture(GL_TEXTURE1);
	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;
	msFBO = 0;
	depthTextureName = 0;
	worldAngle = 0;
	mode = 1;
	blendMode = 1;

	gltSetWorkingDirectory(argv[0]);

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

	glutCreateWindow("HDR Imaging");

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

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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值