OpenGL - Распределение компонент RGB в 3D пространстве
www.исходники.ru
Цель данного примера - показать, как можно цвета обыкновенной картинки разпределить в объёме (в данном случае в кубе). И при всём при том сделать это при помощи OpenGL :) Не знаю зачем это надо, но обезьянка на рисунке красивая :)
Рисунок 1: Наша цель отобразить на экране в палитре RGB цветов это 24 битное BMP цветное изображение интуитивным способом. OpenGL поможет нам в этом.

Рисунок 2: Иллюстрирует две точки обзора цветного распределения в диалоге. Точка обзора изменяется левой кнопкой мышки, которая позволяет вращать изображение в координатах x/y, диалог может быть увеличен или уменьшен и всплывающее меню позволяет загрузить и просмотреть текущую картинку (Рисунок 3).

Рисунок 3: Два примера цветного распределения в RGB кубе, видимое под двумя точками обозрения. В частности красное затемнение компонуется с носовой частью бабуина, показанного на рисунке 1. Облако рисуется при помощи GL_POINTS.

Рисунок 4: Всплывающее меню позволяет загружать 24 битовую RGB картинку, изменять бэкграунд OpenGL, и смотреть изображение в диалоговом окне.

Инициализация движка рендеринга
Следующие строки инициализируют движок в диалоге.
//********************************* // OnCreate //********************************* int CColorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Инициализируем движок OpenGL HWND hWnd = GetSafeHwnd(); HDC hDC = ::GetDC(hWnd); if(SetWindowPixelFormat(hDC)==FALSE) return 0; if(CreateViewGLContext(hDC)==FALSE) return 0; // Линии антиалиасинга glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT,GL_NICEST); glLineWidth(1.5); // required glPointSize(1.0); glPolygonMode(GL_FRONT,GL_LINE); glPolygonMode(GL_BACK,GL_LINE); glShadeModel(GL_SMOOTH); // Вычисленные списки дисплея BuildListCube(); BuildListCloud(); return 0; } //********************************************** // OpenGL //********************************************** BOOL CColorDlg::SetWindowPixelFormat(HDC hDC) { PIXELFORMATDESCRIPTOR pixelDesc; pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); pixelDesc.nVersion = 1; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE; pixelDesc.iPixelType = PFD_TYPE_RGBA; pixelDesc.cColorBits = 32; pixelDesc.cRedBits = 8; pixelDesc.cRedShift = 16; pixelDesc.cGreenBits = 8; pixelDesc.cGreenShift = 8; pixelDesc.cBlueBits = 8; pixelDesc.cBlueShift = 0; pixelDesc.cAlphaBits = 0; pixelDesc.cAlphaShift = 0; pixelDesc.cAccumBits = 64; pixelDesc.cAccumRedBits = 16; pixelDesc.cAccumGreenBits = 16; pixelDesc.cAccumBlueBits = 16; pixelDesc.cAccumAlphaBits = 0; pixelDesc.cDepthBits = 32; pixelDesc.cStencilBits = 8; pixelDesc.cAuxBuffers = 0; pixelDesc.iLayerType = PFD_MAIN_PLANE; pixelDesc.bReserved = 0; pixelDesc.dwLayerMask = 0; pixelDesc.dwVisibleMask = 0; pixelDesc.dwDamageMask = 0; m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc); if(m_GLPixelIndex==0) // выбираем default { m_GLPixelIndex = 1; if(!DescribePixelFormat(hDC,m_GLPixelIndex, sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)) return FALSE; } if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc)) return FALSE; return TRUE; } //********************************* // CreateViewGLContext //********************************* BOOL CColorDlg::CreateViewGLContext(HDC hDC) { m_hGLContext = wglCreateContext(hDC); if(m_hGLContext==NULL) return FALSE; if(wglMakeCurrent(hDC,m_hGLContext)==FALSE) return FALSE; return TRUE; } //********************************* // OnDestroy //********************************* void CColorDlg::OnDestroy() { CDialog::OnDestroy(); if(wglGetCurrentContext() != NULL) wglMakeCurrent(NULL,NULL); if(m_hGLContext != NULL) { wglDeleteContext(m_hGLContext); m_hGLContext = NULL; } glDeleteLists(1,2); }
РЕНДЕРИНГ
RGB куб и облака рендерятся в двух отдельных списках. Куб - всегда остаётся постоянным, в то время как облако вычисляется каждый раз при загрузке новой картинки.
//********************************* // OnPaint //********************************* void CColorDlg::OnPaint() { // ** Draw scene ** CPaintDC dc(this); RenderScene(); SwapBuffers(dc.m_ps.hdc); // двойной буфер } //********************************* // RenderScene //********************************* void CColorDlg::RenderScene() { ::glClearColor((float)GetRValue(m_BackColor)/255.0f, (float)GetGValue(m_BackColor)/255.0f, (float)GetBValue(m_BackColor)/255.0f,1.0f); ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ::glPushMatrix(); ::glTranslated(0.0,0.0,-8.0); ::glRotated(m_xRotate, 1.0, 0.0, 0.0); ::glRotated(m_yRotate, 0.0, 1.0, 0.0); ::glCallList(1); // cube ::glCallList(2); // clouds ::glPopMatrix(); } //*********************************************** // BuildList //*********************************************** void CColorDlg::BuildListCube(BOOL list) { GLUquadricObj* pQuadric = gluNewQuadric(); if(list) ::glNewList(1,GL_COMPILE_AND_EXECUTE); float x = m_Size; // RGB куб glBegin(GL_LINE_LOOP); glColor3ub(0,0,0); glVertex3d(-x,-x,-x); glColor3ub(255,0,0); glVertex3d(x,-x,-x); glColor3ub(255,255,0); glVertex3d(x,x,-x); glColor3ub(0,255,0); glVertex3d(-x,x,-x); glEnd(); glBegin(GL_LINE_LOOP); glColor3ub(0,0,255); glVertex3d(-x,-x,x); glColor3ub(255,0,255); glVertex3d(x,-x,x); glColor3ub(255,255,255); glVertex3d(x,x,x); glColor3ub(0,255,255); glVertex3d(-x,x,x); glEnd(); glBegin(GL_LINES); glColor3ub(0,0,0); glVertex3d(-x,-x,-x); glColor3ub(0,0,255); glVertex3d(-x,-x,x); glColor3ub(255,0,0); glVertex3d(x,-x,-x); glColor3ub(255,0,255); glVertex3d(x,-x,x); glColor3ub(255,255,0); glVertex3d(x,x,-x); glColor3ub(255,255,255); glVertex3d(x,x,x); glColor3ub(0,255,0); glVertex3d(-x,x,-x); glColor3ub(0,255,255); glVertex3d(-x,x,x); glEnd(); // Сферы glPolygonMode(GL_FRONT,GL_FILL); glPolygonMode(GL_BACK,GL_FILL); float radius = 0.1f; glPushMatrix(); glTranslated(-m_Size,-m_Size,-m_Size); glColor3ub(0,0,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,-m_Size,-m_Size); glColor3ub(255,0,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,m_Size,-m_Size); glColor3ub(0,255,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,-m_Size,m_Size); glColor3ub(0,0,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,m_Size,-m_Size); glColor3ub(255,255,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,m_Size,m_Size); glColor3ub(0,255,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,-m_Size,m_Size); glColor3ub(255,0,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,m_Size,m_Size); glColor3ub(255,255,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); if(list) ::glEndList(); gluDeleteQuadric(pQuadric); } //*********************************************** // BuildListCloud //*********************************************** void CColorDlg::BuildListCloud() { TRACE("Build list cloud..."); // Область изображения unsigned int area = m_Image.GetWidth() * m_Image.GetHeight(); TRACE("area : %d...",area); // Необходимо, чтобы картинка была 24 бита if(area == 0 || m_Image.GetDepth() != 24) return; // Максимум -> область отчётливых цветов / 2^24 // Эта таблица занимает прилично памати, но на короткое время TRACE("alloc..."); unsigned char *pTable = new unsigned char[16777216]; memset(pTable,0,16777216); // init 0 // Содержимое картинки unsigned int wb32 = m_Image.GetWidthByte32(); unsigned char *pData = m_Image.GetData(); // Строим новый список TRACE("build list..."); int nb = 0; ::glNewList(2,GL_COMPILE_AND_EXECUTE); glBegin(GL_POINTS); float tmp = 2.0f/255.0f*m_Size; for(unsigned int j=0;j<m_Image.GetHeight();j++) for(unsigned int i=0;i<m_Image.GetWidth();i++) { unsigned char b = pData[wb32*j+3*i]; unsigned char g = pData[wb32*j+3*i+1]; unsigned char r = pData[wb32*j+3*i+2]; if(!pTable[b*65536+g*256+r]) { glColor3ub(r,g,b); float x = -m_Size+(float)r*tmp; float y = -m_Size+(float)g*tmp; float z = -m_Size+(float)b*tmp; glVertex3d(x,y,z); pTable[b*65536+g*256+r] = 1; nb++; } } glEnd(); ::glEndList(); TRACE("%d points...",nb); TRACE("cleanup..."); delete [] pTable; TRACE("ok\n"); }