OpenGL中调色板的使用

转载 2006年06月16日 09:42:00
OpenGL中调色板的使用

目 录
  1 调色板的知识
  2 颜色表示与转换
  3 调色板的生成算法
  4 设置调色板的例子

--------------------------------------------------------------------------------

  OpenGL是由SGI公司开发的一套3D图形软件接口标准,由于具有体系结构简单合理、使用方便、与操作平台无关等优点,OpenGL迅速成为一种3D图形接口的工业标准,并陆续在各种平台上得以实现。微软公司在推出Windows NT 3.5时便开始把OpenGL集成到NT操作系统之中,96年下半年又在Windows 95OSR2中加入OpenGL,使得低端用户也能够充分享受到OpenGL带来的高质量3D图形效果。
  基于OpenGL的应用程序有两种类型。一种是利用OpenGL辅助库来完成一些简单的图形显示,这种应用程序编写起来非常简单,但其功能十分有限,因此只适合于演示OpenGL函数的用法等任务。第二种是与VC++等这样功能强大的开发工具相结合,从而完成比较复杂的任务。本文所要讨论的就是以MFC类库为基础,使用OpenGL时所涉及到的关于调色板的问题。

1、Windows下的调色板
  OpenGL可以使用16色、256色、64K和16M真彩色。真彩模式下不需要调色板,而在16色模式下根本不可能得到较为满意的效果,因此对OpenGL而言,调色板只有在256色模式下才有意义。
  我们知道,Windows把调色板分为系统调色板和逻辑调色板。每个应用程序都拥有一套自己的逻辑调色板(或使用缺省调色板),当该应用程序拥有键盘输入焦点时可以最多使用从16M种色彩中选取的256种颜色(20种系统保留颜色和236种自由选取的颜色),而失去焦点的应用程序可能会有某些颜色显示不正常。系统调色板由Windows内核来管理,它是由系统保留的20种颜色和经仲裁后各个应用程序设置的颜色组成,并与硬件的256个调色板相对应。应用程序的逻辑调色板与硬件的调色板没有直接的对应关系,而是按照最小误差的原则映射到系统调色板中,因此即使应用程序自由选取256种不同颜色构成自己的逻辑调色板,也有可能某些颜色显示到屏幕上时是一样的。
  当应用程序的窗口接收到键盘输入焦点时,Windows会向它发送一条WM-QUERYNEWPALETTE消息,让它设置自己的逻辑调色板,此时Windows会在系统调色板中尽量多地加入该应用程序需要的颜色,并生成相应的映射关系。接着Windows会向系统中所有的覆盖型窗口和顶级窗口(包括拥有键盘输入焦点的窗口)发送一条WM-PALETTECHANGED消息,让它们设置逻辑调色板和重绘客户区,以便能更充分地利用系统调色板,已拥有键盘输入焦点的窗口不应再处理这条消息,以避免出现死循环。

2、OpenGL的颜色表示与转换
  OpenGL内部用浮点数来表示和处理颜色,红绿蓝和Alpha值这四种成份每种的最大值为1.0,最小值为0.0。在256色模式下,OpenGL把一个象素颜色的内部值按线性关系转换为8比特(Bit)来输出到屏幕上,其中红色占最低位的3比特,绿色占中间的3比特,蓝色占最高位的2比特,Windows将这个8比特值看作逻辑调色板的索引值。例如OpenGL的颜色值(1.0、0.14、0.6667)经过转换后二进制值为10001111(红色为111、绿色为001、蓝色为10),即第143号调色板,该调色板指定的颜色的RGB值应与(1.0、0.14、0.6667)有相同的比率,为(255、36、170),如果不是该值,那么显示出来的颜色就会有误差。

