// occquery.cpp : Defines the entry point for the console application. // #include #include #include "common.h" #include "glInterface.h" #include "RenderTraverser.h" #include "SceneEntity.h" #include "Vector3.h" #include "Matrix4x4.h" #include "BinaryLoader.h" #include "Bvh.h" #include "Camera.h" #include "Geometry.h" #include "BvhLoader.h" #include "FrustumCullingTraverser.h" #include "StopAndWaitTraverser.h" using namespace std; using namespace CHCDemo; /// the renderable scene geometry SceneEntityContainer sceneEntities; // traverses and renders the hierarchy RenderTraverser *traverser; /// the hierarchy Bvh *bvh; /// the scene camera Camera *camera; /// the scene bounding box AxisAlignedBox3 sceneBox; /// the current render state RenderState state; // eye near plane distance float nearDist = 0.1f; int winWidth = 1024; int winHeight = 768; float winAspectRatio = 1.0f; float visZoomFactor = 1.5f; bool showHelp = false; bool showStatistics = true; bool showBoundingVolumes = false; bool visMode = false; bool showCreateParams = false; int currentFrame = -1; // visualisation view matrix Matrix4x4 visView; //mouse navigation state int xEyeBegin, yEyeBegin, yMotionBegin, verticalMotionBegin, horizontalMotionBegin = 0; //int renderMode = RenderTraverser::RENDER_COHERENT; const int renderTimeSize = 100; long renderTimes[renderTimeSize]; int renderTimesIdx = 0; int renderTimesValid = 0; bool useOptimization = true; Vector3 amb[2]; Vector3 dif[2]; Vector3 spec[2]; void InitExtensions(); void DisplayVisualization(); void InitGLstate(); void CleanUp(); void SetupEyeView(); void UpdateEyeMtx(); void SetupLighting(); void begin2D(); void end2D(); void output(int x, int y, const char *string); void keyboard(unsigned char c, int x, int y); void drawHelpMessage(); void drawStatistics(); void display(void); void special(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 drawEyeView(void); void setupVisView(void); long calcRenderTime(void); void resetTimer(void); void calcDecimalPoint(std::string &str, int d); int main(int argc, char* argv[]) { camera = new Camera(winWidth, winHeight); glutInitWindowSize(winWidth, winHeight); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutCreateWindow("Coherent Hierarchical Culling"); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutIdleFunc(display); InitExtensions(); InitGLstate(); leftMotion(0, 0); middleMotion(0, 0); BinaryLoader loader; //const string filename("house_test.dem"); //const string filename("city_demo.dem"); const string filename("city.dem"); //const string filename("roofs.dem"); if (loader.Load(filename, sceneEntities)) cout << "scene " << filename << " loaded" << endl; else cerr << "loading scene " << filename << " failed" << endl; BvhLoader bvhLoader; //bvh = bvhLoader.Load("roofs.bvh", sceneEntities); bvh = bvhLoader.Load("city.bvh", sceneEntities); //bvh = bvhLoader.Load("city_demo.bvh", sceneEntities); //bvh = bvhLoader.Load("house_test.bvh", sceneEntities); sceneBox = bvh->GetBox(); //traverser = new FrustumCullingTraverser(); traverser = new StopAndWaitTraverser(); traverser->SetHierarchy(bvh); traverser->SetRenderState(&state); //SetupProjection(800, 600, 60, sceneBox); //camera->LookAtBox(sceneBox); camera->LookInBox(sceneBox); //camera->SetPosition(Vector3(0, 0, -3)); //camera->SetDirection(Vector3(0, 0, 1)); /// initialise rendertime array for(int i=0; iSetupCameraView(); GLfloat position[] = {0.8f, 1.0f, 1.5f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {sceneBox.Center().x, sceneBox.Max().y, sceneBox.Center().z, 1.0f}; //GLfloat position1[] = {-2.0f, 1.0f, 0.0f, 0.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); } void display(void) { char * msg[] = {"Frustum culling only", "Hierarchical stop and wait", "Coherent hierarchical culling"}; char msg2[200]; char msg3[200]; char msg4[100]; char msg5[100]; char msg6[100]; char msg7[100]; char msg8[100]; /*sprintf_s(msg2, "Traversed: %4d, frustum culled: %4d, query culled: %4d (of %d nodes)", traverser.GetNumTraversedNodes(), traverser.GetNumFrustumCulledNodes(), traverser.GetNumQueryCulledNodes(), traverser.GetHierarchy()->GetNumHierarchyNodes()); */ char *optstr[2] = {"", ", using optimization"}; float fps = 1e3f; long renderTime = calcRenderTime(); if (renderTime) fps = 1e3f / (float)renderTime; //sprintf_s(msg3, "Threshold: %4d, algorithm rendering time: %ld ms (%3.3f fps), queries: %s", // traverser.GetVisibilityThreshold(), renderTime / 1000, fps, optstr[useOptimization]); sprintf_s(msg3, "render time: %ld ms (%3.3f fps), queries: %s", renderTime, fps, optstr[useOptimization]); string str; string str2; /*calcDecimalPoint(str, Geometry::CountTriangles(objectType) * traverser.GetNumRenderedGeometry()); calcDecimalPoint(str2, Geometry::CountTriangles(objectType) * numObjects); sprintf_s(msg4, "Rendered objects %d (of %d), rendered triangles: %s (of %s)", traverser.GetNumRenderedGeometry(), numObjects, str.c_str(), str2.c_str()); */ ++ currentFrame; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // bring eye modelview matrix up-to-date SetupEyeView(); bvh->InitFrame(camera, currentFrame); InitTiming(); long t1, t2; t1 = GetTime(); traverser->SetCamera(camera); //traverser->RenderFrustum(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); traverser->Render(); /* bool usesTextures = false; SceneEntityContainer::const_iterator sit, sit_end = sceneEntities.end(); for (sit = sceneEntities.begin(); sit != sit_end; ++ sit) { SceneEntity *entity = *sit; if (!usesTextures && entity->GetGeometry()->HasTexture()) { glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); usesTextures = true; } else if (usesTextures && !entity->GetGeometry()->HasTexture()) { glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); usesTextures = false; } entity->Render(); } */ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); t2 = GetTime(); long loop_time = TimeDiff(t1, t2); //cout<<"t: " << loop_time< renderTimesValid) renderTimesValid = renderTimesIdx; //if(visMode) displayVisualization(); begin2D(); if(showHelp) { drawHelpMessage(); } else { glColor3f(1.0,1.0,1.0); //output(10, winHeight-10, msg[renderMode]); if(showStatistics) { if(showCreateParams) { output(10, winHeight-150, msg8); output(10, winHeight-130, msg7); output(10, winHeight-110, msg6); output(10, winHeight-90, msg5); } output(10, winHeight-70, msg3); //output(10, winHeight-50, msg4); //output(10, winHeight-30, msg2); } } end2D(); glutSwapBuffers(); } #pragma warning( disable : 4100 ) void keyboard(const unsigned char c, const int x, const int y) { //int threshold; //HierarchyNode *hierarchy; switch(c) { case 27: exit(0); break; case 32: //space // renderMode = (renderMode + 1) % RenderTraverser::NUM_RENDERMODES; resetTimer(); //traverser.Render(renderMode); // render once so stats are updated break; case 'h': case 'H': showHelp = !showHelp; break; case 'v': case 'V': showBoundingVolumes = !showBoundingVolumes; //HierarchyNode::SetRenderBoundingVolume(showBoundingVolumes); break; case 's': case 'S': showStatistics = !showStatistics; break; case '+': //threshold = traverser.GetVisibilityThreshold() + 10; //traverser.SetVisibilityThreshold(threshold); break; case '-': //threshold = traverser.GetVisibilityThreshold() - 10; //if(threshold < 0) threshold = 0; //traverser.SetVisibilityThreshold(threshold); break; case '1': visMode = !visMode; break; case '2': visZoomFactor += 0.1; setupVisView(); break; case '3': visZoomFactor -= 0.1; if(visZoomFactor < 0.1) visZoomFactor = 0.1; setupVisView(); break; case 'r': case 'R': showCreateParams = !showCreateParams; break; case 'g': case 'G': useOptimization = !useOptimization; //traverser.SetUseOptimization(useOptimization); break; /* case 'c': case 'C': hierarchy = traverser.GetHierarchy(); // delete old hierarchy if (hierarchy) delete hierarchy; deleteGeometry(); maxTranslation[2] = -3.0 - zLength; numObjects = numNextObjects; objectType = nextObjectType; hierarchy = generateHierarchy(numObjects); traverser.SetHierarchy(hierarchy); showCreateParams = false; traverser.Render(renderMode); // render once to update stats resetTimer(); break; */ default: return; } glutPostRedisplay(); } void special(const int c, const int x, const int y) { // used to avoid vertical motion with the keys //Vector3 hvec = Vector3(viewDir[0], 0, viewDir[2]); switch(c) { case GLUT_KEY_F1: showHelp = !showHelp; break; case GLUT_KEY_F2: //numNextObjects -= 100; //if(numNextObjects < 100) numNextObjects = 100; break; case GLUT_KEY_F3: // numNextObjects += 100; break; case GLUT_KEY_F4: //zLength -= 1; //if(zLength < 0) zLength = 0; break; case GLUT_KEY_F5: //zLength += 1; break; case GLUT_KEY_F6: //objectSize -= 0.1; //if(objectSize < 0.1) objectSize = 0.1; break; case GLUT_KEY_F7: //objectSize += 0.1; break; case GLUT_KEY_F8: //nextObjectType = (nextObjectType + 1) % Geometry::NUM_OBJECTS; break; case GLUT_KEY_LEFT: // rotateVectorY(viewDir, 0.2); break; case GLUT_KEY_RIGHT: //rotateVectorY(viewDir, -0.2); break; case GLUT_KEY_UP: // linCombVector3(eyePos, eyePos, hvec, 0.6); break; case GLUT_KEY_DOWN: //linCombVector3(eyePos, eyePos, hvec, -0.6); break; default: return; } glutPostRedisplay(); } #pragma warning( default : 4100 ) void reshape(const int w, const int h) { winAspectRatio = 1.0f; glViewport(0, 0, w, h); winWidth = w; winHeight = h; if (w) winAspectRatio = (float) h / (float) w; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, 1.0f / winAspectRatio, nearDist, 2.0f * Magnitude(sceneBox.Diagonal())); 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)) { 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) { static float eyeXAngle = 0.0f; Vector3 viewDir = camera->GetDirection(); Vector3 pos = camera->GetPosition(); // don't move in the vertical direction Vector3 horView(viewDir[0], 0, viewDir[2]); eyeXAngle = -0.2f * M_PI * (xEyeBegin - x) / 180.0; // rotate view vector Matrix4x4 rot = RotationYMatrix(eyeXAngle); viewDir = rot * viewDir; pos += horView * (yMotionBegin - y) * 0.2f; camera->SetDirection(viewDir); 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) { static float eyeYAngle = 0.0f; Vector3 viewDir = camera->GetDirection(); Vector3 right = camera->GetRightVector(); eyeYAngle = -0.2f * M_PI * (yEyeBegin - y) / 180.0; // rotate view vector Matrix4x4 rot = RotationAxisMatrix(right, eyeYAngle); viewDir = rot * viewDir; camera->SetDirection(viewDir); 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], 0, viewDir[2]); Matrix4x4 rot = RotationYMatrix(M_PI * 0.5f); rVec = rot * rVec; pos += rVec * (x - horizontalMotionBegin) * 0.1f; pos[1] += (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(void) { glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, winWidth, winHeight, 0); } void end2D(void) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); } void output(const int x, const int y, const char *string) { if(string != 0) { int len, i; glRasterPos2f(x,y); len = (int) strlen(string); for (i = 0; i < len; i++) { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, string[i]); } } } // displays the visualisation of the kd tree node culling void displayVisualization() { begin2D(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0.0,0.0,0.0,0.5); glRecti(winWidth, 0, winWidth / 2, winHeight / 2); glDisable(GL_BLEND); end2D(); glViewport(winWidth / 2, winHeight / 2, winWidth, winHeight); glPushMatrix(); glLoadMatrixf((float *)visView.x); glClear(GL_DEPTH_BUFFER_BIT); // --- visualization of the occlusion culling /*HierarchyNode::SetRenderBoundingVolume(true); traverser.RenderVisualization(); HierarchyNode::SetRenderBoundingVolume(showBoundingVolumes); */ glPopMatrix(); glViewport(0, 0, winWidth, winHeight); } /** Sets up view matrix in order to get a good position for viewing the kd tree node culling */ void setupVisView() { const Vector3 up(0.0, 1.0, 0.0); Vector3 visPos(24, 23, -6); visPos[0] *= visZoomFactor; visPos[1] *= visZoomFactor; visPos[2] *= visZoomFactor; Vector3 visDir = Vector3(-1.3, -1, -1); //normalize(visDir); //look(visView, visPos, visDir, up); } // we take a couple of measurements and compute the average long calcRenderTime() { long result = 0; for(int i=0; i numbers; char hstr[100]; while (d != 0) { numbers.push_back(d % 1000); d /= 1000; } // first element without leading zeros if (numbers.size() > 0) { sprintf_s(hstr, "%d", numbers.back()); str.append(hstr); } for (size_t i = numbers.size() - 2; i >= 0; i--) { sprintf_s(hstr, ",%03d", numbers[i]); str.append(hstr); } }