#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" using namespace std; 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 CGprogram sCgInitialIntensityProgram; static CGprogram sCgDownSampleProgram; static CGprogram sCgToneProgram; static CGprogram sCgLogLumProgram; /////////////////////////////////////// static CGparameter sColorsTexParam; static CGparameter sPositionsTexParam; static CGparameter sNormalsTexParam; static CGparameter sOldModelViewProjMatrixParam; static CGparameter sModelViewProjMatrixParam; static CGparameter sMaxDepthParam; static CGparameter sEyePosParam; static CGparameter sSamplesParam; static CGparameter sOldTexParam; static CGparameter sNoiseTexParam; static CGparameter sTemporalCoherenceParam; /////////////////////////////////////// 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 sTemporalCoherenceGiParam; static CGparameter sColorsTexCombinedIllumParam; static CGparameter sSsaoTexCombinedIllumParam; static CGparameter sIllumTexCombinedIllumParam; static CGparameter sColorsTexCombinedSsaoParam; static CGparameter sSsaoTexCombinedSsaoParam; static CGparameter sPositionsTexCombinedSsaoParam; 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 sMaxDepthShadowParam; 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 sIntensityTexDownSampleParam; //#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); } } /** 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_RGB8, w, h, 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"); } DeferredRenderer::DeferredRenderer(int w, int h, Camera *cam, float scaleFactor): mWidth(w), mHeight(h), mCamera(cam), mScaleFactor(scaleFactor), mUseTemporalCoherence(true), mRegenerateSamples(true), mSamplingMethod(SAMPLING_POISSON), mShadingMethod(DEFAULT), mFboIndex(0) { // create noise texture for ssao CreateNoiseTex2D(w, h); /////////// //-- the flip-flop fbos mFbo = new FrameBufferObject(w, h, FrameBufferObject::DEPTH_NONE); mFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); mFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); mFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); mFbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR); } DeferredRenderer::~DeferredRenderer() { if (sCgSsaoProgram) cgDestroyProgram(sCgSsaoProgram); if (sCgDeferredProgram) cgDestroyProgram(sCgDeferredProgram); if (sCgSsaoProgram) cgDestroyProgram(sCgSsaoProgram); if (sCgGiProgram) cgDestroyProgram(sCgGiProgram); if (sCgAntiAliasingProgram) cgDestroyProgram(sCgAntiAliasingProgram); DEL_PTR(mFbo); glDeleteTextures(1, &noiseTex); } void DeferredRenderer::SetUseTemporalCoherence(bool temporal) { mUseTemporalCoherence = temporal; } void DeferredRenderer::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"); sLightDirParam = cgGetNamedParameter(sCgDeferredProgram, "lightDir"); } 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); sPositionsTexParam = cgGetNamedParameter(sCgSsaoProgram, "positions"); sColorsTexParam = cgGetNamedParameter(sCgSsaoProgram, "colors"); sEyePosParam = cgGetNamedParameter(sCgSsaoProgram, "eyePos"); sNormalsTexParam = cgGetNamedParameter(sCgSsaoProgram, "normals"); sNoiseTexParam = cgGetNamedParameter(sCgSsaoProgram, "noiseTexture"); sOldModelViewProjMatrixParam = cgGetNamedParameter(sCgSsaoProgram, "oldModelViewProj"); sModelViewProjMatrixParam = cgGetNamedParameter(sCgSsaoProgram, "mymodelViewProj"); sMaxDepthParam = cgGetNamedParameter(sCgSsaoProgram, "maxDepth"); 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"); } 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"); sOldModelViewProjMatrixGiParam = cgGetNamedParameter(sCgGiProgram, "oldModelViewProj"); sMaxDepthGiParam = cgGetNamedParameter(sCgGiProgram, "maxDepth"); 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"); } 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"); } 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"); sPositionsTexCombinedSsaoParam = cgGetNamedParameter(sCgCombinedSsaoProgram, "positions"); } 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"); } 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"); sMaxDepthShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "maxDepth"); sSampleWidthParam = cgGetNamedParameter(sCgDeferredShadowProgram, "sampleWidth"); sShadowMatrixParam = cgGetNamedParameter(sCgDeferredShadowProgram, "shadowMatrix"); sNoiseTexShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "noiseTexture"); sSamplesShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "samples"); sLightDirShadowParam = cgGetNamedParameter(sCgDeferredShadowProgram, "lightDir"); PoissonDiscSampleGenerator2 poisson(NUM_PCF_TABS, 1.0f); poisson.Generate((float *)pcfSamples); cgGLSetParameterArray2f(sSamplesShadowParam, 0, NUM_PCF_TABS, (const float *)pcfSamples); } 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"); } 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"); } else cerr << "tone program failed to load" << endl; /* sCgInitialIntensityProgram = cgCreateProgramFromFile(context, CG_SOURCE, "src/shaders/tonemap.cg", RenderState::sCgFragmentProfile, "GreyScaleDownSample", NULL); if (sCgInitialIntensityProgram != NULL) { cgGLLoadProgram(sCgInitialIntensityProgram); // we need size of texture for scaling sColorsTexInitialParam = cgGetNamedParameter(sCgInitialIntensityProgram, "colors"); } else cerr << "intensity 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 mFboIndex = 2 - mFboIndex; FrameBufferObject::Release(); cgGLEnableProfile(RenderState::sCgFragmentProfile); glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); 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: ComputeSsao(fbo, tempCohFactor, oldProjViewMatrix, projViewMatrix); CombineSsao(fbo); break; case GI: ComputeGlobIllum(fbo, tempCohFactor, 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, light, imageKey, whiteLum, middleGrey); } AntiAliasing(fbo, light); glEnable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); 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); #endif cgGLSetMatrixParameterfc(sOldModelViewProjMatrixParam, (const float *)oldProjViewMatrix.x); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); // generate mip map levels of position in order to improve texture lookup performance //glBindTexture(GL_TEXTURE_2D, positionsTex); glGenerateMipmapEXT(GL_TEXTURE_2D); // read the second buffer, write to the first buffer mFbo->Bind(); glDrawBuffers(1, mrt + mFboIndex); GLuint oldTex = mFbo->GetColorBuffer(2 - mFboIndex)->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); Vector3 pos = mCamera->GetPosition() / mScaleFactor; 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); glEnd(); cgGLDisableTextureParameter(sColorsTexParam); cgGLDisableTextureParameter(sPositionsTexParam); cgGLDisableTextureParameter(sNormalsTexParam); cgGLDisableTextureParameter(sNoiseTexParam); cgGLDisableTextureParameter(sOldTexParam); FrameBufferObject::Release(); PrintGLerror("ssao first pass"); } void DeferredRenderer::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); 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) { ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); GLuint colorsTex = colorBuffer->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); 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 positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); fbo->Bind(); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); 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); Vector3 lightDir = -light->GetDirection(); cgGLSetParameter3f(sLightDirParam, lightDir.x, lightDir.y, lightDir.z); 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 DeferredRenderer::ComputeGlobIllum(FrameBufferObject *fbo, float tempCohFactor, const Matrix4x4 &oldProjViewMatrix) { cgGLSetMatrixParameterfc(sOldModelViewProjMatrixGiParam, (const float *)oldProjViewMatrix.x); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); // 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 mFbo->Bind(); glDrawBuffers(2, mrt + mFboIndex); GLuint oldSsaoTex = mFbo->GetColorBuffer(2 - mFboIndex)->GetTexture(); GLuint oldIllumTex = mFbo->GetColorBuffer(2 - mFboIndex + 1)->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); 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); #ifdef USE_3D_SSAO cgGLSetParameterArray3f(sSamplesGiParam, 0, NUM_SAMPLES, (const float *)samples3); #else cgGLSetParameterArray2f(sSamplesGiParam, 0, NUM_SAMPLES, (const float *)samples2); #endif } Vector3 tl, tr, bl, br; ComputeViewVectors(tl, tr, bl, br); const Vector3 pos = mCamera->GetPosition() / mScaleFactor; 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); 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; glTexCoord2f(0, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, bl.x, bl.y, bl.z); glVertex3f(-new_offs, -new_offs, -0.5f); glTexCoord2f(1, 0); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, br.x, br.y, br.z); glVertex3f( new_offs, -new_offs, -0.5f); glTexCoord2f(1, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tr.x, tr.y, tr.z); glVertex3f( new_offs, new_offs, -0.5f); glTexCoord2f(0, 1); glMultiTexCoord3fARB(GL_TEXTURE1_ARB, tl.x, tl.y, tl.z); 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"); } void DeferredRenderer::CombineIllum(FrameBufferObject *fbo) { GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint ssaoTex = mFbo->GetColorBuffer(mFboIndex)->GetTexture(); GLuint illumTex = mFbo->GetColorBuffer(mFboIndex + 1)->GetTexture(); fbo->Bind(); // overwrite old color texture colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgCombinedIllumProgram); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 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); cgGLDisableProfile(RenderState::sCgFragmentProfile); FrameBufferObject::Release(); PrintGLerror("combine"); } void DeferredRenderer::CombineSsao(FrameBufferObject *fbo) { fbo->Bind(); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint ssaoTex = mFbo->GetColorBuffer(mFboIndex)->GetTexture(); // overwrite old color texture colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgCombinedSsaoProgram); cgGLSetTextureParameter(sColorsTexCombinedSsaoParam, colorsTex); cgGLEnableTextureParameter(sColorsTexCombinedSsaoParam); cgGLSetTextureParameter(sSsaoTexCombinedSsaoParam, ssaoTex); cgGLEnableTextureParameter(sSsaoTexCombinedSsaoParam); cgGLSetTextureParameter(sPositionsTexCombinedSsaoParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexCombinedSsaoParam); 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); cgGLDisableTextureParameter(sPositionsTexCombinedSsaoParam); cgGLDisableProfile(RenderState::sCgFragmentProfile); FrameBufferObject::Release(); PrintGLerror("combine ssao"); } void DeferredRenderer::FirstPassShadow(FrameBufferObject *fbo, DirectionalLight *light, ShadowMap *shadowMap) { fbo->Bind(); GLuint colorsTex = fbo->GetColorBuffer(colorBufferIdx)->GetTexture(); GLuint positionsTex = fbo->GetColorBuffer(1)->GetTexture(); GLuint normalsTex = fbo->GetColorBuffer(2)->GetTexture(); GLuint shadowTex = shadowMap->GetDepthTexture(); Matrix4x4 shadowMatrix; shadowMap->GetTextureMatrix(shadowMatrix); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLBindProgram(sCgDeferredShadowProgram); cgGLSetTextureParameter(sColorsTexShadowParam, colorsTex); cgGLEnableTextureParameter(sColorsTexShadowParam); cgGLSetTextureParameter(sPositionsTexShadowParam, positionsTex); cgGLEnableTextureParameter(sPositionsTexShadowParam); cgGLSetTextureParameter(sNormalsTexShadowParam, normalsTex); cgGLEnableTextureParameter(sNormalsTexShadowParam); cgGLSetTextureParameter(sShadowMapParam, shadowTex); cgGLEnableTextureParameter(sShadowMapParam); cgGLSetParameter1f(sMaxDepthShadowParam, mScaleFactor); 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); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); float offs2 = 0.5f; glTexCoord2f(0, 0); glVertex3f(-offs2, -offs2, -0.5f); glTexCoord2f(1, 0); glVertex3f( offs2, -offs2, -0.5f); glTexCoord2f(1, 1); glVertex3f( offs2, offs2, -0.5f); glTexCoord2f(0, 1); glVertex3f(-offs2, offs2, -0.5f); glEnd(); cgGLDisableTextureParameter(sColorsTexShadowParam); cgGLDisableTextureParameter(sPositionsTexShadowParam); cgGLDisableTextureParameter(sNormalsTexShadowParam); cgGLDisableTextureParameter(sShadowMapParam); cgGLDisableTextureParameter(sNoiseTexShadowParam); FrameBufferObject::Release(); 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(1e4f); //////////////////// //-- linear interpolate brightness key depending on the current sun position const float minKey = 0.09f; const float maxKey = 0.5f; const float lightIntensity = DotProd(-light->GetDirection(), Vector3::UNIT_Z()); middleGrey = lightIntensity * maxKey + (1.0f - lightIntensity) * minKey; #if 1 ////////// //-- compute avg loglum ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); fbo->Bind(); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); 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); FrameBufferObject::Release(); PrintGLerror("ToneMapParams"); #endif /////////////////// //-- compute avg loglum in scene using mipmapping glBindTexture(GL_TEXTURE_2D, fbo->GetColorBuffer(colorBufferIdx)->GetTexture()); glGenerateMipmapEXT(GL_TEXTURE_2D); } void DeferredRenderer::DownSample(FrameBufferObject *fbo) { GLuint intensityTex=0; cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(sCgDownSampleProgram); cgGLSetTextureParameter(sIntensityTexDownSampleParam, intensityTex); cgGLEnableTextureParameter(sIntensityTexDownSampleParam); } void DeferredRenderer::ToneMap(FrameBufferObject *fbo, DirectionalLight *light, float imageKey, float whiteLum, float middleGrey) { ColorBufferObject *colorBuffer = fbo->GetColorBuffer(colorBufferIdx); fbo->Bind(); colorBufferIdx = 3 - colorBufferIdx; glDrawBuffers(1, mrt + colorBufferIdx); GLuint colorsTex = colorBuffer->GetTexture(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLEnableProfile(RenderState::sCgFragmentProfile); 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); // the neighbouring texels const float x_offs = 1.0f / mWidth; const 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(sColorsTexToneParam); FrameBufferObject::Release(); PrintGLerror("ToneMap"); } } // namespace