3、调色板的生成算法
  很明显,OpenGL输出的8比特值中直接表明了颜色的组成,为了使图形显示正常,我们应以线性关系来设置逻辑调色板,使其索引值直接表明颜色的组成。因此生成调色板时,把索引值从低位到高位分成3-3-2共三个部分,将每一部分映射到0 — 255中去,这样3比特映射为{0、36、73、109、146、182、219、255},2比特映射为{0、85、170、255},最后把三部分组合起来成为一种颜色。
  经过上面的处理后,256种颜色均匀分布在颜色空间中,并没有完全包含系统保留的20种颜色(只包含了7种),这意味着将会有数种颜色显示成一样,从而影响效果。一个较好的解决办法是按照最小均方误差的原则把13种系统颜色纳入到逻辑调色板中,具体的对应关系请参见后面的例子。
  从原理上来说,并非一定要使用线性映射,还可以用其它一些映射关系,如加入Gamma校正以便更能符合人眼的视觉特性,不过这些映射关系应用得并不广泛,在此不再讨论。

4、MFC应用程序中设置调色板的例子
  下面以一个简单的MFC应用程序为例来说明设置调色板的方法,使用的开发工具为Visual C++ 5.0。
  1)使用AppWizard生成一个拥有缺省选项的应用程序Sample,并在“Project//Settings...//Link”属性页中添加库模块:“opengl32.lib、glu32.lib、glaux.lib”。
  2)利用ClassWizard为CMainFrame添加处理WM-QUERYNEWPALETTE和WM-PALETTECHANGED两条消息的函数,并在函数体添加如下内容:

  void CMainFrame::OnPaletteChanged(CWnd *pFocusWnd)
  {
    CView *pView=GetActiveView(); // 取得活动的视
    // 把消息传递给活动视的消息处理函数
    if (pView)
      pView->SendMessage(WM-PALETTECHANGED,(WPARAM)(pFocusWnd->GetSafeHwnd()),(LPARAM)0);
  }

  BOOL CMainFrame::OnQueryNewPalette()
  {
    CView *pView=GetActiveView();
    if (pView)
      return pView->SendMessage(WM-QUERYNEWPALETTE,(WPARAM)0,(LPARAM)0);
    return FALSE;
  }

  3)利用ClassWizard为CSampleView加入处理WM-QUERYNEWPALETTE和WM-PALETTECHANGED两条消息的函数,其中内容如下:

  voidCSampleView::OnPaletteChanged(CWnd *pFocusWnd)
  {
    // 如果自己拥有输入焦点,那么不处理这条消息
    if (pFocusWnd!=this)
      OnQueryNewPalette();
  }

  BOOLCSampleView::OnQueryNewPalette()
  {
    if (m-pPal)
    {
      CDC *pDC=GetDC();
      CPalette *pOldPal=pDC->SelectPalette(m-pPal,FALSE);
      UINTu=pDC->RealizePalette();
      ReleaseDC(pDC);
      // 某些颜色改变了,需要重画客户区
      if (u!=0)
        InvalidateRect(NULL,TRUE);
    }
    returnTRUE;
  }

  4)在SampleView.h中添加下列公有成员变量和函数的声明:

  CPalette *m-pPal;
  HGLRC m-hrc;
  static unsignedcharm-oneto8[2];
  static unsignedcharm-twoto8[4];      // 2比特转换数组
  static unsignedcharm-threeto8[8];     // 3比特转换数组
  static intm-defaultOverride[13];      // 需处理的13种系统保留颜色
  static PALETTEENTRYm-defaultPalEntry[20]; // 系统保留颜色

  BOOL CreateRGBPalette(HDC hDC);
  unsigned char ComponentFromIndex(inti,UINTnbits,UINTshift);

  并在SampleView.cpp中加入下列代码:

  unsigned char CSampleView::m-threeto8[8]={
    0,0111>>1,0222>>1,0333>>1,0444>>1,0555>>1,0666>>1, 0377
  };
  unsigned char CSampleView::m-twoto8[4]={ 0,0x55,0xaa,0xff};
  unsigned char CSampleView::m-oneto8[2]={ 0,255};

  // 按最小均方误差计算出的需用系统保留颜色替换的索引号
  int CSampleView::m-defaultOverride[13]={ 0,3,24,27,64,67,88,173,181,236,247,164,91};

  // 20种系统保留颜色值
  PALETTEENTRY CSampleView::m-defaultp alEntu[20]={
    {0,0, 0, 0,},{0x80, 0, 0, 0},{0, 0x80,0, 0},
    {0x80,0x80,0, 0},{0,0, 0x80, 0},{ 0x80, 0, 0x80, 0},
    { 0, 0x80, 0x80,0},{0xC0,0xC0,0xC0,0},{192,220,192,0}
    {166,202,240,0},{255,251,240,0},{160,160,164,0}
    {0x80,0x80,0x80, 0},{0xFF,0,0,0},{0xFF,0, 0xFF,}
    {0, 0xFF,0xFF,O},{0xFF,0xFF,0xFF,0}
  };

  unsigned char CSampleView::ComponentFromlndex(int i,UINT nbits, UINT shift)
  {
    unsigned char val;
    val=(unsigned char)(i>>shift);
    switch (nbits)
    {
    case 1:val&=0x1;
      return m-oneto8[val]
    case 2:val&=0x3;
      return m-twoto8[val]
    case 3:val&=0x7;
      return m-threeto8[val];
    default:return 0;
    }
  }

  BOOL CSampleView::CreateRGBPalette(HDC hDC)
  {
    PIXELFORMATDESCRIPTOR pfd;
    int n=GetPixelFormat(hDC);
    DescribepixxelFornt(hDC, n, sizeof(PIXELFORMATDESCRIPTOR),&pfd);

    // 判断是否需要调色板,真彩模式下不需要
    if (!(pfd.dwflags &PFD-NEED-PALETTE))
      return FALSE;

    LOGPALETTE*pPAL=(LOGPALETTE*)malloc(sizeof(logpalette)+256*sizeof(PALETTEENTRY));
     if (!pPal)
      return FALSE; // 内存不足返回

    pPal->palVersion=0x300;
    pPal->palNumEntries=256; // 逻辑调色板数量
    n=1<    for(int i =0; i>n; i++)
    {
      pPal->palPalEnty[i].peRed= ComponentFromlndex(i,pfd.cRedBits,pfd.cRedShift);
      pPal->palPalEnty[i].peGreen= ComponentFromlndex(i,pfd.cCREENbits,pfd.cGreenShift);
      pPal->palPalEnty[i].peBlue= ComponentFromlndex(i,pfd.cBlueBits,pfd.cBlueShift);
      pPal->palPalEntry[i].peFlags=0;
    }

    // 插入13种系统保留颜色
    if ((pfd.cColorBits==8)&&
      (pfd.cRedBits==3)&&(pfd.cRedShift==0)&&
      (pfd.cCreenBits==3)&&(pfd.cCreenBits==3)&&
      (pfd.cBlueBits==2)&&(pfd.cBlueBits==6))
    {
      for (int j=1; j<=12; j++)
        pPal->palPalEntry[m-defaulrOverride[j]]=m-default-palEntry[j];
    }

    if(m-pPal)
      delete m-pPal;
    m-pPal=new CPalette;
    BOOL bResult =m-pPal->CreatePalette(pPal);
    free(pPal);
    return bResult;
  }

  5)修改CSamplsView::OnCreate()函数:

  int CSample View::OnCreate(lpCreateStruct)==-1)
  return -1;
  CClientDC dc(this);

  // 填充象素格式描述符,请参考联机帮助
  PLXELFORMATDESCRIPTOR;
  memset (&pfd ,0,sixeof(PLXELFORMATDESCRIPTOR));
  pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
  pfd.nVersion =1;
  pfd.dwflags=PFD=DOUBLEBUFFER|PFD-SUPPORT-OPENGL|PFD-DRAW-TO-WINDOW;
  pfd.ipixlType=PFD-TYPE-RGBA;
  pfd.cColorBits=24;
  pfd.cColorBits=32;
  pfd.iLayerType=PED-MAIN-PLANE;

  int nPixlformat=ChoosePixelFormat(dc.m-hDC,nPixelFormat,&pfd);
  if (!bResult)
    return -1;

  // 创建rendering context.
  m-hrc=wglCreateContext(dc,m-hDC);
  if(!m-hrc)
    return -1;

  // 创建逻辑调色板
  CreateRGBPalette(dc.m-hDC);
  return 0;

  此外还要修改OnSize、OnDraw和preCreateWindow等函数,此处不再述,读者可以从联机帮助中找到。


