#include "SsaoShader.h" #include "FrameBufferObject.h" #include "RenderState.h" #include "SampleGenerator.h" #include "Vector3.h" #include "Camera.h" using namespace std; static GLenum mymrt[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT}; namespace CHCDemoEngine { // number of ssao samples #define NUM_SAMPLES 10 static CGprogram sCgSsaoProgram = NULL; static CGprogram sCgGiProgram = NULL; static CGprogram sCgDeferredProgram = NULL; static CGprogram sCgAntiAliasingProgram = NULL; static CGprogram sCgCombineProgram = NULL; static CGparameter sColorsTexCombineParam; static CGparameter sSsaoTexCombineParam; static CGparameter sColorsTexDeferredParam; static CGparameter sPositionsTexDeferredParam; static CGparameter sNormalsTexDeferredParam; ///////////////////////////////////////7 static CGparameter sColorsTexParam; static CGparameter sPositionsTexParam; static CGparameter sNormalsTexParam; static CGparameter sOldModelViewProjMatrixParam; static CGparameter sMaxDepthParam; static CGparameter sSamplesParam; static CGparameter sOldTexParam; static CGparameter sNoiseTexParam; static CGparameter sNoiseMultiplierParam; static CGparameter sExpFactorParam; /////////////////////////////////////// static CGparameter sColorsTexGiParam; static CGparameter sPositionsTexGiParam; static CGparameter sNormalsTexGiParam; static CGparameter sOldModelViewProjMatrixGiParam; static CGparameter sMaxDepthGiParam; static CGparameter sSamplesGiParam; static CGparameter sOldSsaoTexGiParam; static CGparameter sOldIllumTexGiParam; static CGparameter sNoiseTexGiParam; static CGparameter sNoiseMultiplierGiParam; static CGparameter sExpFactorGiParam; //////////// static CGparameter sColorsTexAntiAliasingParam; static CGparameter sNormalsTexAntiAliasingParam; static GLuint noiseTex = 0; // ssao random spherical samples static Sample2 samples[NUM_SAMPLES]; static void PrintGLerror(char *msg) { GLenum errCode; const GLubyte *errStr; if ((errCode = glGetError()) != GL_NO_ERROR) { errStr = gluErrorString(errCode); fprintf(stderr,"OpenGL ERROR: %s: %s\n", errStr, msg); } } /** Generate poisson disc distributed sample points on the unit disc */ static void GenerateSamples() { static PoissonDiscSampleGenerator poisson(NUM_SAMPLES, 1.0f); poisson.Generate((Sample2 *)samples); } static void CreateNoiseTex2D(int w, int h) { // hack: should be able to recalc noise texture //if (noiseTex > 0) return; //GLubyte *randomNormals = new GLubyte[mWidth * mHeight * 3]; float *randomNormals = new float[w * h * 3]; for (int i = 0; i < w * h * 3; i += 3) { // create random samples on a circle const float rx = RandomValue(0, 1); const float theta = 2.0f * acos(sqrt(1.0f - rx)); //randomNormals[i + 0] = (GLubyte)((cos(theta) * 0.5f + 0.5f) * 255.0f); //randomNormals[i + 1] = (GLubyte)((sin(theta) * 0.5f + 0.5f) * 255.0f); randomNormals[i + 0] = cos(theta); randomNormals[i + 1] = sin(theta); randomNormals[i + 2] = 0; } glEnable(GL_TEXTURE_2D); glGenTextures(1, &noiseTex); glBindTexture(GL_TEXTURE_2D, noiseTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, randomNormals); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGB, GL_FLOAT, randomNormals); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); delete [] randomNormals; cout << "created noise texture" << endl; PrintGLerror("noisetexture"); } SsaoShader::SsaoShader(int w, int h, Camera *cam, float scaleFactor): mWidth(w), mHeight(h), mCamera(cam), mScaleFactor(scaleFactor), mUseTemporalCoherence(true), mUseGlobIllum(false) { // create noise texture for ssao CreateNoiseTex2D(w, h); /////////// //-- the flip-flop fbos mNewFbo = new FrameBufferObject(w, h, FrameBufferObject::DEPTH_NONE); mNewFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); mNewFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); mNewFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); mOldFbo = new FrameBufferObject(w, h, FrameBufferObject::DEPTH_NONE); mOldFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); mOldFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); mOldFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false); //mFbo = new FrameBufferObject(w, h, FrameBufferObject::DEPTH_NONE); //mFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false);*/ } SsaoShader::~SsaoShader() { if (sCgSsaoProgram) cgDestroyProgram(sCgSsaoProgram); if (sCgDeferredProgram) cgDestroyProgram(sCgDeferredProgram); if (sCgSsaoProgram) cgDestroyProgram(sCgSsaoProgram); if (sCgGiProgram) cgDestroyProgram(sCgGiProgram); if (sCgAntiAliasingProgram) cgDestroyProgram(sCgAntiAliasingProgram); DEL_PTR(mNewFbo); DEL_PTR(mOldFbo); //DEL_PTR(mFbo); glDeleteTextures(1, &noiseTex); } void SsaoShader::SetUseGlobIllum(bool useGlobIllum) { mUseGlobIllum = useGlobIllum; } void SsaoShader::SetUseTemporalCoherence(bool temporal) { mUseTemporalCoherence = temporal; } void SsaoShader::Init(CGcontext context) { sCgDeferredProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/deferred.cg", RenderState::sCgFragmentProfile, "main", NULL); if (sCgDeferredProgram != NULL) { cgGLLoadProgram(sCgDeferredProgram); // we need size of texture for scaling sPositionsTexDeferredParam = cgGetNamedParameter(sCgDeferredProgram, "positions"); sColorsTexDeferredParam = cgGetNamedParameter(sCgDeferredProgram, "colors"); sNormalsTexDeferredParam = cgGetNamedParameter(sCgDeferredProgram, "normals"); } else cerr << "deferred program failed to load" << endl; /////////////// sCgSsaoProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/ssao.cg", RenderState::sCgFragmentProfile, "main", NULL); if (sCgSsaoProgram != NULL) { cgGLLoadProgram(sCgSsaoProgram); // we need size of texture for scaling sPositionsTexParam = cgGetNamedParameter(sCgSsaoProgram, "positions"); sColorsTexParam = cgGetNamedParameter(sCgSsaoProgram, "colors"); sNormalsTexParam = cgGetNamedParameter(sCgSsaoProgram, "normals"); sNoiseTexParam = cgGetNamedParameter(sCgSsaoProgram, "noiseTexture"); sNoiseMultiplierParam = cgGetNamedParameter(sCgSsaoProgram, "noiseMultiplier"); sOldModelViewProjMatrixParam = cgGetNamedParameter(sCgSsaoProgram, "oldModelViewProj"); sMaxDepthParam = cgGetNamedParameter(sCgSsaoProgram, "maxDepth"); sExpFactorParam = cgGetNamedParameter(sCgSsaoProgram, "expFactor"); sSamplesParam = cgGetNamedParameter(sCgSsaoProgram, "samples"); sOldTexParam = cgGetNamedParameter(sCgSsaoProgram, "oldTex"); // generate samples for ssao kernel GenerateSamples(); cgGLSetParameterArray2f(sSamplesParam, 0, NUM_SAMPLES, (const float *)samples); cgGLSetParameter1f(sNoiseMultiplierParam, RandomValue(3.0f, 17.0f)); } else cerr << "ssao program failed to load" << endl; sCgGiProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/globillum.cg", RenderState::sCgFragmentProfile, "main", NULL); if (sCgGiProgram != NULL) { cgGLLoadProgram(sCgGiProgram); // we need size of texture for scaling sPositionsTexGiParam = cgGetNamedParameter(sCgGiProgram, "positions"); sColorsTexGiParam = cgGetNamedParameter(sCgGiProgram, "colors"); sNormalsTexGiParam = cgGetNamedParameter(sCgGiProgram, "normals"); sNoiseTexGiParam = cgGetNamedParameter(sCgGiProgram, "noiseTexture"); sNoiseMultiplierGiParam = cgGetNamedParameter(sCgGiProgram, "noiseMultiplier"); sOldModelViewProjMatrixGiParam = cgGetNamedParameter(sCgGiProgram, "oldModelViewProj"); sMaxDepthGiParam = cgGetNamedParameter(sCgGiProgram, "maxDepth"); sExpFactorGiParam = cgGetNamedParameter(sCgGiProgram, "expFactor"); sSamplesGiParam = cgGetNamedParameter(sCgGiProgram, "samples"); sOldSsaoTexGiParam = cgGetNamedParameter(sCgGiProgram, "oldSsaoTex"); sOldIllumTexGiParam = cgGetNamedParameter(sCgGiProgram, "oldIllumTex"); // generate samples for ssao kernel GenerateSamples(); cgGLSetParameterArray2f(sSamplesGiParam, 0, NUM_SAMPLES, (const float *)samples); cgGLSetParameter1f(sNoiseMultiplierGiParam, RandomValue(3.0f, 17.0f)); } else cerr << "globillum program failed to load" << endl; sCgAntiAliasingProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/antialiasing.cg", RenderState::sCgFragmentProfile, "main", NULL); if (sCgAntiAliasingProgram != NULL) { cgGLLoadProgram(sCgAntiAliasingProgram); sColorsTexAntiAliasingParam = cgGetNamedParameter(sCgAntiAliasingProgram, "colors"); sNormalsTexAntiAliasingParam = cgGetNamedParameter(sCgAntiAliasingProgram, "normals"); } else cerr << "antialiasing program failed to load" << endl; PrintGLerror("init"); } void SsaoShader::Render(FrameBufferObject *fbo, const Matrix4x4 &oldProjViewMatrix, float expFactor) { // switch roles of old and new fbo // the algorihm uses two input fbos, where the one // contais the color buffer from the last frame, // the other one will be written swap(mNewFbo, mOldFbo); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, mWidth, mHeight); FrameBufferObject::Release(); cgGLEnableProfile(RenderState::sCgFragmentProfile); glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); const float offs = 0.5f; glOrtho(-offs, offs, -offs, offs, 0, 1); FirstPass(fbo); if (!mUseGlobIllum) ComputeSsao(fbo, expFactor, oldProjViewMatrix); else ComputeGlobIllum(fbo, expFactor, oldProjViewMatrix); AntiAliasing(fbo); glEnable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); cgGLDisableProfile(RenderState::sCgFragmentProfile); } void SsaoShader::ComputeSsao(FrameBufferObject *fbo, float expFactor, const Matrix4x4 &oldProjViewMatrix ) { cgGLSetMatrixParameterfc(sOldModelViewProjMatrixParam, (const float *)oldProjViewMatrix.x); // GLuint colorsTex = mFbo->GetColorBuffer(0)->GetTexture(); GLuint colorsTex = fbo->GetColorBuffer(3)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); if (1) { // generate mip map levels for position texture glBindTexture(GL_TEXTURE_2D, positionsTex); glGenerateMipmapEXT(GL_TEXTURE_2D); } // read the second buffer, write to the first buffer mNewFbo->Bind(); glDrawBuffers(2, mymrt); GLuint oldTex = mOldFbo->GetColorBuffer(0)->GetTexture(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgSsaoProgram); cgGLSetTextureParameter(sPositionsTexParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexParam); cgGLSetTextureParameter(sColorsTexParam, colorsTex); cgGLEnableTextureParameter(sColorsTexParam); cgGLSetTextureParameter(sNormalsTexParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexParam); cgGLSetTextureParameter(sNoiseTexParam, noiseTex); cgGLEnableTextureParameter(sNoiseTexParam); cgGLSetTextureParameter(sOldTexParam, oldTex); cgGLEnableTextureParameter(sOldTexParam); cgGLSetParameter1f(sMaxDepthParam, mScaleFactor); if (mUseTemporalCoherence) { cgGLSetParameter1f(sNoiseMultiplierParam, RandomValue(3.0f, 17.0f)); cgGLSetParameter1f(sExpFactorParam, expFactor); // q: should we generate new samples or only rotate the old ones? // in the first case, the sample patterns look nicer, but the kernel // needs longer to converge GenerateSamples(); cgGLSetParameterArray2f(sSamplesParam, 0, NUM_SAMPLES, (const float *)samples); } else { cgGLSetParameter1f(sExpFactorParam, 1.0f); } Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); // note: slightly larger texture hides ambient occlusion error on border but costs resolution //const float new_offs = 0.55f; const float new_offs = 0.5f; glColor3f(bl.x, bl.y, bl.z); glTexCoord2f(0, 0); glVertex3f(-new_offs, -new_offs, -0.5f); glColor3f(br.x, br.y, br.z); glTexCoord2f(1, 0); glVertex3f( new_offs, -new_offs, -0.5f); glColor3f(tr.x, tr.y, tr.z); glTexCoord2f(1, 1); glVertex3f( new_offs, new_offs, -0.5f); glColor3f(tl.x, tl.y, tl.z); glTexCoord2f(0, 1); glVertex3f(-new_offs, new_offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexParam); cgGLDisableTextureParameter(sPositionsTexParam); cgGLDisableTextureParameter(sNormalsTexParam); cgGLDisableTextureParameter(sNoiseTexParam); cgGLDisableTextureParameter(sOldTexParam); FrameBufferObject::Release(); PrintGLerror("ssao first pass"); } void SsaoShader::ComputeViewVectors(Vector3 &tl, Vector3 &tr, Vector3 &bl, Vector3 &br) { Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr; mCamera->ComputePoints(ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr); #if 1 // matT: debug this!! bl = -Normalize(nbl - fbl); br = -Normalize(nbr - fbr); tl = -Normalize(ntl - ftl); tr = -Normalize(ntr - ftr); #else // just take camera direction bl = -Normalize(mCamera->GetDirection()); br = -Normalize(mCamera->GetDirection()); tl = -Normalize(mCamera->GetDirection()); tr = -Normalize(mCamera->GetDirection()); #endif // normalize to 0 .. 1 bl = bl * 0.5f + 0.5f; br = br * 0.5f + 0.5f; tl = tl * 0.5f + 0.5f; tr = tr * 0.5f + 0.5f; } static void SetVertex(float x, float y, float x_offs, float y_offs) { glMultiTexCoord2fARB(GL_TEXTURE0_ARB, x, y); // center glMultiTexCoord2fARB(GL_TEXTURE1_ARB, x - x_offs, y + y_offs); // left top glMultiTexCoord2fARB(GL_TEXTURE2_ARB, x + x_offs, y - y_offs); // right bottom glMultiTexCoord2fARB(GL_TEXTURE3_ARB, x + x_offs, y + y_offs); // right top glMultiTexCoord2fARB(GL_TEXTURE4_ARB, x - x_offs, y - y_offs); // left bottom glMultiTexCoord4fARB(GL_TEXTURE5_ARB, x - x_offs, y, x + x_offs, y); // left right glMultiTexCoord4fARB(GL_TEXTURE6_ARB, x, y + y_offs, x, y - y_offs); // top bottom glVertex3f(x - 0.5f, y - 0.5f, -0.5f); } void SsaoShader::AntiAliasing(FrameBufferObject *fbo) { GLuint colorsTex = mNewFbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgAntiAliasingProgram); cgGLSetTextureParameter(sColorsTexAntiAliasingParam, colorsTex); cgGLEnableTextureParameter(sColorsTexAntiAliasingParam); cgGLSetTextureParameter(sNormalsTexAntiAliasingParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexAntiAliasingParam); glColor3f(1.0f, 1.0f, 1.0f); float offs2 = 0.5f; glBegin(GL_QUADS); // the neighbouring texels float x_offs = 1.0f / mWidth; float y_offs = 1.0f / mHeight; SetVertex(0, 0, x_offs, y_offs); SetVertex(1, 0, x_offs, y_offs); SetVertex(1, 1, x_offs, y_offs); SetVertex(0, 1, x_offs, y_offs); glEnd(); cgGLDisableTextureParameter(sColorsTexAntiAliasingParam); cgGLDisableTextureParameter(sNormalsTexAntiAliasingParam); PrintGLerror("antialiasing"); } void SsaoShader::FirstPass(FrameBufferObject *fbo) { GLuint colorsTex = fbo->GetColorBuffer(0)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); fbo->Bind(); glDrawBuffers(1, mymrt + 3); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgDeferredProgram); cgGLSetTextureParameter(sColorsTexDeferredParam, colorsTex); cgGLEnableTextureParameter(sColorsTexDeferredParam); cgGLSetTextureParameter(sPositionsTexDeferredParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexDeferredParam); cgGLSetTextureParameter(sNormalsTexDeferredParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexDeferredParam); glColor3f(1.0f, 1.0f, 1.0f); const float offs = 0.5f; glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-offs, -offs, -0.5f); glTexCoord2f(1, 0); glVertex3f( offs, -offs, -0.5f); glTexCoord2f(1, 1); glVertex3f( offs, offs, -0.5f); glTexCoord2f(0, 1); glVertex3f(-offs, offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexDeferredParam); cgGLDisableTextureParameter(sPositionsTexDeferredParam); cgGLDisableTextureParameter(sNormalsTexDeferredParam); cgGLDisableProfile(RenderState::sCgFragmentProfile); FrameBufferObject::Release(); PrintGLerror("deferred shading"); } void SsaoShader::ComputeGlobIllum(FrameBufferObject *fbo, float expFactor, const Matrix4x4 &oldProjViewMatrix ) { cgGLSetMatrixParameterfc(sOldModelViewProjMatrixGiParam, (const float *)oldProjViewMatrix.x); //GLuint colorsTex = mFbo->GetColorBuffer(0)->GetTexture(); GLuint colorsTex = fbo->GetColorBuffer(3)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); if (1) { // generate mip map levels for position texture glBindTexture(GL_TEXTURE_2D, positionsTex); glGenerateMipmapEXT(GL_TEXTURE_2D); // generate mip map levels for position texture glBindTexture(GL_TEXTURE_2D, colorsTex); glGenerateMipmapEXT(GL_TEXTURE_2D); } // read the second buffer, write to the first buffer mNewFbo->Bind(); glDrawBuffers(3, mymrt); GLuint oldSsaoTex = mOldFbo->GetColorBuffer(0)->GetTexture(); GLuint oldIllumTex = mOldFbo->GetColorBuffer(2)->GetTexture(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgGiProgram); cgGLSetTextureParameter(sPositionsTexGiParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexGiParam); cgGLSetTextureParameter(sColorsTexGiParam, colorsTex); cgGLEnableTextureParameter(sColorsTexGiParam); cgGLSetTextureParameter(sNormalsTexGiParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexGiParam); cgGLSetTextureParameter(sNoiseTexGiParam, noiseTex); cgGLEnableTextureParameter(sNoiseTexGiParam); cgGLSetTextureParameter(sOldSsaoTexGiParam, oldSsaoTex); cgGLEnableTextureParameter(sOldSsaoTexGiParam); cgGLSetTextureParameter(sOldIllumTexGiParam, oldIllumTex); cgGLEnableTextureParameter(sOldIllumTexGiParam); cgGLSetParameter1f(sMaxDepthGiParam, mScaleFactor); if (mUseTemporalCoherence) { cgGLSetParameter1f(sNoiseMultiplierGiParam, RandomValue(3.0f, 17.0f)); cgGLSetParameter1f(sExpFactorGiParam, expFactor); // q: should we generate new samples or only rotate the old ones? // in the first case, the sample patterns look nicer, but the kernel // needs longer to converge GenerateSamples(); cgGLSetParameterArray2f(sSamplesGiParam, 0, NUM_SAMPLES, (const float *)samples); } else { cgGLSetParameter1f(sExpFactorGiParam, 1.0f); } Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); // note: slightly larger texture hides ambient occlusion error on border but costs resolution //const float new_offs = 0.55f; const float new_offs = 0.5f; glColor3f(bl.x, bl.y, bl.z); glTexCoord2f(0, 0); glVertex3f(-new_offs, -new_offs, -0.5f); glColor3f(br.x, br.y, br.z); glTexCoord2f(1, 0); glVertex3f( new_offs, -new_offs, -0.5f); glColor3f(tr.x, tr.y, tr.z); glTexCoord2f(1, 1); glVertex3f( new_offs, new_offs, -0.5f); glColor3f(tl.x, tl.y, tl.z); glTexCoord2f(0, 1); glVertex3f(-new_offs, new_offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexGiParam); cgGLDisableTextureParameter(sPositionsTexGiParam); cgGLDisableTextureParameter(sNormalsTexGiParam); cgGLDisableTextureParameter(sNoiseTexGiParam); cgGLDisableTextureParameter(sOldSsaoTexGiParam); cgGLDisableTextureParameter(sOldIllumTexGiParam); FrameBufferObject::Release(); PrintGLerror("globillum first pass"); } } // namespace