#include "DeferredRenderer.h" #include "FrameBufferObject.h" #include "RenderState.h" #include "SampleGenerator.h" #include "Vector3.h" #include "Camera.h" #include "shaderenv.h" #include "Halton.h" #include "ShadowMapping.h" #include "Light.h" #include #include #ifdef _CRT_SET #define _CRTDBG_MAP_ALLOC #include #include // redefine new operator #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) #define new DEBUG_NEW #endif using namespace std; static void startil() { ilInit(); assert(ilGetError() == IL_NO_ERROR); } static void stopil() { ilShutDown(); assert(ilGetError() == IL_NO_ERROR); } namespace CHCDemoEngine { static CGprogram sCgSsaoProgram = NULL; static CGprogram sCgGiProgram = NULL; static CGprogram sCgDeferredProgram = NULL; static CGprogram sCgAntiAliasingProgram = NULL; static CGprogram sCgDeferredShadowProgram = NULL; static CGparameter sColorsTexCombineParam; static CGparameter sSsaoTexCombineParam; static CGparameter sColorsTexDeferredParam; static CGparameter sPositionsTexDeferredParam; static CGparameter sNormalsTexDeferredParam; static CGprogram sCgCombinedSsaoProgram = NULL; static CGprogram sCgCombinedIllumProgram = NULL; static CGparameter sColorsTexLogLumParam; static CGparameter sDownSampleOffsetParam; static CGparameter sFilterOffsetsParam; static CGparameter sFilterWeightsParam; static CGprogram sCgDownSampleProgram; static CGprogram sCgToneProgram; static CGprogram sCgLogLumProgram; ShaderContainer DeferredRenderer::sShaders; /////////////////////////////////////// static CGparameter sColorsTexParam; static CGparameter sNormalsTexParam; static CGparameter sOldModelViewProjMatrixParam; static CGparameter sModelViewProjMatrixParam; static CGparameter sEyePosParam; static CGparameter sEyePosShadowParam; static CGparameter sSamplesParam; static CGparameter sOldTexParam; static CGparameter sNoiseTexParam; static CGparameter sTemporalCoherenceParam; /////////////////////////////////////// static CGparameter sColorsTexGiParam; static CGparameter sNormalsTexGiParam; static CGparameter sOldModelViewProjMatrixGiParam; static CGparameter sModelViewProjMatrixGiParam; static CGparameter sSamplesGiParam; static CGparameter sOldSsaoTexGiParam; static CGparameter sOldIllumTexGiParam; static CGparameter sNoiseTexGiParam; static CGparameter sTemporalCoherenceGiParam; static CGparameter sColorsTexCombinedIllumParam; static CGparameter sSsaoTexCombinedIllumParam; static CGparameter sIllumTexCombinedIllumParam; static CGparameter sColorsTexCombinedSsaoParam; static CGparameter sSsaoTexCombinedSsaoParam; static CGparameter sTLParam; static CGparameter sTRParam; static CGparameter sBRParam; static CGparameter sBLParam; static CGparameter sTLGiParam; static CGparameter sTRGiParam; static CGparameter sBRGiParam; static CGparameter sBLGiParam; static CGparameter sEyePosGiParam; //////////// static CGparameter sColorsTexAntiAliasingParam; static CGparameter sNormalsTexAntiAliasingParam; static CGparameter sShadowMapParam; static CGparameter sPositionsTexShadowParam; static CGparameter sColorsTexShadowParam; static CGparameter sNormalsTexShadowParam; static CGparameter sShadowMatrixParam; static CGparameter sSampleWidthParam; static CGparameter sNoiseTexShadowParam; static CGparameter sSamplesShadowParam; static CGparameter sLightDirParam; static CGparameter sLightDirShadowParam; static CGparameter sImageKeyParam; static CGparameter sMiddleGreyParam; static CGparameter sWhiteLumParam; static CGparameter sColorsTexInitialParam; static CGparameter sColorsTexToneParam; static CGparameter sColorsTexDownSampleParam; //#define USE_3D_SSAO static GLuint noiseTex = 0; // ssao random spherical samples #ifdef USE_3D_SSAO static Sample2 samples3[NUM_SAMPLES]; #else static Sample2 samples2[NUM_SAMPLES]; #endif // number of pcf tabs Sample2 pcfSamples[NUM_PCF_TABS]; int DeferredRenderer::colorBufferIdx = 0; 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); } } static void ComputeSampleOffsets(float *sampleOffsets, int w, int h) { /* const float xoffs = 0.5f / w; const float yoffs = 0.5f / h; sampleOffsets[0] = xoffs; sampleOffsets[1] = yoffs; sampleOffsets[2] = xoffs; sampleOffsets[3] = -yoffs; sampleOffsets[4] = -xoffs; sampleOffsets[5] = -yoffs; sampleOffsets[6] = -xoffs; sampleOffsets[7] = yoffs; */ //const float xoffs = .5f / w; //const float yoffs = .5f / h; const float xoffs = 1.0f / w; const float yoffs = 1.0f / h; int idx = 0; for (int x = -1; x <= 1; ++ x) { for (int y = -1; y <= 1; ++ y) { sampleOffsets[idx + 0] = x * xoffs; sampleOffsets[idx + 1] = y * yoffs; idx += 2; } } } /** Generate poisson disc distributed sample points on the unit disc */ static void GenerateSamples(int sampling) { #ifdef USE_3D_SSAO SphericalSampleGenerator sph(NUM_SAMPLES, 1.0f); sph.Generate((float *)samples3); #else switch (sampling) { case DeferredRenderer::SAMPLING_POISSON: { PoissonDiscSampleGenerator2 poisson(NUM_SAMPLES, 1.0f); poisson.Generate((float *)samples2); } break; case DeferredRenderer::SAMPLING_QUADRATIC: { QuadraticDiscSampleGenerator2 g(NUM_SAMPLES, 1.0f); g.Generate((float *)samples2); } break; default: // SAMPLING_DEFAULT RandomSampleGenerator2 g(NUM_SAMPLES, 1.0f); g.Generate((float *)samples2); } #endif } static void CreateNoiseTex2D(int w, int h) { //GLubyte *randomNormals = new GLubyte[mWidth * mHeight * 3]; float *randomNormals = new float[w * h * 3]; static HaltonSequence halton; float r[2]; for (int i = 0; i < w * h * 3; i += 3) { #ifdef USE_3D_SSAO //halton.GetNext(2, r); r[0] = RandomValue(0, 1); r[1] = RandomValue(0, 1); const float theta = 2.0f * acos(sqrt(1.0f - r[0])); const float phi = 2.0f * M_PI * r[1]; randomNormals[i + 0] = sin(theta) * cos(phi); randomNormals[i + 1] = sin(theta) * sin(phi); randomNormals[i + 2] = cos(theta); #else // create random samples on a circle r[0] = RandomValue(0, 1); //halton.GetNext(1, r); const float theta = 2.0f * acos(sqrt(1.0f - r[0])); randomNormals[i + 0] = cos(theta); randomNormals[i + 1] = sin(theta); randomNormals[i + 2] = 0; #endif } 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_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"); } static void InitBuffer(FrameBufferObject *fbo, int index) { // read the second buffer, write to the first buffer fbo->Bind(); glDrawBuffers(1, mrt + index); //glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnd(); FrameBufferObject::Release(); } DeferredRenderer::DeferredRenderer(int w, int h, Camera *cam, float scaleFactor): mWidth(w), mHeight(h), mCamera(cam), mUseTemporalCoherence(true), mRegenerateSamples(true), mSamplingMethod(SAMPLING_POISSON), mShadingMethod(DEFAULT), mIllumFboIndex(0) { // create noise texture for ssao CreateNoiseTex2D(w, h); /////////// //-- the flip-flop fbos mIllumFbo = new FrameBufferObject(w / 2, h / 2, FrameBufferObject::DEPTH_NONE); mFBOs.push_back(mIllumFbo); for (int i = 0; i < 4; ++ i) { mIllumFbo->AddColorBuffer(ColorBufferObject::RGB_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); InitBuffer(mIllumFbo, i); } mDownSampleFbo = new FrameBufferObject(w / 2, h / 2, FrameBufferObject::DEPTH_NONE); mDownSampleFbo->AddColorBuffer(ColorBufferObject::RGBA_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); mDownSampleFbo->AddColorBuffer(ColorBufferObject::RGB_FLOAT_16, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); mFBOs.push_back(mDownSampleFbo); } DeferredRenderer::~DeferredRenderer() { CLEAR_CONTAINER(mFBOs); glDeleteTextures(1, &noiseTex); } void DeferredRenderer::SetUseTemporalCoherence(bool temporal) { mUseTemporalCoherence = temporal; } void DeferredRenderer::ReleaseCG() { CLEAR_CONTAINER(sShaders); } void DeferredRenderer::InitCG(CGcontext context) { ShaderProgram *pr; 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"); sLightDirParam = cgGetNamedParameter(sCgDeferredProgram, "lightDir"); pr = new ShaderProgram(sCgDeferredProgram); sShaders.push_back(pr); } else cerr << "deferred program failed to load" << endl; /////////////// sCgSsaoProgram = cgCreateProgramFromFile(context, CG_SOURCE, #ifdef USE_3D_SSAO "src/shaders/ssao3d.cg", #else "src/shaders/ssao.cg", #endif RenderState::sCgFragmentProfile, "main", NULL); if (sCgSsaoProgram != NULL) { cgGLLoadProgram(sCgSsaoProgram); sColorsTexParam = cgGetNamedParameter(sCgSsaoProgram, "colors"); sEyePosParam = cgGetNamedParameter(sCgSsaoProgram, "eyePos"); sNormalsTexParam = cgGetNamedParameter(sCgSsaoProgram, "normals"); sNoiseTexParam = cgGetNamedParameter(sCgSsaoProgram, "noiseTexture"); sOldModelViewProjMatrixParam = cgGetNamedParameter(sCgSsaoProgram, "oldModelViewProj"); sModelViewProjMatrixParam = cgGetNamedParameter(sCgSsaoProgram, "modelViewProj"); sTemporalCoherenceParam = cgGetNamedParameter(sCgSsaoProgram, "temporalCoherence"); sOldTexParam = cgGetNamedParameter(sCgSsaoProgram, "oldTex"); sSamplesParam = cgGetNamedParameter(sCgSsaoProgram, "samples"); sTLParam = cgGetNamedParameter(sCgSsaoProgram, "tl"); sTRParam = cgGetNamedParameter(sCgSsaoProgram, "tr"); sBRParam = cgGetNamedParameter(sCgSsaoProgram, "br"); sBLParam = cgGetNamedParameter(sCgSsaoProgram, "bl"); pr = new ShaderProgram(sCgSsaoProgram); sShaders.push_back(pr); } 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 sColorsTexGiParam = cgGetNamedParameter(sCgGiProgram, "colors"); sNormalsTexGiParam = cgGetNamedParameter(sCgGiProgram, "normals"); sOldModelViewProjMatrixGiParam = cgGetNamedParameter(sCgGiProgram, "oldModelViewProj"); sModelViewProjMatrixGiParam = cgGetNamedParameter(sCgGiProgram, "modelViewProj"); sTemporalCoherenceGiParam = cgGetNamedParameter(sCgGiProgram, "temporalCoherence"); sNoiseTexGiParam = cgGetNamedParameter(sCgGiProgram, "noiseTexture"); sSamplesGiParam = cgGetNamedParameter(sCgGiProgram, "samples"); sOldSsaoTexGiParam = cgGetNamedParameter(sCgGiProgram, "oldSsaoTex"); sOldIllumTexGiParam = cgGetNamedParameter(sCgGiProgram, "oldIllumTex"); sTLGiParam = cgGetNamedParameter(sCgGiProgram, "tl"); sTRGiParam = cgGetNamedParameter(sCgGiProgram, "tr"); sBRGiParam = cgGetNamedParameter(sCgGiProgram, "br"); sBLGiParam = cgGetNamedParameter(sCgGiProgram, "bl"); sEyePosGiParam = cgGetNamedParameter(sCgGiProgram, "eyePos"); pr = new ShaderProgram(sCgGiProgram); sShaders.push_back(pr); } else cerr << "globillum program failed to load" << endl; sCgCombinedIllumProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/globillum.cg", RenderState::sCgFragmentProfile, "combine", NULL); if (sCgCombinedIllumProgram != NULL) { cgGLLoadProgram(sCgCombinedIllumProgram); sColorsTexCombinedIllumParam = cgGetNamedParameter(sCgCombinedIllumProgram, "colors"); sSsaoTexCombinedIllumParam = cgGetNamedParameter(sCgCombinedIllumProgram, "ssaoTex"); sIllumTexCombinedIllumParam = cgGetNamedParameter(sCgCombinedIllumProgram, "illumTex"); pr = new ShaderProgram(sCgCombinedIllumProgram); sShaders.push_back(pr); } else cerr << "combined illum program failed to load" << endl; sCgCombinedSsaoProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/ssao.cg", RenderState::sCgFragmentProfile, "combine", NULL); if (sCgCombinedSsaoProgram != NULL) { cgGLLoadProgram(sCgCombinedSsaoProgram); sColorsTexCombinedSsaoParam = cgGetNamedParameter(sCgCombinedSsaoProgram, "colors"); sSsaoTexCombinedSsaoParam = cgGetNamedParameter(sCgCombinedSsaoProgram, "ssaoTex"); sFilterOffsetsParam = cgGetNamedParameter(sCgCombinedSsaoProgram, "filterOffs"); sFilterWeightsParam = cgGetNamedParameter(sCgCombinedSsaoProgram, "filterWeights"); pr = new ShaderProgram(sCgCombinedSsaoProgram); sShaders.push_back(pr); } else cerr << "combied illum 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"); pr = new ShaderProgram(sCgAntiAliasingProgram); sShaders.push_back(pr); } else cerr << "antialiasing program failed to load" << endl; sCgDeferredShadowProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/deferred.cg", RenderState::sCgFragmentProfile, "main_shadow", NULL); if (sCgDeferredShadowProgram != NULL) { cgGLLoadProgram(sCgDeferredShadowProgram); // we need size of texture for scaling sPositionsTexShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "positions"); sColorsTexShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "colors"); sNormalsTexShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "normals"); sShadowMapParam = cgGetNamedParameter(sCgDeferredShadowProgram, "shadowMap"); sSampleWidthParam = cgGetNamedParameter(sCgDeferredShadowProgram, "sampleWidth"); sShadowMatrixParam = cgGetNamedParameter(sCgDeferredShadowProgram, "shadowMatrix"); sNoiseTexShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "noiseTexture"); sSamplesShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "samples"); sLightDirShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "lightDir"); sEyePosShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "eyePos"); PoissonDiscSampleGenerator2 poisson(NUM_PCF_TABS, 1.0f); poisson.Generate((float *)pcfSamples); cgGLSetParameterArray2f(sSamplesShadowParam, 0, NUM_PCF_TABS, (const float *)pcfSamples); pr = new ShaderProgram(sCgDeferredShadowProgram); sShaders.push_back(pr); } else cerr << "deferred program failed to load" << endl; sCgLogLumProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/tonemap.cg", RenderState::sCgFragmentProfile, "CalcAvgLogLum", NULL); if (sCgLogLumProgram != NULL) { cgGLLoadProgram(sCgLogLumProgram); sColorsTexLogLumParam = cgGetNamedParameter(sCgLogLumProgram, "colors"); pr = new ShaderProgram(sCgLogLumProgram); sShaders.push_back(pr); } else cerr << "avg loglum program failed to load" << endl; sCgToneProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/tonemap.cg", RenderState::sCgFragmentProfile, "ToneMap", NULL); if (sCgToneProgram != NULL) { cgGLLoadProgram(sCgToneProgram); sImageKeyParam = cgGetNamedParameter(sCgToneProgram, "imageKey"); sMiddleGreyParam = cgGetNamedParameter(sCgToneProgram, "middleGrey"); sWhiteLumParam = cgGetNamedParameter(sCgToneProgram, "whiteLum"); sColorsTexToneParam = cgGetNamedParameter(sCgToneProgram, "colors"); pr = new ShaderProgram(sCgToneProgram); sShaders.push_back(pr); } else cerr << "tone program failed to load" << endl; sCgDownSampleProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/tonemap.cg", RenderState::sCgFragmentProfile, "DownSample", NULL); if (sCgDownSampleProgram != NULL) { cgGLLoadProgram(sCgDownSampleProgram); // we need size of texture for scaling sColorsTexDownSampleParam = cgGetNamedParameter(sCgDownSampleProgram, "colors"); sDownSampleOffsetParam = cgGetNamedParameter(sCgDownSampleProgram, "downSampleOffs"); pr = new ShaderProgram(sCgDownSampleProgram); sShaders.push_back(pr); } else cerr << "downsample program failed to load" << endl; PrintGLerror("init"); } void DeferredRenderer::Render(FrameBufferObject *fbo, const Matrix4x4 &oldProjViewMatrix, const Matrix4x4 &projViewMatrix, float tempCohFactor, DirectionalLight *light, bool useToneMapping, ShadowMap *shadowMap ) { // 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 mIllumFboIndex = 2 - mIllumFboIndex; cgGLEnableProfile(RenderState::sCgFragmentProfile); glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, mWidth, mHeight); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); const float offs = 0.5f; glOrtho(-offs, offs, -offs, offs, 0, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); if (shadowMap) FirstPassShadow(fbo, light, shadowMap); else FirstPass(fbo, light); switch (mShadingMethod) { case SSAO: // downsample fbo buffers for colors, normals DownSample(fbo, colorBufferIdx, mDownSampleFbo, 0); DownSample(fbo, 1, mDownSampleFbo, 1); ComputeSsao(fbo, tempCohFactor, oldProjViewMatrix, projViewMatrix); CombineSsao(fbo); break; case GI: // downsample fbo buffers for colors, normals DownSample(fbo, colorBufferIdx, mDownSampleFbo, 0); DownSample(fbo, 1, mDownSampleFbo, 1); ComputeGlobIllum(fbo, tempCohFactor, projViewMatrix, oldProjViewMatrix); CombineIllum(fbo); break; default: // DEFAULT // do nothing: standard deferred shading break; } if (useToneMapping) { float imageKey, whiteLum, middleGrey; ComputeToneParameters(fbo, light, imageKey, whiteLum, middleGrey); ToneMap(fbo, imageKey, whiteLum, middleGrey); } AntiAliasing(fbo, light); glEnable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); FrameBufferObject::Release(); cgGLDisableProfile(RenderState::sCgFragmentProfile); } void DeferredRenderer::ComputeSsao(FrameBufferObject *fbo, float tempCohFactor, const Matrix4x4 &oldProjViewMatrix, const Matrix4x4 &projViewMatrix ) { #ifdef USE_3D_SSAO // bias from [-1, 1] to [0, 1] static Matrix4x4 biasMatrix(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f); Matrix4x4 m = projViewMatrix * biasMatrix; cgGLSetMatrixParameterfc(sModelViewProjMatrixParam, (const float *)m.x); #else cgGLSetMatrixParameterfc(sModelViewProjMatrixParam, (const float *)projViewMatrix.x); #endif cgGLSetMatrixParameterfc(sOldModelViewProjMatrixParam, (const float *)oldProjViewMatrix.x); #if 0 GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(1)->GetTexture(); #else GLuint colorsTex = mDownSampleFbo->GetColorBuffer(0)->GetTexture(); GLuint normalsTex = mDownSampleFbo->GetColorBuffer(1)->GetTexture(); #endif GLuint oldTex = mIllumFbo->GetColorBuffer(2 - mIllumFboIndex)->GetTexture(); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, mIllumFbo->GetWidth(), mIllumFbo->GetHeight()); // read the second buffer, write to the first buffer mIllumFbo->Bind(); glDrawBuffers(1, mrt + mIllumFboIndex); cgGLBindProgram(sCgSsaoProgram); cgGLSetTextureParameter(sColorsTexParam, colorsTex); cgGLEnableTextureParameter(sColorsTexParam); cgGLSetTextureParameter(sNormalsTexParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexParam); cgGLSetTextureParameter(sNoiseTexParam, noiseTex); cgGLEnableTextureParameter(sNoiseTexParam); cgGLSetTextureParameter(sOldTexParam, oldTex); cgGLEnableTextureParameter(sOldTexParam); Vector3 pos = mCamera->GetPosition(); cgGLSetParameter3f(sEyePosParam, pos.x, pos.y, pos.z); cgGLSetParameter1f(sTemporalCoherenceParam, (mUseTemporalCoherence && !mRegenerateSamples) ? tempCohFactor : 0); if (mUseTemporalCoherence || mRegenerateSamples) { mRegenerateSamples = false; // 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(mSamplingMethod); #ifdef USE_3D_SSAO cgGLSetParameterArray3f(sSamplesParam, 0, NUM_SAMPLES, (const float *)samples3); #else cgGLSetParameterArray2f(sSamplesParam, 0, NUM_SAMPLES, (const float *)samples2); #endif } Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); cgGLSetParameter3f(sBLParam, bl.x, bl.y, bl.z); cgGLSetParameter3f(sBRParam, br.x, br.y, br.z); cgGLSetParameter3f(sTLParam, tl.x, tl.y, tl.z); cgGLSetParameter3f(sTRParam, tr.x, tr.y, tr.z); glBegin(GL_QUADS); // note: slightly larger texture could hide ambient occlusion error on border but costs resolution const float offs = 0.5f; glTexCoord2f(0, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, bl.x, bl.y, bl.z); glVertex3f(-offs, -offs, -0.5f); glTexCoord2f(1, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, br.x, br.y, br.z); glVertex3f( offs, -offs, -0.5f); glTexCoord2f(1, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tr.x, tr.y, tr.z); glVertex3f( offs, offs, -0.5f); glTexCoord2f(0, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tl.x, tl.y, tl.z); glVertex3f(-offs, offs, -0.5f); //cout<ComputePoints(ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr); bl = Normalize(nbl - fbl); br = Normalize(nbr - fbr); tl = Normalize(ntl - ftl); tr = Normalize(ntr - ftr); } 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 DeferredRenderer::AntiAliasing(FrameBufferObject *fbo, DirectionalLight *light) { FrameBufferObject::Release(); ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); cgGLBindProgram(sCgAntiAliasingProgram); cgGLSetTextureParameter(sColorsTexAntiAliasingParam, colorsTex); cgGLEnableTextureParameter(sColorsTexAntiAliasingParam); cgGLSetTextureParameter(sNormalsTexAntiAliasingParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexAntiAliasingParam); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0f, 1.0f, 1.0f); 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 DeferredRenderer::FirstPass(FrameBufferObject *fbo, DirectionalLight *light) { GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(2)->GetTexture(); fbo->Bind(); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgDeferredProgram); cgGLSetTextureParameter(sColorsTexDeferredParam, colorsTex); cgGLEnableTextureParameter(sColorsTexDeferredParam); cgGLSetTextureParameter(sPositionsTexDeferredParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexDeferredParam); cgGLSetTextureParameter(sNormalsTexDeferredParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexDeferredParam); Vector3 lightDir = -light->GetDirection(); cgGLSetParameter3f(sLightDirParam, lightDir.x, lightDir.y, lightDir.z); Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); // note: slightly larger texture could hide ambient occlusion error on border but costs resolution const float offs = 0.5f; glBegin(GL_QUADS); glTexCoord2f(0, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, bl.x, bl.y, bl.z); glVertex3f(-offs, -offs, -0.5f); glTexCoord2f(1, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, br.x, br.y, br.z); glVertex3f( offs, -offs, -0.5f); glTexCoord2f(1, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tr.x, tr.y, tr.z); glVertex3f( offs, offs, -0.5f); glTexCoord2f(0, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tl.x, tl.y, tl.z); glVertex3f(-offs, offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexDeferredParam); cgGLDisableTextureParameter(sPositionsTexDeferredParam); cgGLDisableTextureParameter(sNormalsTexDeferredParam); PrintGLerror("deferred shading"); } void DeferredRenderer::ComputeGlobIllum(FrameBufferObject *fbo, float tempCohFactor, const Matrix4x4 &projViewMatrix, const Matrix4x4 &oldProjViewMatrix) { cgGLSetMatrixParameterfc(sOldModelViewProjMatrixGiParam, (const float *)oldProjViewMatrix.x); cgGLSetMatrixParameterfc(sModelViewProjMatrixGiParam, (const float *)projViewMatrix.x); #if 0 GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(1)->GetTexture(); #else GLuint colorsTex = mDownSampleFbo->GetColorBuffer(0)->GetTexture(); GLuint normalsTex = mDownSampleFbo->GetColorBuffer(1)->GetTexture(); #endif glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, mIllumFbo->GetWidth(), mIllumFbo->GetHeight()); // read the second buffer, write to the first buffer mIllumFbo->Bind(); glDrawBuffers(2, mrt + mIllumFboIndex); GLuint oldSsaoTex = mIllumFbo->GetColorBuffer(2 - mIllumFboIndex)->GetTexture(); GLuint oldIllumTex = mIllumFbo->GetColorBuffer(2 - mIllumFboIndex + 1)->GetTexture(); cgGLBindProgram(sCgGiProgram); 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(sTemporalCoherenceGiParam, (mUseTemporalCoherence && !mRegenerateSamples) ? tempCohFactor : 0); if (mUseTemporalCoherence || mRegenerateSamples) { mRegenerateSamples = false; // 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(mSamplingMethod); cgGLSetParameterArray2f(sSamplesGiParam, 0, NUM_SAMPLES, (const float *)samples2); } Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); const Vector3 pos = mCamera->GetPosition(); cgGLSetParameter3f(sEyePosGiParam, pos.x, pos.y, pos.z); cgGLSetParameter3f(sBLGiParam, bl.x, bl.y, bl.z); cgGLSetParameter3f(sBRGiParam, br.x, br.y, br.z); cgGLSetParameter3f(sTLGiParam, tl.x, tl.y, tl.z); cgGLSetParameter3f(sTRGiParam, tr.x, tr.y, tr.z); // note: slightly larger texture could hide ambient occlusion error on border but costs resolution const float offs = 0.5f; glBegin(GL_QUADS); glTexCoord2f(0, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, bl.x, bl.y, bl.z); glVertex3f(-offs, -offs, -0.5f); glTexCoord2f(1, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, br.x, br.y, br.z); glVertex3f( offs, -offs, -0.5f); glTexCoord2f(1, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tr.x, tr.y, tr.z); glVertex3f( offs, offs, -0.5f); glTexCoord2f(0, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tl.x, tl.y, tl.z); glVertex3f(-offs, offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexGiParam); cgGLDisableTextureParameter(sNormalsTexGiParam); cgGLDisableTextureParameter(sNoiseTexGiParam); cgGLDisableTextureParameter(sOldSsaoTexGiParam); cgGLDisableTextureParameter(sOldIllumTexGiParam); glPopAttrib(); PrintGLerror("globillum first pass"); } void DeferredRenderer::CombineIllum(FrameBufferObject *fbo) { GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint ssaoTex = mIllumFbo->GetColorBuffer(mIllumFboIndex)->GetTexture(); GLuint illumTex = mIllumFbo->GetColorBuffer(mIllumFboIndex + 1)->GetTexture(); fbo->Bind(); // overwrite old color texture colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgCombinedIllumProgram); cgGLSetTextureParameter(sColorsTexCombinedIllumParam, colorsTex); cgGLEnableTextureParameter(sColorsTexCombinedIllumParam); cgGLSetTextureParameter(sSsaoTexCombinedIllumParam, ssaoTex); cgGLEnableTextureParameter(sSsaoTexCombinedIllumParam); cgGLSetTextureParameter(sIllumTexCombinedIllumParam, illumTex); cgGLEnableTextureParameter(sIllumTexCombinedIllumParam); 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(sColorsTexCombinedIllumParam); cgGLDisableTextureParameter(sSsaoTexCombinedIllumParam); cgGLDisableTextureParameter(sIllumTexCombinedIllumParam); PrintGLerror("combine"); } static float GaussianDistribution(float x, float y, float rho) { float g = 1.0f / sqrtf(2.0f * M_PI * rho * rho); g *= expf( -(x*x + y*y) / (2.0f * rho * rho)); return g; } void DeferredRenderer::CombineSsao(FrameBufferObject *fbo) { fbo->Bind(); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(2)->GetTexture(); GLuint ssaoTex = mIllumFbo->GetColorBuffer(mIllumFboIndex)->GetTexture(); // overwrite old color texture colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgCombinedSsaoProgram); float filterOffsets[NUM_DOWNSAMPLES * 2]; float filterWeights[NUM_DOWNSAMPLES]; PoissonDiscSampleGenerator2 poisson(NUM_DOWNSAMPLES, 1.0f); poisson.Generate((float *)filterOffsets); const float xoffs = 2.0f / fbo->GetWidth(); const float yoffs = 2.0f / fbo->GetHeight(); for (int i = 0; i < NUM_DOWNSAMPLES; ++ i) { float x = filterOffsets[2 * i + 0]; float y = filterOffsets[2 * i + 1]; filterOffsets[2 * i + 0] *= xoffs; filterOffsets[2 * i + 1] *= yoffs; filterWeights[i] = GaussianDistribution(x, y, 1.0f); } //ComputeSampleOffsets(filterOffsets, fbo->GetWidth(), fbo->GetHeight()); cgGLSetParameterArray2f(sFilterOffsetsParam, 0, NUM_DOWNSAMPLES, (const float *)filterOffsets); cgGLSetParameterArray1f(sFilterWeightsParam, 0, NUM_DOWNSAMPLES, (const float *)filterWeights); cgGLSetTextureParameter(sColorsTexCombinedSsaoParam, colorsTex); cgGLEnableTextureParameter(sColorsTexCombinedSsaoParam); cgGLSetTextureParameter(sSsaoTexCombinedSsaoParam, ssaoTex); cgGLEnableTextureParameter(sSsaoTexCombinedSsaoParam); 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(sColorsTexCombinedSsaoParam); cgGLDisableTextureParameter(sSsaoTexCombinedSsaoParam); PrintGLerror("combine ssao"); } void DeferredRenderer::FirstPassShadow(FrameBufferObject *fbo, DirectionalLight *light, ShadowMap *shadowMap) { fbo->Bind(); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(2)->GetTexture(); GLuint shadowTex = shadowMap->GetDepthTexture(); Matrix4x4 shadowMatrix; shadowMap->GetTextureMatrix(shadowMatrix); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgDeferredShadowProgram); cgGLSetTextureParameter(sColorsTexShadowParam, colorsTex); cgGLEnableTextureParameter(sColorsTexShadowParam); cgGLSetTextureParameter(sPositionsTexShadowParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexShadowParam); cgGLSetTextureParameter(sNormalsTexShadowParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexShadowParam); cgGLSetTextureParameter(sShadowMapParam, shadowTex); cgGLEnableTextureParameter(sShadowMapParam); cgGLSetParameter1f(sSampleWidthParam, 2.0f / shadowMap->GetSize()); cgGLSetMatrixParameterfc(sShadowMatrixParam, (const float *)shadowMatrix.x); cgGLSetTextureParameter(sNoiseTexShadowParam, noiseTex); cgGLEnableTextureParameter(sNoiseTexShadowParam); Vector3 lightDir = -light->GetDirection(); cgGLSetParameter3f(sLightDirShadowParam, lightDir.x, lightDir.y, lightDir.z); Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); const Vector3 pos = mCamera->GetPosition(); cgGLSetParameter3f(sEyePosShadowParam, pos.x, pos.y, pos.z); // note: slightly larger texture could hide ambient occlusion error on border but costs resolution const float offs = 0.5f; glBegin(GL_QUADS); glTexCoord2f(0, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, bl.x, bl.y, bl.z); glVertex3f(-offs, -offs, -0.5f); glTexCoord2f(1, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, br.x, br.y, br.z); glVertex3f( offs, -offs, -0.5f); glTexCoord2f(1, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tr.x, tr.y, tr.z); glVertex3f( offs, offs, -0.5f); glTexCoord2f(0, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tl.x, tl.y, tl.z); glVertex3f(-offs, offs, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexShadowParam); cgGLDisableTextureParameter(sPositionsTexShadowParam); cgGLDisableTextureParameter(sNormalsTexShadowParam); cgGLDisableTextureParameter(sShadowMapParam); cgGLDisableTextureParameter(sNoiseTexShadowParam); PrintGLerror("deferred shading + shadows"); } void DeferredRenderer::SetSamplingMethod(SAMPLING_METHOD s) { if (s != mSamplingMethod) { mSamplingMethod = s; mRegenerateSamples = true; } } void DeferredRenderer::SetShadingMethod(SHADING_METHOD s) { if (s != mShadingMethod) { mShadingMethod = s; mRegenerateSamples = true; } } void DeferredRenderer::ComputeToneParameters(FrameBufferObject *fbo, DirectionalLight *light, float &imageKey, float &whiteLum, float &middleGrey) { // hack: estimate value where sky burns out whiteLum = log(WHITE_LUMINANCE); //////////////////// //-- linear interpolate brightness key depending on the current sun position const float minKey = 0.09f; const float maxKey = 0.36f; const float lightIntensity = DotProd(-light->GetDirection(), Vector3::UNIT_Z()); middleGrey = lightIntensity * maxKey + (1.0f - lightIntensity) * minKey; ////////// //-- compute avg loglum ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); fbo->Bind(); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgLogLumProgram); cgGLSetTextureParameter(sColorsTexLogLumParam, colorsTex); cgGLEnableTextureParameter(sColorsTexLogLumParam); 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(sColorsTexLogLumParam); PrintGLerror("ToneMapParams"); /////////////////// //-- compute avg loglum in scene using mipmapping glBindTexture(GL_TEXTURE_2D, fbo->GetColorBuffer(colorBufferIdx)->GetTexture()); glGenerateMipmapEXT(GL_TEXTURE_2D); } static void ExportData(float *data, int w, int h) { startil(); cout << "w: " << w << " h: " << h << endl; ILstring filename = ILstring("downsample2.jpg"); ilRegisterType(IL_FLOAT); const int depth = 1; const int bpp = 4; if (!ilTexImage(w, h, depth, bpp, IL_RGBA, IL_FLOAT, data)) { cerr << "IL error " << ilGetError() << endl; stopil(); return; } if (!ilSaveImage(filename)) { cerr << "TGA write error " << ilGetError() << endl; } stopil(); // cout << "exported buffer" << endl; } void DeferredRenderer::DownSample(FrameBufferObject *fbo, int bufferIdx, FrameBufferObject *downSampleFbo, int downSampleBufferIdx) { ColorBufferObject *colorBuffer = fbo->GetColorBuffer(bufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, downSampleFbo->GetWidth(), downSampleFbo->GetHeight()); cgGLBindProgram(sCgDownSampleProgram); cgGLSetTextureParameter(sColorsTexDownSampleParam, colorsTex); cgGLEnableTextureParameter(sColorsTexDownSampleParam); float downSampleOffsets[NUM_DOWNSAMPLES * 2]; ComputeSampleOffsets(downSampleOffsets, fbo->GetWidth(), fbo->GetHeight()); cgGLSetParameterArray2f(sDownSampleOffsetParam, 0, NUM_DOWNSAMPLES, (const float *)downSampleOffsets); mDownSampleFbo->Bind(); glDrawBuffers(1, mrt + downSampleBufferIdx); cgGLBindProgram(sCgDownSampleProgram); 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(sColorsTexDownSampleParam); /*float *data = (float *)mDownSampleFbo->GetColorBuffer(0)->ReadTexture(); ExportData(data, mWidth / 2, mHeight / 2); delete [] data;*/ glPopAttrib(); PrintGLerror("downsample"); } void DeferredRenderer::ToneMap(FrameBufferObject *fbo, float imageKey, float whiteLum, float middleGrey) { ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); fbo->Bind(); #if 1 colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLBindProgram(sCgToneProgram); cgGLSetTextureParameter(sColorsTexToneParam, colorsTex); cgGLEnableTextureParameter(sColorsTexToneParam); cgGLSetParameter1f(sImageKeyParam, imageKey); cgGLSetParameter1f(sWhiteLumParam, whiteLum); cgGLSetParameter1f(sMiddleGreyParam, middleGrey); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); const float offs = 0.5f; 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(); #endif cgGLDisableTextureParameter(sColorsTexToneParam); PrintGLerror("ToneMap"); } } // namespace