摘自OGDEV

相关文章推荐

OpenGL(三) RGBA颜色设置

OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式。像素点附加颜色信息之后,就必须为每一个像素点额外分配一个内存空间保存该点的颜色信息,对于RGBA颜色模式,保存的数据直接代表了颜色,对...
  • dcrmg
  • dcrmg
  • 2016年11月07日 23:29
  • 2667

OpenGL颜色

几乎所有OpenGL应用目的都是在屏幕窗口内绘制彩色图形,所以颜色在OpenGL编程中占有很重要的地位。这里的颜色与绘画中的颜色概念不一样,它属于RGB颜色空间,只在监视器屏幕上显示。另外,屏幕窗口坐...

OpenGL中的颜色设置

RGB模式和RGBA模式    计算机屏幕的颜色属于RGB空间。    通常有RGB模式和RGBA模式,其中RGB模式有R、G、B三个分量,取值范围为0.0~1.0;而RGBA模式有R、G...

关于opengl的纹理和调色板问题

最近碰到了一点问题,关于图片载入和显示方面的。 自己的引擎显示方面是基于opengl来实现的。显示图片也就是画一个矩形,然后贴上纹理。并且采用了批量绘图方法,将顶点数据存入显存里。用到了glsl。不...

Android调色板的开发与RGB颜色的使用

