Changeset 3068 for GTP


Ignore:
Timestamp:
10/24/08 16:39:24 (16 years ago)
Author:
mattausch
Message:

working on dynamic stuff again

Location:
GTP/trunk/App/Demos/Vis/FriendlyCulling/src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp

    r3066 r3068  
    419419        if (!mDynamicEntities.empty()) 
    420420        { 
    421                 //UpdateDynamicBranch(); 
     421                UpdateDynamicBranch(); 
    422422        } 
    423423} 
     
    427427{ 
    428428        // q: should we use distance to center rather than the distance to the near plane? 
    429          
    430         // because otherwise problems with big object penetrating the near plane  
    431         // (e.g., big objects in the distance which are then always visible) 
    432         // especially annoying is this problem when using the frustum  
    433         // fitting on the visible objects for shadow mapping 
    434         // on the other hand, distance to near plane can also be used  
    435         // for near plane intersection 
    436         node->mDistance = sNearPlane.Distance(node->GetBox().Center()); 
    437         //node->mDistance = node->GetBox().GetMinDistance(sNearPlane); 
     429        // distance to near plane can also be used for checking near plane intersection 
     430        //node->mDistance = sNearPlane.Distance(node->GetBox().Center()); 
     431        node->mDistance = node->GetBox().GetMinDistance(sNearPlane); 
    438432} 
    439433 
     
    441435float Bvh::CalcMaxDistance(BvhNode *node) const 
    442436{ 
     437#if 1 
    443438        return node->GetBox().GetMaxDistance(sNearPlane); 
    444439 
     440#else 
     441        // use bounding boxes of geometry to determine max dist 
    445442        float maxDist = .0f; 
    446443 
     
    457454 
    458455        return maxDist; 
     456#endif 
    459457} 
    460458 
     
    932930 
    933931        mNumVirtualNodes = 0; 
    934  
    935932        // assign new virtual leaves based on specified #triangles per leaf 
    936933        std::stack<BvhNode *> nodeStack; 
    937  
    938934        nodeStack.push(mRoot); 
    939935 
     
    12731269void Bvh::UpdateDynamicBranch() 
    12741270{ 
    1275         BvhNode *dynamicRoot = static_cast<BvhInterior *>(mRoot)->mBack; 
    1276  
    12771271        // delete old branch 
    1278         if (!dynamicRoot->IsLeaf()) 
     1272        if (!mDynamicRoot->IsLeaf()) 
    12791273        { 
    12801274                cout << "deleting old branch" << endl; 
    12811275 
    1282                 DEL_PTR(dynamicRoot); 
    1283  
    1284                 dynamicRoot = new BvhLeaf(mRoot); 
    1285                 dynamicRoot->mBox = mRoot->mBox; 
     1276                DEL_PTR(mDynamicRoot); 
     1277 
     1278                mDynamicRoot = new BvhLeaf(mRoot); 
     1279                mDynamicRoot->mBox = mRoot->mBox; 
     1280 
     1281                mDynamicRoot->mFirst = 0; 
     1282                mDynamicRoot->mLast = 0; 
     1283                mDynamicRoot->mArea = mDynamicRoot->mBox.SurfaceArea(); 
    12861284        } 
    12871285 
    12881286        cout << "updating dynamic branch" << endl; 
    12891287 
    1290         dynamicRoot = SubdivideLeaf(static_cast<BvhLeaf *>(dynamicRoot), 0, mDynamicEntities); 
     1288        mDynamicRoot = SubdivideLeaf(static_cast<BvhLeaf *>(mDynamicRoot), 0, mDynamicEntities); 
    12911289 
    12921290        cout << "finished updating dynamic branch" << endl; 
     
    13021300bool Bvh::IntersectsNearPlane(BvhNode *node) const 
    13031301{  
    1304         float distanceToNearPlane = node->GetBox().GetMinDistance(sNearPlane); 
     1302        // note: we have problems with large scale object penetrating the near plane  
     1303        // (e.g., objects in the distance which are always handled to be visible) 
     1304        // especially annoying is this problem when using the frustum  
     1305        // fitting on the visible objects for shadow mapping 
     1306        // but don't see how to solve this issue without using much costlier calculations 
     1307         
    13051308        // we stored the near plane distance => we can use it also here 
    1306         //float distanceToNearPlane = node->GetDistance(); 
    1307          
    1308         return distanceToNearPlane < sNear; 
    1309 } 
    1310  
    1311  
    1312 } 
     1309        float distanceToNearPlane = node->GetDistance(); 
     1310        //float distanceToNearPlane = node->GetBox().GetMinDistance(sNearPlane); 
     1311         
     1312        return (distanceToNearPlane < sNear); 
     1313} 
     1314 
     1315 
     1316} 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/BvhLoader.cpp

    r3065 r3068  
    7676        BvhNode *root = LoadNextNode(stream, NULL); 
    7777 
    78 #if 1 
    79  
    8078        bvh->mRoot = root; 
    8179 
     80#if 0 
     81 
     82        //bvh->mRoot = bvh->mStaticRoot; 
     83        bvh->mNumNodes = 1; 
     84 
    8285#else 
    83         // copy root and set new one for dynamic objects 
    84         BvhInterior *newRoot = new BvhInterior(NULL); 
     86        // we are setting a new root node  
     87        // and adds one level of indirection to the bvh  
     88        // It allows us to use dynamic objects 
     89 
     90        // the new bvh has two main branches 
     91        // a static branch (the old root), and adynamic branch  
     92        // we create a 'dynamic' leaf which basically is a container 
     93        // for all dynamic objects underneath 
     94 
     95        // the bounding boxes of the dynamic tree must be updated 
     96        // once each frame in order to be able to incorporate 
     97        // the movements of the objects within 
     98 
     99        // create new root 
     100        /*BvhInterior *newRoot = new BvhInterior(NULL); 
     101        bvh->mRoot = newRoot; 
     102 
     103        // the separation is a purely logical one 
     104        // the bounding boxes of the child nodes are  
     105        // identical to those of the root node 
     106 
     107        newRoot->mBox = bvh->mStaticRoot->mBox; 
     108        newRoot->mArea = newRoot->mBox.SurfaceArea(); 
     109 
     110        newRoot->mFirst = bvh->mStaticRoot->mFirst; 
     111        newRoot->mLast = bvh->mStaticRoot->mLast; 
     112 
     113        // add static root on left subtree 
     114        newRoot->mFront = bvh->mStaticRoot; 
     115        bvh->mStaticRoot->mParent = newRoot; 
     116        */ 
     117        // create and add dynamic root 
     118        BvhLeaf *dynamicRoot = new BvhLeaf(NULL); 
    85119         
    86         newRoot->mBox = root->mBox; 
    87         newRoot->mFirst = root->mFirst; 
    88         newRoot->mLast = root->mLast; 
     120        dynamicRoot->mFirst = 0; 
     121        dynamicRoot->mLast = 0; 
    89122 
    90         // create 'dynamic' leaf which basically is a container 
    91         // for all dynamic objects 
    92         BvhLeaf *dynamicLeaf = new BvhLeaf(newRoot); 
    93         dynamicLeaf->mBox = root->mBox; 
     123        //dynamicRoot->mBox = bvh->mStaticRoot->mBox; 
     124        dynamicRoot->mBox = bvh->mRoot->mBox; 
     125        dynamicRoot->mArea = dynamicRoot->mBox.SurfaceArea(); 
    94126 
    95         newRoot->mFront = root; 
    96         root->mParent = newRoot; 
     127        bvh->mDynamicRoot = dynamicRoot; 
     128        //newRoot->mBack = dynamicRoot; 
    97129 
    98         newRoot->mBack = dynamicLeaf; 
    99  
    100         bvh->mRoot = newRoot; 
     130        bvh->mNumNodes = 1; 
    101131#endif 
    102132 
    103133        tQueue.push(bvh->mRoot); 
    104         bvh->mNumNodes = 1; 
    105  
     134         
    106135        while(!tQueue.empty()) 
    107136        { 
     
    139168        //-- post process nodes 
    140169 
     170        /// this function must be called once after creation 
    141171        bvh->PostProcess(); 
    142172         
    143173        // set virtual leaves for specified number of triangles 
    144174        bvh->SetVirtualLeaves(INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES); 
    145  
     175        /// update the numleaves parameter of the bvh nodes 
    146176        bvh->UpdateNumLeaves(bvh->mRoot); 
    147177        // compute unique ids 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.cpp

    r3063 r3068  
    222222        glDrawBuffers(1, mrt + index); 
    223223 
    224         //glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
    225224        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    226225 
    227         glEnd(); 
    228  
    229226        FrameBufferObject::Release(); 
    230227} 
    231228 
    232229 
    233 DeferredRenderer::DeferredRenderer(int w, int h, PerspectiveCamera *cam, float scaleFactor): 
     230DeferredRenderer::DeferredRenderer(int w, int h, PerspectiveCamera *cam): 
    234231mWidth(w), mHeight(h),  
    235232mCamera(cam), 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/DeferredRenderer.h

    r3062 r3068  
    3030public: 
    3131        /** Constructor for a deferred shader taking the requested output image size, 
    32                 the current camera,     and a scaling factor. 
    33                          
    34                 The parameter scaleFactor must be reciprocal value of the  
    35                 scale factor used for creating the world space position texture. It is used recover the  
    36                 exact scene size that was scaled in order to improve floating point precision. 
     32                the current camera; 
    3733        */ 
    38         DeferredRenderer(int w, int h, PerspectiveCamera *cam, float scaleFactor); 
     34        DeferredRenderer(int w, int h, PerspectiveCamera *cam); 
    3935        /** The algorithm renders the scene given an fbo consists of 1 color buffer,  
    4036                1 position buffer, and 1 normal buffer. 
     
    5955        enum SAMPLING_METHOD {SAMPLING_POISSON, SAMPLING_QUADRATIC, SAMPLING_DEFAULT}; 
    6056        enum SHADING_METHOD {DEFAULT, SSAO, GI}; 
    61  
     57        /** Set the samplig method for the indirect illumination 
     58        */ 
    6259        void SetSamplingMethod(SAMPLING_METHOD s); 
    63  
     60        /** Set the shading method (SSAO, SSAO + color bleeding 
     61        */ 
    6462        void SetShadingMethod(SHADING_METHOD s); 
    6563 
    66         // hack: store the color buffer idx for the first flipflip-mrt here 
     64        // hack: store the color buffer idx for the currently used flip flop-MRT here 
    6765        // TODO matt: make this less hacky 
    6866        static int colorBufferIdx; 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Material.cpp

    r3065 r3068  
    9696void Material::Render(RenderState *state) 
    9797{ 
    98         mTechniques[state->GetRenderTechnique()]->Render(state); 
     98        // set technique if available 
     99        int idx = min((int)mTechniques.size() - 1 , state->GetRenderTechnique()); 
     100        mTechniques[idx]->Render(state); 
    99101} 
    100102 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/RenderState.cpp

    r3066 r3068  
    1717 
    1818RenderState::RenderState(): 
    19 mRenderTechnique(FORWARD), 
     19mRenderTechnique(0), 
    2020mUseAlphaToCoverage(true), 
    2121mLockCullFaceEnabled(false), 
     
    320320 
    321321 
    322 void RenderState::SetRenderTechnique(RenderTechnique t)  
     322void RenderState::SetRenderTechnique(int t)  
    323323{  
    324324        mRenderTechnique = t;  
     
    326326 
    327327 
    328 RenderState::RenderTechnique RenderState::GetRenderTechnique() const  
     328int RenderState::GetRenderTechnique() const  
    329329{ 
    330330        return mRenderTechnique;  
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/RenderState.h

    r3066 r3068  
    2323                QUERY, 
    2424                RENDER 
    25         }; 
    26  
    27         /// the used render technique 
    28         enum RenderTechnique 
    29         { 
    30                 FORWARD, 
    31                 DEFERRED, 
    32                 DEPTH_PASS 
    3325        }; 
    3426 
     
    5951        */ 
    6052        inline int GetCurrentVboId() const { return mCurrentVboId; } 
    61         /** Sets the render technique (foreward, depth pass, deferred) 
     53        /** Sets the index of the render technique that is used to render a material.  
     54                Initially we use foreward = 0, deferred = 1, depth pass = 1 
    6255        */ 
    63         void SetRenderTechnique(RenderTechnique t); 
     56        void SetRenderTechnique(int t); 
    6457        /** See Set 
    6558        */ 
    66         RenderTechnique GetRenderTechnique() const; 
     59        int GetRenderTechnique() const; 
    6760        /** If alpha to coverage is instead of alpha testing 
    6861        */ 
     
    8780        int mCurrentVboId; 
    8881        /// the current render technique 
    89         RenderTechnique mRenderTechnique; 
     82        int mRenderTechnique; 
    9083 
    9184        bool mUseAlphaToCoverage; 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/ShadowMapping.cpp

    r3067 r3068  
    596596        glViewport(0, 0, mSize, mSize); 
    597597 
    598         glDisable(GL_LIGHTING); 
    599         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 
     598        // turn off colors + lighting (should be handled by the render state) 
    600599        glShadeModel(GL_FLAT); 
    601600 
     
    607606 
    608607        glPopAttrib(); 
    609          
    610608        glShadeModel(GL_SMOOTH); 
    611         glEnable(GL_LIGHTING); 
    612         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 
    613609 
    614610#if 0 
  • GTP/trunk/App/Demos/Vis/FriendlyCulling/src/chcdemo.cpp

    r3067 r3068  
    6262 
    6363 
     64/// the environment for the program parameter 
    6465static Environment env; 
    6566 
    66 #define MAX_DEPTH_CONST 10.0f 
    67  
    6867 
    6968GLuint fontTex; 
    70 /// fbo 
     69/// the fbo used for MRT 
    7170FrameBufferObject *fbo = NULL; 
    7271/// the renderable scene geometry 
     
    9190int renderMode = RenderTraverser::CHCPLUSPLUS; 
    9291/// eye near plane distance 
    93 float nearDist = 0.2f; 
     92const float nearDist = 0.2f; 
    9493/// eye far plane distance 
    9594float farDist = 1e6f; 
    9695/// the field of view 
    97 float fov = 50.0f; 
    98 /// the pixel threshold where a node is still considered invisible 
    99 int threshold; 
    100  
    101 int assumedVisibleFrames = 10; 
    102 int maxBatchSize = 50; 
    103 int trianglesPerVirtualLeaf = INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES; 
     96const float fov = 50.0f; 
     97 
    10498SceneQuery *sceneQuery = NULL; 
    10599RenderQueue *renderQueue = NULL; 
    106 // traverses and renders the hierarchy 
     100/// traverses and renders the hierarchy 
    107101RenderTraverser *shadowTraverser = NULL; 
    108  
     102/// the skylight + skydome model 
    109103SkyPreetham *preetham = NULL; 
     104 
     105 
     106 
     107/// the technique used for rendering 
     108enum RenderTechnique 
     109{ 
     110        FORWARD, 
     111        DEFERRED, 
     112        DEPTH_PASS 
     113}; 
    110114 
    111115 
     
    170174bool descendKeyPressed = false; 
    171175bool ascendKeyPressed = false; 
    172  
    173176bool altKeyPressed = false; 
    174177 
     
    207210 
    208211 
    209 #define CAMERA_PASS 0 
    210 #define LIGHT_PASS 1 
     212////////////// 
     213//-- algorithm parameters 
     214 
     215/// the pixel threshold where a node is still considered invisible  
     216/// (should be zero for conservative visibility) 
     217int threshold; 
     218int assumedVisibleFrames = 10; 
     219int maxBatchSize = 50; 
     220int trianglesPerVirtualLeaf = INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES; 
     221 
     222////////////// 
     223 
     224enum {CAMERA_PASS = 0, LIGHT_PASS = 1}; 
     225 
     226 
    211227 
    212228//DeferredRenderer::SAMPLING_METHOD samplingMethod = DeferredRenderer::SAMPLING_POISSON; 
     
    495511         
    496512        /// forward rendering is the default 
    497         state.SetRenderTechnique(RenderState::FORWARD); 
     513        state.SetRenderTechnique(FORWARD); 
    498514 
    499515        // frame time is restarted every frame 
     
    814830        // multisampling does not work with deferred shading 
    815831        glDisable(GL_MULTISAMPLE_ARB); 
    816  
    817         state.SetRenderTechnique(RenderState::DEFERRED); 
    818  
    819         shaderManager->EnableVertexProfile(); 
    820         shaderManager->EnableFragmentProfile(); 
    821  
    822         const Vector3 pos = camera->GetPosition(); 
     832        state.SetRenderTechnique(DEFERRED); 
    823833 
    824834 
     
    887897        int oldRenderMethod = renderMethod; 
    888898        // for rendering the light view, we use forward rendering 
    889         if (renderLightView) renderMethod = RenderState::FORWARD; 
     899        if (renderLightView) renderMethod = FORWARD; 
    890900 
    891901        /// enable vbo vertex array 
     
    899909                glEnable(GL_MULTISAMPLE_ARB); 
    900910                 
    901                 state.SetRenderTechnique(RenderState::FORWARD); 
     911                state.SetRenderTechnique(FORWARD); 
    902912                glEnable(GL_LIGHTING); 
    903913 
     
    913923                state.SetUseAlphaToCoverage(false); 
    914924 
    915                 state.SetRenderTechnique(RenderState::DEPTH_PASS); 
     925                state.SetRenderTechnique(DEPTH_PASS); 
    916926 
    917927                if (!fbo) InitFBO(); fbo->Bind(); 
     
    921931                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    922932 
    923                 // the scene is rendered withouth any shading    
     933                // the scene is rendered withouth any shading  
     934                // (should be handled by render state) 
    924935                glShadeModel(GL_FLAT); 
    925                 glDisable(GL_LIGHTING); 
    926                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 
    927936 
    928937 
     
    933942                glEnable(GL_MULTISAMPLE_ARB); 
    934943                 
    935                 state.SetRenderTechnique(RenderState::DEPTH_PASS); 
     944                state.SetRenderTechnique(DEPTH_PASS); 
    936945 
    937946                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    938947 
    939                 // the scene is rendered withouth any shading    
     948                // the scene is rendered withouth any shading  
     949                // (should be handled by render state) 
    940950                glShadeModel(GL_FLAT); 
    941                 glDisable(GL_LIGHTING); 
    942                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 
    943  
     951                 
    944952 
    945953                break; 
     
    10141022 
    10151023                if (!ssaoShader) ssaoShader =  
    1016                         new DeferredRenderer(texWidth, texHeight, camera, farDist / MAX_DEPTH_CONST); 
     1024                        new DeferredRenderer(texWidth, texHeight, camera); 
    10171025                 
    10181026                DeferredRenderer::SHADING_METHOD shadingMethod; 
     
    10381046 
    10391047 
    1040         state.SetRenderTechnique(RenderState::FORWARD); 
     1048        state.SetRenderTechnique(FORWARD); 
    10411049        state.Reset(); 
    10421050 
     
    18551863 
    18561864        if ((renderMethod == RENDER_DEFERRED) || (renderMethod == RENDER_DEPTH_PASS_DEFERRED)) 
    1857                 state.SetRenderTechnique(RenderState::DEFERRED); 
     1865                state.SetRenderTechnique(DEFERRED); 
    18581866 
    18591867        const bool useToneMapping =  
     
    18741882                if (showShadowMap && !renderLightView) 
    18751883                { 
    1876                         state.Reset(); 
    1877  
    1878                         float minVisibleDist = min(camera->GetFar(), traverser->GetMaxVisibleDistance()); 
    1879                         RenderShadowMap(minVisibleDist); 
     1884                        // usethe maximal visible distance to focus shadow map 
     1885                        float maxVisibleDist = min(camera->GetFar(), traverser->GetMaxVisibleDistance()); 
     1886                        RenderShadowMap(maxVisibleDist); 
    18801887                } 
    18811888 
    1882                 glViewport(0, 0, texWidth, texHeight); 
    1883                 // rese the state before the final visible objects pass 
    1884                 state.Reset(); 
     1889                //glViewport(0, 0, texWidth, texHeight); 
     1890                // initialize deferred rendering 
    18851891                InitDeferredRendering(); 
    18861892        } 
    18871893        else 
    18881894        { 
    1889                 state.SetRenderTechnique(RenderState::FORWARD); 
    1890                 // rese the state before the final visible objects pass 
    1891                 state.Reset(); 
    1892         } 
     1895                state.SetRenderTechnique(FORWARD); 
     1896        } 
     1897 
     1898        ///////////////// 
     1899        //-- reset gl state before the final visible objects pass 
     1900 
     1901        state.Reset(); 
    18931902 
    18941903        glEnableClientState(GL_NORMAL_ARRAY); 
    1895  
     1904        /// switch back to smooth shading 
    18961905        glShadeModel(GL_SMOOTH); 
    1897         // draw all objects that have exactly the same depth as the current sample 
    1898         glDepthFunc(GL_LEQUAL); 
    1899  
    1900         //glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 
     1906        /// reset alpha to coverage flag 
    19011907        state.SetUseAlphaToCoverage(true); 
    19021908        // clear color 
    19031909        glClear(GL_COLOR_BUFFER_BIT); 
    19041910         
     1911        // draw only objects having exactly the same depth as the current sample 
     1912        glDepthFunc(GL_EQUAL); 
    19051913 
    19061914        //cout << "visible: " << (int)traverser->GetVisibleObjects().size() << endl; 
    19071915 
    1908         SceneEntityContainer::const_iterator sit,  
     1916        SceneEntityContainer::const_iterator sit, 
    19091917                sit_end = traverser->GetVisibleObjects().end(); 
    19101918 
     
    19131921                renderQueue->Enqueue(*sit); 
    19141922        } 
    1915  
     1923        /// now render out everything in one giant pass 
    19161924        renderQueue->Apply(); 
    19171925 
     1926        // switch back to standard depth func 
    19181927        glDepthFunc(GL_LESS); 
    19191928        state.Reset(); 
     
    19411950void RenderShadowMap(float newfar) 
    19421951{ 
    1943         shaderManager->DisableVertexProfile(); 
    1944         shaderManager->DisableFragmentProfile(); 
    1945  
    19461952        glDisableClientState(GL_NORMAL_ARRAY); 
    1947  
    1948         state.SetRenderTechnique(RenderState::DEPTH_PASS); 
     1953        state.SetRenderTechnique(DEPTH_PASS); 
    19491954         
    19501955        // hack: disable cull face because of alpha textured balconies 
    19511956        glDisable(GL_CULL_FACE); 
    19521957        state.LockCullFaceEnabled(true); 
    1953         /// don't use alphatocoverage 
     1958 
     1959        /// don't use alpha to coverage for the depth map (problems with fbo rendering) 
    19541960        state.SetUseAlphaToCoverage(false); 
    19551961 
     
    19741980} 
    19751981 
     1982 
    19761983/** Toach each material once in order to preload the render queue  
    19771984        bucket id of each material 
     
    19811988        for (int i = 0; i < 3; ++ i) 
    19821989        { 
    1983                 state.SetRenderTechnique((RenderState::RenderTechnique)i); 
     1990                state.SetRenderTechnique(i); 
    19841991 
    19851992                // fill all shapes into the render queue        once so we can establish the buckets 
Note: See TracChangeset for help on using the changeset viewer.