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

     
    实现无关shader编写的全屏反走样的扩展,全名叫WGL_ARB_multisample。关键字1,ARB,说明它真是扩展(别打~);关键字2,WGL,说明它并非一般的扩展。锯齿,或者,早已把此扩展忘记了吧。本为下篇,有意者可先看上篇,
    如果你的程序INCLUDE目录里面只有glew.h或者glext.h,你是用不起这个扩展的。它属于ARB委员会的闲置物,因此才会被安排在wglew.h或者wglext.h里的吧。是不是呢?请好心人路过告知。总之,要使用这个扩展,两道。1.程序包含wglew.h,并拥有glew32.lb库文件(与glew.h不同,wglew.h不必要置于gl.h之前,本扩展也没看到需要Initglew()之类的初始化函数);2.程序包含wglext.h......恩,貌似只需要wglext.h就可。
    另外,当时发现本扩展存在EXT版本,惊喜之余专门用了一下,发现是无法用的。用opengl extension viewer看了看,本显卡支持的EXT扩展里没有这个的EXT版本,而且貌似其他显卡也没有。只有用WGL_ARB_multisample了。(ARB与EXT是哪门子区别?可求助GOOGLE大神,通俗点说是一个不能直接用,一个可以。见下所述。)
    参考NEHE #46,弄了一个类。最初是想封装得好点的,但后来发现这难度大,因为使用该扩展的位置是程序初始化之前——屏幕像素设置,DC,RC设置的地方。好吧,还是先说这个类:

     
  1. class MultiSample  
  2. {
  3. public:
  4.     MultiSample();
  5.     ~MultiSample();
  6.  
  7.     bool InitMultiSample(HWND hwnd);
  8.     bool ExtentionSurpported(){ return multisampleSupportted;}
  9.  
  10.     int GetMultiSampleFormat(){ return MultiSampleFormat;}
  11.     void SetMultiSample(UINT sample){Multisample = sample; }
  12.  
  13.     UINT GetSupportedFormatNum(){ return numofFormats;}
  14.     int GetSupportedFormats(UINT i){ return i < numofFormats ? pixelformat[i] : 0;}
  15.  
  16. private:
  17.     bool WGLisExtensionSupported(const char *extension);
  18.  
  19.     UINT Multisample;
  20.     bool multisampleSupportted;
  21.     int MultiSampleFormat;
  22.     UINT numofFormats;
  23.     int pixelformat[20];
  24. };

最重要的函数是InitMultiSample(),它完成了“全屏反走样必要的设置”,更准确地说,它给下面列出的私有成员变量赋值了。这些变量中最重要的——也是本扩展所需要的东西和最后给出的东西:输入Multisample,输出MultiSampleFormat。前者就是我们要告诉扩展的采样参数,譬如4代表4X,8代表8X等等(详见[全屏反锯齿 - 多重采样Ⅰ] );后者就是:像素格式。
    恩,没错,最后要的就是像素格式。就是我们在初始化OPENGL窗口设置时用来设置渲染窗口像素的模式的那样东西。(详细见[自剖一下自己用的NEHE OpenGL框架(下篇)] 。)作用的话,接下来再探讨,先来看看这个UINT“像素格式”是怎么得到的:

     
  1. bool MultiSample::InitMultiSample(HWND hwnd)
  2. {
  3.     multisampleSupportted = WGLisExtensionSupported("WGL_ARB_multisample");
  4.  
  5.     if(!multisampleSupportted)return false;
  6.  
  7.     PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
  8.  
  9.     HDC hdc = ::GetDC(hwnd);
  10.  
  11.     float   fAttributes[] = {0,0};
  12.     int iAtributes[] = 
  13.     {
  14.         WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
  15.         WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
  16.         WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
  17.         WGL_COLOR_BITS_ARB, 24,
  18.         WGL_ALPHA_BITS_ARB, 8,
  19.         WGL_DEPTH_BITS_ARB, 16,
  20.         WGL_STENCIL_BITS_ARB, 0,
  21.         WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
  22.         WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
  23.         WGL_SAMPLES_ARB, Multisample,   
  24.         0,0
  25.     };
  26.  
  27.    if(!wglChoosePixelFormatARB(hdc, iAtributes, fAttributes, 20 , pixelformat, &numofFormats))
  28.    {
  29.        multisampleSupportted = false;
  30.        return false;
  31.    }
  32.    if(numofFormats <= 0)return false;
  33.  
  34.    MultiSampleFormat = pixelformat[0];
  35.    return true;
  36. }