项目简介:显示器的颜色是有三原色(RGB)构成的,显示使用中除了这三种参数外还有一个重要的参数:Alpha(透明度)。 项目的界面由图所示! 这就是界面package com.tabc...

使用 Palette 提取图片调色板

使用 Palette 支持包分析图片的像素数据,并为旨在补充此图片的背景和文本产生颜色样本。         调色板仅作为 Android 支持库中的模块提供,它不是核心框架的一部分。然而,目标平台...

【Qt5开发及实例】11、QPalette调色板使用

我做的这个不知道为什么有两个功能无法显示,也没有报错,我暂时是想不出什么好办法= = 实现目标 palette.h /** * 书本:【Qt5开发及实例】 * 功能:实现调色板的...

(译)Cocos2d_for_iPhone_1_Game_Development_Cookbook:1.12使用层来交换调色板

(译)Cocos2d_for_iPhone_1_Game_Development_Cookbook 著作权声明:本文由iam126 翻译,欢迎转载分享。 请尊重作者劳动,转载时保留该声 明...
  • iam126
  • iam126
  • 2012年04月04日 19:25
  • 1242

(一)调色板的使用

调色板又称颜色查找表(Look-Up Table, LUT),它是早期为解决显示设备不能同时显示丰富的颜色而提出的。通过为需要显示的颜色建立一个查找表(即调色板),就可以只存储像素颜色所对应的索引值...
  • ujn304
  • ujn304
  • 2012年08月09日 17:21
  • 1468

Android学习之5.0三姐妹调色板palette的使用

生命不息,学习不止,与大家共勉之。相信大家对5.0三姐妹都很熟悉了,分别是RecylerView,CardView,Palette,前二者以前都或多或少提到过,所以回来看了一下关于palette的使用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OpenGL中调色板的使用
举报原因:
原因补充:

(最多只允许输入30个字)