// occquery.cpp : Defines the entry point for the console application. // #include "glInterface.h" #include #include #include "common.h" #include "RenderTraverser.h" #include "SceneEntity.h" #include "Vector3.h" #include "Matrix4x4.h" #include "ResourceManager.h" #include "Bvh.h" #include "Camera.h" #include "Geometry.h" #include "BvhLoader.h" #include "FrustumCullingTraverser.h" #include "StopAndWaitTraverser.h" #include "CHCTraverser.h" #include "CHCPlusPlusTraverser.h" #include "Visualization.h" #include "RenderState.h" #include "Timer/PerfTimer.h" #include "SceneQuery.h" #include "RenderQueue.h" #include "Material.h" #include #include #include "glfont2.h" #include "PerformanceGraph.h" #include "Environment.h" #include "Halton.h" #include "Transform3.h" #include "SampleGenerator.h" #include "FrameBufferObject.h" #include "SsaoShader.h" #include "DeferredShader.h" using namespace std; using namespace CHCDemoEngine; static Environment env; ///////////// //-- fbos FrameBufferObject *fbo; bool isFirstTexture = true; GLuint fontTex; /// the renderable scene geometry SceneEntityContainer sceneEntities; // traverses and renders the hierarchy RenderTraverser *traverser = NULL; /// the hierarchy Bvh *bvh = NULL; /// handles scene loading ResourceManager *loader = NULL; /// the scene camera Camera *camera = NULL; /// the scene camera Camera *visCamera = NULL; /// the visualization Visualization *visualization = NULL; /// the current render state RenderState state; /// the rendering algorithm int renderMode = RenderTraverser::CHCPLUSPLUS; // eye near plane distance float nearDist = 0.2f; /// the field of view float fov = 50.0f; /// the pixel threshold where a node is still considered invisible int threshold; int assumedVisibleFrames = 10; int maxBatchSize = 50; int trianglesPerVirtualLeaf = INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES; SceneQuery *sceneQuery = NULL; RenderQueue *renderQueue = NULL; /// these values get scaled with the frame rate static float keyForwardMotion = 30.0f; static float keyRotation = 1.5f; /// elapsed time in milliseconds double elapsedTime = 1000.0f; double algTime = 1000.0f; static int winWidth = 1024; static int winHeight = 768; static float winAspectRatio = 1.0f; double accumulatedTime = 1000; float fps = 1e3f; float myfar = 0; glfont::GLFont myfont; // rendertexture static int texWidth = 1024; static int texHeight = 768; //static int texWidth = 2048; //static int texHeight = 2048; int renderedObjects = 0; int renderedNodes = 0; int renderedTriangles = 0; int issuedQueries = 0; int traversedNodes = 0; int frustumCulledNodes = 0; int queryCulledNodes = 0; int stateChanges = 0; int numBatches = 0; bool showHelp = false; bool showStatistics = false; bool showOptions = false; bool showBoundingVolumes = false; bool visMode = false; // mouse navigation state int xEyeBegin = 0; int yEyeBegin = 0; int yMotionBegin = 0; int verticalMotionBegin = 0; int horizontalMotionBegin = 0; bool useOptimization = false; bool useTightBounds = true; bool useRenderQueue = true; bool useMultiQueries = true; bool flyMode = true; SceneEntityContainer skyGeometry; bool leftKeyPressed = false; bool rightKeyPressed = false; bool upKeyPressed = false; bool downKeyPressed = false; bool descendKeyPressed = false; bool ascendKeyPressed = false; bool useSsao = false; static float ssaoExpFactor = 0.1f; bool showAlgorithmTime = false; GLubyte *randomNormals = NULL; PerfTimer frameTimer, algTimer; int renderType = RenderState::FIXED; PerformanceGraph *perfGraph = NULL; bool useFullScreen = false; static Matrix4x4 matProjectionView = IdentityMatrix(); // function forward declarations void InitExtensions(); void DisplayVisualization(); void InitGLstate(); void InitRenderTexture(); void InitCg(); void CleanUp(); void SetupEyeView(); void UpdateEyeMtx(); void SetupLighting(); void DisplayStats(); void Output(int x, int y, const char *string); void DrawHelpMessage(); void RenderSky(); void RenderVisibleObjects(); void Begin2D(); void End2D(); void KeyBoard(unsigned char c, int x, int y); void DrawStatistics(); void Display(); void Special(int c, int x, int y); void KeyUp(unsigned char c, int x, int y); void SpecialKeyUp(int c, int x, int y); void Reshape(int w, int h); void Mouse(int button, int state, int x, int y); void LeftMotion(int x, int y); void RightMotion(int x, int y); void MiddleMotion(int x, int y); void CalcDecimalPoint(string &str, int d); void ResetTraverser(); void KeyHorizontalMotion(float shift); void KeyVerticalMotion(float shift); void PlaceViewer(const Vector3 &oldPos); inline float KeyRotationAngle() { return keyRotation * elapsedTime * 1e-3f; } inline float KeyShift() { return keyForwardMotion * elapsedTime * 1e-3f; } void InitFBO(); SsaoShader *ssaoShader = NULL; DeferredShader *deferredShader = NULL; GLenum mrt[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT}; ///////// //-- cg stuff static CGcontext sCgContext = NULL; static CGprogram sCgMrtVertexProgram = NULL; static CGparameter sModelViewProjMatrixParam; static CGparameter sMaxDepthParam; static CGparameter sMaxDepthParamTex; static Matrix4x4 oldViewProjMatrix; static void cgErrorCallback() { CGerror lastError = cgGetError(); if(lastError) { printf("%s\n\n", cgGetErrorString(lastError)); printf("%s\n", cgGetLastListing(sCgContext)); printf("Cg error, exiting...\n"); exit(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); } } int main(int argc, char* argv[]) { int returnCode = 0; Vector3 camPos(.0f, .0f, .0f); Vector3 camDir(.0f, 1.0f, .0f); cout << "=== reading environment file === " << endl; string envFileName = "default.env"; if (!env.Read(envFileName)) { cerr << "loading environment " << envFileName << " failed!" << endl; } else { env.GetIntParam(string("assumedVisibleFrames"), assumedVisibleFrames); env.GetIntParam(string("maxBatchSize"), maxBatchSize); env.GetIntParam(string("trianglesPerVirtualLeaf"), trianglesPerVirtualLeaf); env.GetFloatParam(string("keyForwardMotion"), keyForwardMotion); env.GetFloatParam(string("keyRotation"), keyRotation); env.GetIntParam(string("winWidth"), winWidth); env.GetIntParam(string("winHeight"), winHeight); env.GetBoolParam(string("useFullScreen"), useFullScreen); env.GetFloatParam(string("expFactor"), ssaoExpFactor); env.GetVectorParam(string("camPosition"), camPos); env.GetVectorParam(string("camDirection"), camDir); //env.GetStringParam(string("modelPath"), model_path); //env.GetIntParam(string("numSssaoSamples"), numSsaoSamples); cout << "assumedVisibleFrames: " << assumedVisibleFrames << endl; cout << "maxBatchSize: " << maxBatchSize << endl; cout << "trianglesPerVirtualLeaf: " << trianglesPerVirtualLeaf << endl; cout << "keyForwardMotion: " << keyForwardMotion << endl; cout << "keyRotation: " << keyRotation << endl; cout << "winWidth: " << winWidth << endl; cout << "winHeight: " << winHeight << endl; cout << "useFullScreen: " << useFullScreen << endl; cout << "camPosition: " << camPos << endl; cout << "expFactor: " << ssaoExpFactor << endl; //cout << "model path: " << model_path << endl; } /////////////////////////// camera = new Camera(winWidth, winHeight, fov); camera->SetNear(nearDist); camera->SetDirection(camDir); camera->SetPosition(camPos); visCamera = new Camera(winWidth, winHeight, fov); visCamera->SetNear(0.0f); visCamera->Yaw(.5 * M_PI); renderQueue = new RenderQueue(&state, camera); glutInitWindowSize(winWidth, winHeight); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE); //glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //glutInitDisplayString("samples=2"); if (!useFullScreen) { glutCreateWindow("FriendlyCulling"); } else { glutGameModeString( "1024x768:32@75" ); glutEnterGameMode(); } glutDisplayFunc(Display); glutKeyboardFunc(KeyBoard); glutSpecialFunc(Special); glutReshapeFunc(Reshape); glutMouseFunc(Mouse); glutIdleFunc(Display); glutKeyboardUpFunc(KeyUp); glutSpecialUpFunc(SpecialKeyUp); glutIgnoreKeyRepeat(true); // initialise gl graphics InitExtensions(); InitGLstate(); glEnable(GL_MULTISAMPLE_ARB); glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); InitFBO(); LeftMotion(0, 0); MiddleMotion(0, 0); perfGraph = new PerformanceGraph(1000); loader = new ResourceManager(); //const string filename("data/city/model/city.dem"); const string filename = string(model_path + "city.dem"); if (loader->Load(filename, sceneEntities)) cout << "scene " << filename << " loaded" << endl; else { cerr << "loading scene " << filename << " failed" << endl; CleanUp(); exit(0); } SceneEntityContainer dummy; const string envname = string(model_path + "env.dem"); if (loader->Load(envname, skyGeometry)) cout << "sky box " << filename << " loaded" << endl; else { cerr << "loading sky box " << filename << " failed" << endl; CleanUp(); exit(0); } const string bvh_filename = string(model_path + "city.bvh"); BvhLoader bvhLoader; bvh = bvhLoader.Load(bvh_filename, sceneEntities); if (!bvh) { cerr << "loading bvh " << bvh_filename << " failed" << endl; CleanUp(); exit(0); } // set far plane based on scene extent myfar = 10.0f * Magnitude(bvh->GetBox().Diagonal()); bvh->SetVirtualLeaves(trianglesPerVirtualLeaf); bvh->SetCamera(camera); InitCg(); SsaoShader::Init(sCgContext); DeferredShader::Init(sCgContext); ssaoShader = new SsaoShader(texWidth, texHeight, camera, myfar / 10.0f); deferredShader = new DeferredShader(texWidth, texHeight); // initialize the render traverser ResetTraverser(); visualization = new Visualization(bvh, camera, NULL, &state); sceneQuery = new SceneQuery(bvh->GetBox(), traverser); // frame time is restarted every frame frameTimer.Start(); // the rendering loop glutMainLoop(); // clean up CleanUp(); return 0; } void InitCg(void) { // Setup Cg cgSetErrorCallback(cgErrorCallback); // Create cgContext. sCgContext = cgCreateContext(); // get the best profile for this hardware RenderState::sCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); cgGLSetOptimalOptions(RenderState::sCgFragmentProfile); RenderState::sCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); cgGLSetOptimalOptions(RenderState::sCgVertexProfile); sCgMrtVertexProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, "src/shaders/mrt.cg", RenderState::sCgVertexProfile, "vtx", NULL); if (sCgMrtVertexProgram != NULL) { cgGLLoadProgram(sCgMrtVertexProgram); Transform3::sModelMatrixParam = cgGetNamedParameter(sCgMrtVertexProgram, "ModelMatrix"); sModelViewProjMatrixParam = cgGetNamedParameter(sCgMrtVertexProgram, "ModelViewProj"); } RenderState::sCgMrtFragmentTexProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, "src/shaders/mrt.cg", RenderState::sCgFragmentProfile, "fragtex", NULL); if (RenderState::sCgMrtFragmentTexProgram != NULL) { cgGLLoadProgram(RenderState::sCgMrtFragmentTexProgram); sMaxDepthParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "maxDepth"); Material::sDiffuseTexParam = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "diffuse"); Material::sAmbientTexParam = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "ambient"); cgGLSetParameter1f(sMaxDepthParamTex, 10.0f / myfar); Debug << "maxdepth: " << 10.0f / myfar << endl; } else cerr << "fragment tex program failed to load" << endl; RenderState::sCgMrtFragmentProgram = cgCreateProgramFromFile(sCgContext, CG_SOURCE, "src/shaders/mrt.cg", RenderState::sCgFragmentProfile, "frag", NULL); if (RenderState::sCgMrtFragmentProgram != NULL) { cgGLLoadProgram(RenderState::sCgMrtFragmentProgram); sMaxDepthParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "maxDepth"); Material::sDiffuseParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "diffuse"); Material::sAmbientParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "ambient"); cgGLSetParameter1f(sMaxDepthParam, 10.0f / myfar); } else cerr << "fragment program failed to load" << endl; PrintGLerror("init"); cout << "cg initialization successful" << endl; } void InitFBO() { // this fbo basicly stores the scene information we get from standard rendering of a frame // we store colors, normals, positions (for the ssao) fbo = new FrameBufferObject(texWidth, texHeight, FrameBufferObject::DEPTH_24); // the diffuse color buffer fbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_LINEAR, false, false); // the positions buffer fbo->AddColorBuffer(ColorBufferObject::BUFFER_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST, false, false); // the normals buffer fbo->AddColorBuffer(ColorBufferObject::BUFFER_UBYTE, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST, false, false); PrintGLerror("fbo"); } bool InitFont(void) { glEnable(GL_TEXTURE_2D); glGenTextures(1, &fontTex); glBindTexture(GL_TEXTURE_2D, fontTex); if (!myfont.Create("data/fonts/verdana.glf", fontTex)) return false; glDisable(GL_TEXTURE_2D); return true; } void InitGLstate() { glClearColor(0.5f, 0.5f, 0.8f, 0.0f); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT,1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); SetupLighting(); glColor3f(1.0f, 1.0f, 1.0f); glShadeModel(GL_SMOOTH); glMaterialf(GL_FRONT, GL_SHININESS, 64); glEnable(GL_NORMALIZE); //glEnable(GL_ALPHA_TEST); glDisable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.8f); glFrontFace(GL_CCW); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); //glDisable(GL_CULL_FACE); glDisable(GL_TEXTURE_2D); GLfloat ambientColor[] = {0.5, 0.5, 0.5, 1.0}; GLfloat diffuseColor[] = {1.0, 0.0, 0.0, 1.0}; GLfloat specularColor[] = {0.0, 0.0, 0.0, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor); glMaterialfv(GL_FRONT, GL_SPECULAR, specularColor); glDepthFunc(GL_LESS); if (!InitFont()) cerr << "font creation failed" << endl; else cout << "successfully created font" << endl; } void DrawHelpMessage() { const char *message[] = { "Help information", "", "'F1' - shows/dismisses this message", "'F2' - shows/hides bird eye view", "'F3' - shows/hides bounds (boxes or tight bounds)", "'F4', - shows/hides parameters", "'F5' - shows/hides statistics", "'F6', - toggles between fly/walkmode", "'F7', - cycles throw render modes", "'F8', - enables/disables ambient occlusion (only deferred)", "'F9', - shows pure algorithm render time (using glFinish)", "'SPACE' - cycles through occlusion culling algorithms", "", "'MOUSE LEFT' - turn left/right, move forward/backward", "'MOUSE RIGHT' - turn left/right, move forward/backward", "'MOUSE MIDDLE' - move up/down, left/right", "'CURSOR UP/DOWN' - move forward/backward", "'CURSOR LEFT/RIGHT' - turn left/right", "", "'-'/'+' - decreases/increases max batch size", "'1'/'2' - downward/upward motion", "'3'/'4' - decreases/increases triangles per virtual bvh leaf (sets bvh depth)", "'5'/'6' - decreases/increases assumed visible frames", "", "'R' - use render queue", "'B' - use tight bounds", "'M' - use multiqueries", "'O' - use CHC optimization (geometry queries for leaves)", 0, }; glColor4f(0.0f, 1.0f , 0.0f, 0.2f); // 20% green. glRecti(30, 30, winWidth - 30, winHeight - 30); glEnd(); glColor3f(1.0f, 1.0f, 1.0f); glEnable(GL_TEXTURE_2D); myfont.Begin(); int x = 40, y = 30; for(int i = 0; message[i] != 0; ++ i) { if(message[i][0] == '\0') { y += 15; } else { myfont.DrawString(message[i], x, winHeight - y); y += 25; } } glDisable(GL_TEXTURE_2D); } void ResetTraverser() { DEL_PTR(traverser); bvh->ResetNodeClassifications(); switch (renderMode) { case RenderTraverser::CULL_FRUSTUM: traverser = new FrustumCullingTraverser(); break; case RenderTraverser::STOP_AND_WAIT: traverser = new StopAndWaitTraverser(); break; case RenderTraverser::CHC: traverser = new CHCTraverser(); break; case RenderTraverser::CHCPLUSPLUS: traverser = new CHCPlusPlusTraverser(); break; default: traverser = new FrustumCullingTraverser(); } traverser->SetCamera(camera); traverser->SetHierarchy(bvh); traverser->SetRenderQueue(renderQueue); traverser->SetRenderState(&state); traverser->SetUseOptimization(useOptimization); traverser->SetUseRenderQueue(useRenderQueue); traverser->SetVisibilityThreshold(threshold); traverser->SetAssumedVisibleFrames(assumedVisibleFrames); traverser->SetMaxBatchSize(maxBatchSize); traverser->SetUseMultiQueries(useMultiQueries); traverser->SetUseTightBounds(useTightBounds); traverser->SetUseDepthPass(renderType == RenderState::DEPTH_PASS); traverser->SetRenderQueue(renderQueue); } void SetupLighting() { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0}; GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat lmodel_ambient[] = {0.3f, 0.3f, 0.3f, 1.0f}; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); //////////// //-- second light GLfloat ambient1[] = {0.2, 0.2, 0.2, 1.0}; GLfloat diffuse1[] = {1.0, 1.0, 1.0, 1.0}; //GLfloat diffuse1[] = {0.5, 0.5, 0.5, 1.0}; GLfloat specular1[] = {0.0, 0.0, 0.0, 1.0}; glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1); glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1); glLightfv(GL_LIGHT1, GL_SPECULAR, specular1); ////////////////////////////// GLfloat position[] = {0.8f, -1.0f, 0.7f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {-0.5f, 0.5f, 0.4f, 0.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SINGLE_COLOR_EXT); } void SetupEyeView() { Matrix4x4 matViewing, matProjection; // store matrix of last frame oldViewProjMatrix = matProjectionView; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, winAspectRatio, nearDist, myfar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); camera->SetupCameraView(); GLfloat position[] = {0.8f, -1.0f, 0.7f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {-0.5f, 0.5f, 0.4f, 0.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); camera->GetModelViewMatrix(matViewing); camera->GetProjectionMatrix(matProjection); matProjectionView = matViewing * matProjection; if (renderType == RenderState::DEFERRED) { // set modelview matrix for shaders cgGLSetStateMatrixParameter(sModelViewProjMatrixParam, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); static Matrix4x4 identity = IdentityMatrix(); cgGLSetMatrixParameterfc(Transform3::sModelMatrixParam, (const float *)identity.x); } } void KeyHorizontalMotion(float shift) { Vector3 hvec = camera->GetDirection(); hvec.z = 0; Vector3 pos = camera->GetPosition(); pos += hvec * shift; camera->SetPosition(pos); } void KeyVerticalMotion(float shift) { Vector3 uvec = Vector3(0, 0, shift); Vector3 pos = camera->GetPosition(); pos += uvec; camera->SetPosition(pos); } // the main rendering loop void Display() { Vector3 oldPos = camera->GetPosition(); if (leftKeyPressed) camera->Pitch(KeyRotationAngle()); if (rightKeyPressed) camera->Pitch(-KeyRotationAngle()); if (upKeyPressed) KeyHorizontalMotion(KeyShift()); if (downKeyPressed) KeyHorizontalMotion(-KeyShift()); if (ascendKeyPressed) KeyVerticalMotion(KeyShift()); if (descendKeyPressed) KeyVerticalMotion(-KeyShift()); // place view on ground if (!flyMode) PlaceViewer(oldPos); if (showAlgorithmTime) { glFinish(); algTimer.Start(); } // render without shading switch (renderType) { case RenderState::FIXED: glEnable(GL_MULTISAMPLE_ARB); //glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); fbo->Release(); state.SetRenderType(RenderState::FIXED); glEnable(GL_LIGHTING); cgGLDisableProfile(RenderState::sCgFragmentProfile); cgGLDisableProfile(RenderState::sCgVertexProfile); glDrawBuffers(1, mrt); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); break; case RenderState::DEPTH_PASS: glEnable(GL_MULTISAMPLE_ARB); //glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); fbo->Release(); cgGLDisableProfile(RenderState::sCgFragmentProfile); cgGLDisableProfile(RenderState::sCgVertexProfile); state.SetRenderType(RenderState::DEPTH_PASS); // the scene is rendered withouth any shading glDisable(GL_LIGHTING); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDrawBuffers(1, mrt); break; case RenderState::DEFERRED: // multisampling not working with deferred shading //glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); glDisable(GL_MULTISAMPLE_ARB); state.SetRenderType(RenderState::DEFERRED); fbo->Bind(); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0, 0, texWidth, texHeight); cgGLEnableProfile(RenderState::sCgFragmentProfile); cgGLBindProgram(RenderState::sCgMrtFragmentProgram); cgGLEnableProfile(RenderState::sCgVertexProfile); cgGLBindProgram(sCgMrtVertexProgram); /// draw to 3 color buffers glDrawBuffers(3, mrt); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); break; } glDepthFunc(GL_LESS); glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); // reset lod levels for current frame LODLevel::InitFrame(camera->GetPosition()); // bring eye modelview matrix up-to-date SetupEyeView(); // actually render the scene geometry using one of the specified algorithms traverser->RenderScene(); ///////// //-- do the rest of the rendering glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); // reset depth pass and render visible objects if (renderType == RenderState::DEPTH_PASS) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); RenderVisibleObjects(); } /////////////// //-- render sky RenderSky(); state.Reset(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); if (renderType == RenderState::DEFERRED) { fbo->Release(); cgGLDisableProfile(RenderState::sCgVertexProfile); cgGLDisableProfile(RenderState::sCgFragmentProfile); glDrawBuffers(1, mrt); if (useSsao) ssaoShader->Render(fbo, oldViewProjMatrix, ssaoExpFactor); else deferredShader->Render(fbo); } /////////// state.SetRenderType(RenderState::FIXED); if (showAlgorithmTime) { glFinish(); algTime = algTimer.Elapsedms(); perfGraph->AddData(algTime); perfGraph->Draw(); } else { if (visMode) DisplayVisualization(); } //glFlush(); const bool restart = true; elapsedTime = frameTimer.Elapsedms(restart); DisplayStats(); // flip textures for temporal smoothing isFirstTexture = !isFirstTexture; glutSwapBuffers(); } #pragma warning( disable : 4100 ) void KeyBoard(unsigned char c, int x, int y) { switch(c) { case 27: CleanUp(); exit(0); break; case 32: //space renderMode = (renderMode + 1) % RenderTraverser::NUM_TRAVERSAL_TYPES; ResetTraverser(); break; case 'h': case 'H': showHelp = !showHelp; break; case '+': maxBatchSize += 10; traverser->SetMaxBatchSize(maxBatchSize); break; case '-': maxBatchSize -= 10; if (maxBatchSize < 0) maxBatchSize = 1; traverser->SetMaxBatchSize(maxBatchSize); break; case 'M': case 'm': useMultiQueries = !useMultiQueries; traverser->SetUseMultiQueries(useMultiQueries); break; case '1': descendKeyPressed = true; break; case '2': ascendKeyPressed = true; break; case '3': if (trianglesPerVirtualLeaf >= 100) trianglesPerVirtualLeaf -= 100; bvh->SetVirtualLeaves(trianglesPerVirtualLeaf); break; case '4': trianglesPerVirtualLeaf += 100; bvh->SetVirtualLeaves(trianglesPerVirtualLeaf); break; case '5': assumedVisibleFrames -= 1; if (assumedVisibleFrames < 1) assumedVisibleFrames = 1; traverser->SetAssumedVisibleFrames(assumedVisibleFrames); break; case '6': assumedVisibleFrames += 1; traverser->SetAssumedVisibleFrames(assumedVisibleFrames); break; case '7': ssaoExpFactor *= 0.5f; break; case '8': ssaoExpFactor *= 2.0f; if (ssaoExpFactor > 1.0f) ssaoExpFactor = 1.0f; break; case 'o': case 'O': useOptimization = !useOptimization; traverser->SetUseOptimization(useOptimization); break; case 'a': case 'A': leftKeyPressed = true; break; case 'd': case 'D': rightKeyPressed = true; break; case 'w': case 'W': upKeyPressed = true; break; case 's': case 'S': downKeyPressed = true; break; case 'r': case 'R': { useRenderQueue = !useRenderQueue; traverser->SetUseRenderQueue(useRenderQueue); } break; case 'b': case 'B': { useTightBounds = !useTightBounds; traverser->SetUseTightBounds(useTightBounds); } break; default: return; } glutPostRedisplay(); } void SpecialKeyUp(int c, int x, int y) { switch (c) { case GLUT_KEY_LEFT: leftKeyPressed = false; break; case GLUT_KEY_RIGHT: rightKeyPressed = false; break; case GLUT_KEY_UP: upKeyPressed = false; break; case GLUT_KEY_DOWN: downKeyPressed = false; break; default: return; } //glutPostRedisplay(); } void KeyUp(unsigned char c, int x, int y) { switch (c) { case 'A': case 'a': leftKeyPressed = false; break; case 'D': case 'd': rightKeyPressed = false; break; case 'W': case 'w': upKeyPressed = false; break; case 'S': case 's': downKeyPressed = false; break; case '1': descendKeyPressed = false; break; case '2': ascendKeyPressed = false; break; default: return; } //glutPostRedisplay(); } void Special(int c, int x, int y) { switch(c) { case GLUT_KEY_F1: showHelp = !showHelp; break; case GLUT_KEY_F2: visMode = !visMode; break; case GLUT_KEY_F3: showBoundingVolumes = !showBoundingVolumes; traverser->SetShowBounds(showBoundingVolumes); break; case GLUT_KEY_F4: showOptions = !showOptions; break; case GLUT_KEY_F5: showStatistics = !showStatistics; break; case GLUT_KEY_F6: flyMode = !flyMode; break; case GLUT_KEY_F7: renderType = (renderType + 1) % 3; traverser->SetUseDepthPass(renderType == RenderState::DEPTH_PASS); break; case GLUT_KEY_F8: useSsao = !useSsao; break; case GLUT_KEY_F9: showAlgorithmTime = !showAlgorithmTime; break; case GLUT_KEY_LEFT: { leftKeyPressed = true; camera->Pitch(KeyRotationAngle()); } break; case GLUT_KEY_RIGHT: { rightKeyPressed = true; camera->Pitch(-KeyRotationAngle()); } break; case GLUT_KEY_UP: { upKeyPressed = true; KeyHorizontalMotion(KeyShift()); } break; case GLUT_KEY_DOWN: { downKeyPressed = true; KeyHorizontalMotion(-KeyShift()); } break; default: return; } glutPostRedisplay(); } #pragma warning( default : 4100 ) void Reshape(int w, int h) { winAspectRatio = 1.0f; glViewport(0, 0, w, h); winWidth = w; winHeight = h; if (w) winAspectRatio = (float) w / (float) h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, winAspectRatio, nearDist, myfar); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); } void Mouse(int button, int state, int x, int y) { if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) { xEyeBegin = x; yMotionBegin = y; glutMotionFunc(LeftMotion); } else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) { xEyeBegin = x; yEyeBegin = y; yMotionBegin = y; glutMotionFunc(RightMotion); } else if ((button == GLUT_MIDDLE_BUTTON) && (state == GLUT_DOWN)) { horizontalMotionBegin = x; verticalMotionBegin = y; glutMotionFunc(MiddleMotion); } glutPostRedisplay(); } /** rotation for left/right mouse drag motion for up/down mouse drag */ void LeftMotion(int x, int y) { Vector3 viewDir = camera->GetDirection(); Vector3 pos = camera->GetPosition(); // don't move in the vertical direction Vector3 horView(viewDir[0], viewDir[1], 0); float eyeXAngle = 0.2f * M_PI * (xEyeBegin - x) / 180.0; camera->Pitch(eyeXAngle); pos += horView * (yMotionBegin - y) * 0.2f; camera->SetPosition(pos); xEyeBegin = x; yMotionBegin = y; glutPostRedisplay(); } /** rotation for left / right mouse drag motion for up / down mouse drag */ void RightMotion(int x, int y) { float eyeXAngle = 0.2f * M_PI * (xEyeBegin - x) / 180.0; float eyeYAngle = -0.2f * M_PI * (yEyeBegin - y) / 180.0; camera->Yaw(eyeYAngle); camera->Pitch(eyeXAngle); xEyeBegin = x; yEyeBegin = y; glutPostRedisplay(); } // strafe void MiddleMotion(int x, int y) { Vector3 viewDir = camera->GetDirection(); Vector3 pos = camera->GetPosition(); // the 90 degree rotated view vector // y zero so we don't move in the vertical Vector3 rVec(viewDir[0], viewDir[1], 0); Matrix4x4 rot = RotationZMatrix(M_PI * 0.5f); rVec = rot * rVec; pos -= rVec * (x - horizontalMotionBegin) * 0.1f; pos[2] += (verticalMotionBegin - y) * 0.1f; camera->SetPosition(pos); horizontalMotionBegin = x; verticalMotionBegin = y; glutPostRedisplay(); } void InitExtensions(void) { GLenum err = glewInit(); if (GLEW_OK != err) { // problem: glewInit failed, something is seriously wrong fprintf(stderr,"Error: %s\n", glewGetErrorString(err)); exit(1); } if (!GLEW_ARB_occlusion_query) { printf("I require the GL_ARB_occlusion_query to work.\n"); exit(1); } } void Begin2D() { glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, winWidth, 0, winHeight); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); } void End2D() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); } // displays the visualisation of culling algorithm void DisplayVisualization() { visualization->SetFrameId(traverser->GetCurrentFrameId()); Begin2D(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0.0f ,0.0f, 0.0f, 0.5f); glRecti(winWidth - winWidth / 3, winHeight - winHeight / 3, winWidth, winHeight); glDisable(GL_BLEND); End2D(); AxisAlignedBox3 box = bvh->GetBox(); // hack: set far plane for viz camera->SetFar(0.35f * Magnitude(box.Diagonal())); const float offs = box.Size().x * 0.3f; //Vector3 vizpos = Vector3(box.Min().x, box.Min().y + box.Size().y * 0.5f, box.Min().z + box.Size().z * 50); Vector3 vizpos = Vector3(box.Min().x, box.Min().y - box.Size().y * 0.35f, box.Min().z + box.Size().z * 50); visCamera->SetPosition(vizpos); visCamera->ResetPitchAndYaw(); //visCamera->Pitch(M_PI); glPushAttrib(GL_VIEWPORT_BIT); glViewport(winWidth - winWidth / 3, winHeight - winHeight / 3, winWidth / 3, winHeight / 3); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-offs, offs, -offs, offs, 0.0f, box.Size().z * 100.0f); glMatrixMode(GL_MODELVIEW); glPushMatrix(); visCamera->SetupCameraView(); //Matrix4x4 rotX = RotationXMatrix(camera->GetYaw()); //glMultMatrixf((float *)rotX.x); Matrix4x4 rotZ = RotationZMatrix(-camera->GetPitch()); glMultMatrixf((float *)rotZ.x); Vector3 pos = camera->GetPosition(); glTranslatef(-pos.x, -pos.y, -pos.z); GLfloat position[] = {0.8f, 1.0f, 1.5f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {bvh->GetBox().Center().x, bvh->GetBox().Max().y, bvh->GetBox().Center().z, 1.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); glClear(GL_DEPTH_BUFFER_BIT); //////////// //-- visualization of the occlusion culling visualization->Render(); // reset previous settings glPopAttrib(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } // cleanup routine after the main loop void CleanUp() { DEL_PTR(traverser); DEL_PTR(sceneQuery); DEL_PTR(bvh); DEL_PTR(visualization); DEL_PTR(camera); DEL_PTR(loader); DEL_PTR(renderQueue); DEL_PTR(perfGraph); if (sCgMrtVertexProgram) cgDestroyProgram(sCgMrtVertexProgram); if (RenderState::sCgMrtFragmentProgram) cgDestroyProgram(RenderState::sCgMrtFragmentProgram); if (RenderState::sCgMrtFragmentTexProgram) cgDestroyProgram(RenderState::sCgMrtFragmentTexProgram); if (sCgContext) cgDestroyContext(sCgContext); } // this function inserts a dezimal point after each 1000 void CalcDecimalPoint(string &str, int d, int len) { static vector numbers; numbers.clear(); static string shortStr; shortStr.clear(); static char hstr[100]; while (d != 0) { numbers.push_back(d % 1000); d /= 1000; } // first element without leading zeros if (numbers.size() > 0) { sprintf(hstr, "%d", numbers.back()); shortStr.append(hstr); } for (int i = (int)numbers.size() - 2; i >= 0; i--) { sprintf(hstr, ",%03d", numbers[i]); shortStr.append(hstr); } int dif = len - (int)shortStr.size(); for (int i = 0; i < dif; ++ i) { str += " "; } str.append(shortStr); } void DisplayStats() { static char msg[9][300]; static double frameTime = elapsedTime; static double renderTime = algTime; const float expFactor = 0.1f; // if some strange render time spike happened in this frame => don't count if (elapsedTime < 500) frameTime = elapsedTime * expFactor + (1.0f - expFactor) * elapsedTime; static float rTime = 1000.0f; if (showAlgorithmTime) { if (algTime < 500) renderTime = algTime * expFactor + (1.0f - expFactor) * renderTime; } accumulatedTime += elapsedTime; if (accumulatedTime > 500) // update every fraction of a second { accumulatedTime = 0; if (frameTime) fps = 1e3f / (float)frameTime; rTime = renderTime; renderedObjects = traverser->GetStats().mNumRenderedGeometry; renderedNodes = traverser->GetStats().mNumRenderedNodes; renderedTriangles = traverser->GetStats().mNumRenderedTriangles; traversedNodes = traverser->GetStats().mNumTraversedNodes; frustumCulledNodes = traverser->GetStats().mNumFrustumCulledNodes; queryCulledNodes = traverser->GetStats().mNumQueryCulledNodes; issuedQueries = traverser->GetStats().mNumIssuedQueries; stateChanges = traverser->GetStats().mNumStateChanges; numBatches = traverser->GetStats().mNumBatches; } Begin2D(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (showHelp) { DrawHelpMessage(); } else { if (showOptions) { glColor4f(0.0f, 0.0f, 0.0f, 0.5f); glRecti(5, winHeight - 95, winWidth * 2 / 3 - 5, winHeight - 5); } if (showStatistics) { glColor4f(0.0f, 0.0f, 0.0f, 0.5f); glRecti(5, winHeight - 165, winWidth * 2 / 3 - 5, winHeight - 100); } glEnable(GL_TEXTURE_2D); myfont.Begin(); if (showOptions) { glColor3f(0.0f, 1.0f, 0.0f); int i = 0; static char *renderTypeStr[] = {"fixed function", "fixed function + depth pass", "deferred shading"}; sprintf(msg[i ++], "multiqueries: %d, tight bounds: %d, render queue: %d", useMultiQueries, useTightBounds, useRenderQueue); sprintf(msg[i ++], "render technique: %s, SSAO: %d", renderTypeStr[renderType], useSsao); sprintf(msg[i ++], "triangles per virtual leaf: %5d", trianglesPerVirtualLeaf); sprintf(msg[i ++], "assumed visible frames: %4d, max batch size: %4d", assumedVisibleFrames, maxBatchSize); for (int j = 0; j < 4; ++ j) myfont.DrawString(msg[j], 10.0f, winHeight - 5 - j * 20); } if (showStatistics) { glColor3f(1.0f, 1.0f, 0.0f); string str; string str2; int len = 10; CalcDecimalPoint(str, renderedTriangles, len); CalcDecimalPoint(str2, bvh->GetBvhStats().mTriangles, len); int i = 4; sprintf(msg[i ++], "rendered: %6d of %6d nodes, %s of %s triangles", renderedNodes, bvh->GetNumVirtualNodes(), str.c_str(), str2.c_str()); sprintf(msg[i ++], "traversed: %5d, frustum culled: %5d, query culled: %5d", traversedNodes, frustumCulledNodes, queryCulledNodes); sprintf(msg[i ++], "issued queries: %5d, state changes: %5d, render batches: %5d", issuedQueries, stateChanges, numBatches); for (int j = 4; j < 7; ++ j) myfont.DrawString(msg[j], 10.0f, winHeight - (j + 1) * 20); } glColor3f(1.0f, 1.0f, 1.0f); static char *alg_str[] = {"Frustum Cull", "Stop and Wait", "CHC", "CHC ++"}; if (!showAlgorithmTime) { sprintf(msg[7], "%s: %6.1f fps", alg_str[renderMode], fps); } else { sprintf(msg[7], "%s: %6.1f ms", alg_str[renderMode], rTime); } myfont.DrawString(msg[7], 1.3f, 690.0f, 760.0f);//, top_color, bottom_color); //sprintf(msg[8], "algorithm time: %6.1f ms", rTime); //myfont.DrawString(msg[8], 720.0f, 730.0f); } glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); End2D(); } void RenderSky() { SceneEntityContainer::const_iterator sit, sit_end = skyGeometry.end(); for (sit = skyGeometry.begin(); sit != sit_end; ++ sit) (*sit)->Render(&state); } void RenderVisibleObjects() { state.SetRenderType(RenderState::FIXED); state.Reset(); glEnable(GL_LIGHTING); glDepthFunc(GL_LEQUAL); //cout << "visible: " << (int)traverser->GetVisibleObjects().size() << endl; SceneEntityContainer::const_iterator sit, sit_end = traverser->GetVisibleObjects().end(); for (sit = traverser->GetVisibleObjects().begin(); sit != sit_end; ++ sit) renderQueue->Enqueue(*sit); renderQueue->Apply(); glDepthFunc(GL_LESS); } void PlaceViewer(const Vector3 &oldPos) { Vector3 playerPos = camera->GetPosition(); bool validIntersect = sceneQuery->CalcIntersection(playerPos); if (validIntersect) // && ((playerPos.z - oldPos.z) < bvh->GetBox().Size(2) * 1e-1f)) { camera->SetPosition(playerPos); } }