本函数接受一个表征窗口的句柄,并接下来从该句柄得出绘图环境DC。这是本扩展第2个需要知道的东西:产生新像素格式必然要先了解绘图环境。multisampleSupportted返回你的显卡是否支持本WGL扩展,WGLisExtensionSupported是直接从NEHE46那里拿来的。然后我们来获取本ARB扩展功能函数:wglChoosePixelFormatARB的“实体”,获取后我们就能用了。用的方法无非是输入-输出。我们输入绘图环境DC,还有一个iAtributes数组指针,一个fAttributes数组指针。fAttributes只是单纯的0数组,我不知道其他值会有什么效果,只知道这里只需要float类型的0数组就够了,或者NULL,我尝试过,也可以的。至于iAtributes,可是戏玉!
    它很明显在设置类似PIXELFORMATDESCRIPTOR(像素描述器,见[自剖一下自己用的NEHE OpenGL框架(下篇))的东西,告诉wglChoosePixelFormatARB函数,我们所需要的像素格式的模样,譬如彩色通道位数,是否使用双缓冲等等(注意数组内是:“属性,值”的格式),然后由它去设置新的像素格式。值得注意的是WGL_SAMPLE_BUFFERS_ARB和WGL_SAMPLES_ARB。根据opengl官方给出的的本扩展的文档,前者表明新增一个缓冲(缓存),叫“多重采样缓冲”(如何?),该缓冲启用下,传统5大缓冲中的3个将会失效,只有颜色缓冲和辅助缓冲能继续。是不是因为多重采样缓冲其实包含了这些了呢?文档没兴致看仔细,算了。启用该缓冲,并把WGL_SAMPLES_ARB设置为我们需要的采样参数后,就能用它来描述像素格式了。
    像素格式,其实表面上看就是一个简单的UINT,真正的含义只有SetPixelFormat函数才知道。wglChoosePixelFormatARB接收输入后,输出满足要求的像素格式(用UINT表示),我把这些满足的像素格式扔进成员数组pixelformat里了,并规定最多接收20个,numofFormats是实际满足的个数。我做过试验的,其他像素属性按上,1X的不算,2X下共有16种像素格式可以满足(UINT为20,24,28~64);3X~4X,共有12种满足;5X~8X,8种;9X~16X,4种;16X以上,0种。由此一来说明本显卡确实最多支持16X,二来印证上篇所言,只有2的N次方的采样参数有用(中间那些都被默认向大者靠了)。
    函数最后让输出的像素格式取第一个有用的(最准确满足的)像素格式。
    看MainFrame里的像素格式设置部分(OnCreateClient函数),在两个地方作了代码添加:

     
  1. BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
  2. {
  3. //.........常规的像素格式描述器设置
  4. //.........
  5.     if(!SecondWindowCreate)
  6.     {
  7.         if ( !( PixelFormat = ChoosePixelFormat ( m_hDC, &pfd ) ) ) {
  8.             KillGLWindow ();    
  9.             MessageBox ( "Can't Find A Suitable PixelFormat.""ERROR", MB_OK | MB_ICONEXCLAMATION );
  10.             return FALSE;                                               
  11.         }
  12.     }
  13.     else    
  14.         PixelFormat = MultiSampleFormat;
  15.         
  16.         if ( !SetPixelFormat ( m_hDC, PixelFormat, &pfd ) ){
  17.             KillGLWindow ();
  18.             MessageBox ( "Can't Set The PixelFormat.""ERROR", MB_OK | MB_ICONEXCLAMATION );
  19.             return FALSE;                                               
  20.         }
  21.  
  22. //.........DC,RC关联设置
  23. //..........
  24.     if(SecondWindowCreate)
  25.     {
  26.         if (MessageBox("渲染一堆三角形(YES)  渲染几个一般几何模型(NO)"
  27.                        "RederTest Selection",MB_YESNO|MB_ICONQUESTION)==IDYES)
  28.             RenderOb=FALSE;     
  29.         else 
  30.                         RenderOb = TRUE;
  31.     }
  32.     else
  33.     {
  34.         MutiSampleSelectDlg MSdLG;
  35.         if(MSdLG.DoModal() == IDOK)
  36.         {
  37.          MultiSample = MSdLG.GetMultiSample();
  38.          Multisam.SetMultiSample(MultiSample);
  39.  
  40.          Multisam.InitMultiSample(m_hWnd);
  41.          PixelFormat = Multisam.GetMultiSampleFormat();
  42.          return bRet;
  43.         }
  44.     }
  45. //.....
  46. //....初始化....
  47. }   

SecondWindowCreate是CMAINFRAME的成员函数,顾名思义,就是表明OnCreateClient函数要执行两次。SecondWindowCreate为FALSE的时候,按照原设置来设置像素格式。然后关联好RC后,调用InitMultiSample,接收当前opengl渲染窗口(原窗口)句柄和从某对话框(我弄的)得来的采样参数,得出的像素格式存入CMAINFRAME另一成员函数PixelFormat里。不必初始化直接返回。
    注意,返回后,我会保存生成的PixelFormat,然后把这个刚刚建立的窗口(原窗口)——连显示都不让它显示,直接让它夭折。重新建一个CMAINFRAME对象,生成新窗口,让SecondWindowCreate为TRUE,并把刚才的PixelFormat交给它。好了,第二次来到OnCreateClient,直接用支持多重采样的PixelFormat去SetPixelFormat(),一路下去。
    这是因为只有原来的RC建立好后,wglChoosePixelFormatARB才能知道当前有哪些像素格式适合吧。是不方便但也没办法。对了,最后再看一下夭折-再生的处理在我的NEHE框架里怎么改吧,是在APP类的InitInstance函数里(不改动前的,可见[自剖一下自己用的NEHE OpenGL框架(中篇)] ):

     
  1. BOOL CAntialiasing_MultiSampleApp::InitInstance()
  2. {
  3.     // Standard initialization
  4.  
  5.     // Change the registry key under which our settings are stored.
  6.  
  7.     // TODO: You should modify this string to be something appropriate
  8.     // such as the name of your company or organization.
  9.     SetRegistryKey(_T("Local AppWizard-Generated Applications"));
  10.  
  11.     // To create the main window, this code creates a new frame window
  12.     // object and then sets it as the application's main window object.
  13.  
  14.     m_pMainWnd = NULL;
  15.     CMainFrame* pFrame = new CMainFrame;
  16.     pFrame->CreateWindowSecondTime(false);
  17.  
  18.     if (!pFrame->Create(NULL,"MFC OpenGL"))
  19.         return FALSE;
  20.  
  21.     int MultiSampleFormat = pFrame->GetMultiSampleFormat();
  22.  
  23.     pFrame->DestroyWindow();
  24.     //delete pFrame;
  25.  
  26.     pFrame = new CMainFrame;
  27.     pFrame->CreateWindowSecondTime(true);
  28.     pFrame->SetMultiSampleFormat(MultiSampleFormat);
  29.  
  30.     if (!pFrame->Create(NULL,"MFC OpenGL"))
  31.         return FALSE;
  32.  
  33.     m_pMainWnd = pFrame;
  34.     pFrame->ShowWindow(m_nCmdShow);
  35.     pFrame->UpdateWindow();
  36.  
  37.     return TRUE;
  38. }

在下对MFC不熟,中间那里为什么无法DELETE掉呢?好了,看结果吧:
     全屏反锯齿  ---www.zwqxin.com
    
    (场景1是用了NEHE #46里的旋转矩形场景。设置为1X时,可见基本跟不设置差不多的,边缘锯齿严重)
    
    全屏反锯齿  ---www.zwqxin.com
    
    (设置为4X时,边缘锯齿还是明显的,但稍微不那么严重了吧)
    
    全屏反锯齿  ---www.zwqxin.com
    
    (设置为16X时,边缘锯齿效应基本上消除了哦)
    
    全屏反锯齿  ---www.zwqxin.com    
    
    (16X时,再来一张,很好哦。效率呢?这么多次采样平滑,肯定会下降的,但因为场景简单 偶家显卡比较好,所以FPS没有下降)
    
    全屏反锯齿  ---www.zwqxin.com
    
    (自家的场景2,模型边缘,在1X下的严重锯齿)
    
    全屏反锯齿  ---www.zwqxin.com
    
    (自家的场景2,模型边缘,在16X下的锯齿现象消解)
    

    

 

相关新闻

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

您可能对这些感兴趣  

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

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

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