上一题下一题
跳转到
 
 
  世界如此多姿,发展如此迅速,窥一斑未必还能知全豹。但正如万花筒一样,每一个管窥都色彩斑斓。  
 
 
  知识通道 | 学习首页 | 教师首页 | PK首页 | 知识创造首页 | 企业首页 | 登录
 
本文对应知识领域
Picking Tutorial
作者:未知 申领版权
2010年10月25日 共有 2026 次访问 【添加到收藏夹】 【我要附加题目
受欢迎度:
    

The Name Stack


    The OpenGL API provides a mechanism for picking objects in a 3D scene. This tutorial will show you how to detect which objects are bellow the mouse or in a square region of the OpenGL window. The steps involved in detecting which objects are at the location where the mouse was clicked are:

    
  • 1. Get the window coordinates of the mouse
  • 2. Enter selection mode
  • 3. Redefine the viewing volume so that only a small area of the window around the cursor is rendered
  • 4. Render the scene, either using all primitives or only those relevant to the picking operation
  • 5. Exit selection mode and identify the objects which were rendered on that small part of the screen.
  • In order to identify the rendered objects using the OpenGL API you must name all relevant objects in your scene. The OpenGL API allows you to give names to primitives, or sets of primitives (objects). When in selection mode, a special rendering mode provided by the OpenGL API, no objects are actually rendered in the framebuffer. Instead the names of the objects (plus depth information) are collected in an array. For unnamed objects, only depth information is collected.
        
        Using the OpenGL terminology, a hit occurs whenever a primitive is rendered in selection modeHit records are stored in the selection buffer. Upon exiting the selection mode OpenGL returns the selection buffer with the set of hit records. Since OpenGL provides depth information for each hit the application can then easily detect which object is closer to the user.
        
        Introducing the Name Stack
        
        As the title suggests, the names you assign to objects are stored in a stack. Actually you don't give names to objects, as in a text string. Instead you number objects. Nevertheless, since in OpenGL the term name is used, the tutorial will also use the term name instead of number
        .
        
        When an object is rendered, if it intersects the new viewing volume, a hit record is created. The hit record contains the names currently on thename stack plus the minimum and maximum depth for the object. Note that a hit record is created even if the name stack is empty, in which case it only contains depth information. If more objects are rendered before the name stack is altered or the application leaves the selection mode, then the depth values stored on the hit record are altered accordingly.
        
        A hit record is stored on the selection buffer only when the current contents of the name stack are altered or when the application leaves theselection mode
        .
        
        The rendering function for the selection mode therefore is responsible for the contents of the name stack as well as the rendering of primitives.
        
        OpenGL provides the following functions to manipulate the Name Stack: 
        

        

    void glInitNames(void);

        


        This function creates an empty name stack. You are required to call this function to initialize the stack prior to pushing names. 
        

        

    void glPushName(GLuint name);

        


        Adds name to the top of the stack. The stacks maximum dimension is implementation dependent, however according to the specs it must contain at least 64 names which should prove to be more than enough for the vast majority of applications. Nevertheless if you want to be sure you may query the state variableGL_NAME_STACK_DEPTH (use glGetIntegerv(GL_NAME_STACK_DEPTH)). Pushing values onto the stack beyond its capacity causes an overflow errorGL_STACK_OVERFLOW
        

        

    void glPopName();

        


        Removes the name from top of the stack. Popping a value from an empty stack causes an underflow, error GL_STACK_UNDERFLOW
        

        

    void glLoadName(GLunit name);

        


        This function replaces the top of the stack with name. It is the same as calling 
        

        

    glPopName();glPushName(name);

        


        This function is basically a short cut for the above snippet of code. Loading a name on an empty stack causes the error GL_INVALID_OPERATION
        .
        
        Note: Calls to the above functions are ignored when not in selection mode. This means that you may have a single rendering function with all the name stack functions inside it. When in the normal rendering mode the functions are ignored and when in selection mode the hit records will be collected.
        
        Note: You can't place these functions inside a glBegin glEnd construction, which is kind of annoying since that will require a new rendering function for the selection mode in some cases. For instance if you have a set of points inside a glBegin glEnd and you want to name them in such a way that you can tell them apart, then you must create one glBegin glEnd block for each name.
        
        Rendering for the Selection Mode
        
        An example of a rendering function is now presented. 
        

        

    #define BODY 1#define HEAD 2...void renderInSelectionMode() {1 glInitNames();2 glPushName(BODY);3 drawBody();4 glPopName();5 glPushName(HEAD);6 drawHead();7 drawEyes();8 glPopName();9 drawGround();}

        


        OK, lets go line by line.

        
  • 1 glInitNames(); - This function creates an empty stack. This is required before any other operation on the stack such as Load, Push or Pop.
  •  
        
  • 2 glPushName(BODY); - A name is pushed onto the stack. The stack now contains a single name.
  •  
        
  • 3 drawBody(); - A function which calls OpenGL primitives to draw something. If any of the primitives called in here intersects the viewing volume a hit record is created. The contents of the hit record will be the name currently on the name stack, BODY, plus the minimum and maximum depth values for those primitives that intersect the viewing volume
  •  
        
  • 4 glPopName(); - Removes the name of the top of the stack. Since the stack had a single item, it will now be empty. The name stack has been altered so if a hit record was created in 2 it will be saved in the selection buffer
  •  
        
  • 5 glPushName(HEAD); - A name is pushed onto the stack. The stack now contains a single name again. The stack has been altered, but there is no hit record so nothing goes into the selection buffer
  •  
        
  • 6 drawHead(); - Another function that renders OpenGL primitives. Again if any of the primitives intersects the viewing volume a hit record is created
  •  
        
  • 7 drawEyes(); - Yet another function which renders OpenGL primitives. If any of the primitives in here intersects the viewing volume and a hit record already exists from 6, the hit record is updated accordingly. The names currently in the hit record are kept, but if any of the primitives in drawEyes() has a smaller minimum, or a larger maximum depth, then these new values are stored in the hit record. If the primitives in drawEyes() do intersect the viewing volume but there was no hit record from drawHead then a new one is created.
  •  
        
  • 8 glPopName(); - The name on the top of the stack is removed. Since the stack had a single name the stack is now empty. Again the stack has been altered so if a hit record was created it will be stored in the selection buffer
  •  
        
  • 9 drawGround(); - If any if the primitives called in here intersects the viewing volume a hit record is created. The stack is empty, so no names will be stored in the hit record, only depth information. If no alteration to the name stack occurs after this point, then the hit record created will only be stored in the selection buffer when the application leaves the selection mode. This will be covered later on the tutorial.
  •  
        

    Note: lines 4 and 5 could have been replaced by glLoadName(HEAD)
        ;
        
        Note that you can push a dummy name (some unused value) right at the start, and afterwards just use glLoadName, instead of Pushing and Popping names. However it is faster to disregard objects that don't have a name than to check if the name is the dummy name. On the other hand it is probably faster to call glLoadName than it is to Pop followed by Push.
        
        Using multiple names for an object
        
        There is no rule that says that an object must have a single name. You can give multiple names to an object. Suppose you have a number of snowmen disposed on a grid. Instead of naming them as 1,2,3,... you could name each of them with the row and column where they are placed. In this case each snowman will have two names describing its position: the row and column of the grid.
        
        The following two functions show the two different approaches. First using a single name for each snowman. 
        

        

    for(int i = -3; i < 3; i ) for(int j = -3; j < 3; j ) { glPushMatrix(); glPushName(i*6 j); glTranslatef(i*10.0,0,j * 10.0); glCallList(snowManDL); glPopName(); glPopMatrix(); }

        


        The following function gives two names to each snowman. In this latter function if a hit occurs the hit record will have two names. 
        

        

    for(int i = -3; i < 3; i ) { glPushName(i); for(int j = -3; j < 3; j ) { glPushMatrix(); glPushName(j); glTranslatef(i*10.0,0,j * 10.0); glCallList(snowManDL); glPopName(); glPopMatrix(); } glPopName();}

        


        Hierarchical Naming
        
        This is a natural extension to multiple naming. It may be of interest to find out where in a particular object you have clicked. For instance you may want to know not only in which snowman you clicked but also if you clicked on the head or the body. The following function provides this information. 
        

        

    for(int i = -3; i < 3; i ) { glPushName(i); for(int j = -3; j < 3; j ) { glPushMatrix(); glPushName(j); glTranslatef(i*10.0,0,j * 10.0); glPushName(HEAD); glCallList(snowManHeadDL); glLoadName(BODY); glCallList(snowManBodyDL); glPopName(); glPopName(); glPopMatrix(); } glPopName();}

        


        In this case you'll have three names when you click on either the body or head of a snowman: the row, the column and the value BODY or HEAD respectively.
        
        A Note about Rendering on Selection Mode
        
        As mentioned before, all calls to stack functions are ignored when not in selection mode, i.e. when rendering to the frame buffer. This means that you can have a single rendering function for both modes. However this can result in a serious waste of time. An application may have only a small number of pickable objects. Using the same function for both modes will require to render a lot of non-pickable objects when in selection mode. Not only the rendering time will be longer than required as will the time required to process the hit records
        .
        
        Therefore it makes sense to consider writing a special rendering function for the selection mode in these cases. However you should take extra care when doing so. Consider for instance an application where you have several rooms, each room with a potential set of pickable objects. You must prevent the user from selecting objects through walls, i.e. objects that are in other rooms and are not visible. If you use the same rendering function then the walls will cause a hit, and therefore you can use depth information to disregard objects that are behind the wall. However if you decide to build a function just with the pickable objects then there is no way to tell if an object is in the current room, or behind a wall.
        
        Therefore, when building a special rendering function for the selection mode you should include not only the pickable objects, but also all the objects that can cause occlusions, such as walls. For highly interactive real time applications it is probably a good option to build simplified representations of the objects that may cause occlusions. For instance a single polygon may replace a complex wall, or a box may replace a table.

        

     

    相关新闻

    战略:绩效管理的中心
    债务大转嫁
    新股破发不是病 利益链条才要命
    中美研究型大学科技管理体制与运行机制比较研究与启示
    1.3 Intel 系列CPU简介
    Direct3D 实现鼠标拾取
    理解OpenGL拾取模式(OpenGL Picking)
    3D数学:求点到直线的投影
    全屏反锯齿 - 多重采样Ⅱ

    您可能对这些感兴趣  

    《VB程序设计基础》选择题
    设计模式之Iterator
    设计模式之Visitor
    设计模式之Interpreter(解释器)
    设计模式之Mediator(中介者)
    设计模式之Strategy(策略)
    设计模式之State
    设计模式之Command
    设计模式之Chain of Responsibility(职责链)
    设计模式之Observer

    题目筛选器
    日期:
    类型:
    状态:
    得分: <=
    分类:
    作者:
    职业:
    关键字:
    搜索

     
     
     
      焦点事件
     
      知识体系
     
      职业列表
     
     
      最热文章
     
     
      最多引用文章
     
     
      最新文章
     
     
     
     
    网站介绍 | 广告服务 | 招聘信息 | 保护隐私权 | 免责条款 | 法律顾问 | 意见反馈
    版权所有 不得转载
    沪ICP备 10203777 号 联系电话:021-54428255
      帮助提示    
    《我的太学》是一种全新的应用,您在操作中遇到疑问或者问题,请拨打电话13564659895,15921448526。
    《我的太学》