Рисуем объёмное RGB-распределение
цветной картинки, используя OpenGL
Авторы: Pierre Alliez и
Magali Maziere.
Цель данного примера - показать, как можно цвета
обыкновенной картинки разпределить в объёме (в
данном случае в кубе). И при всём при том сделать
это при помощи OpenGL :) Не знаю зачем это надо, но
обезьянка на рисунке красивая :)
Рисунок 1: Наша цель отобразить
на экране в палитре RGB цветов это 24 битное BMP
цветное изображение интуитивным способом. OpenGL
поможет нам в этом.
Рисунок 2: Иллюстрирует две
точки обзора цветного распределения в диалоге.
Точка обзора изменяется левой кнопкой мышки,
которая позволяет вращать изображение в
координатах x/y, диалог может быть увеличен или
уменьшен и всплывающее меню позволяет загрузить
и просмотреть текущую картинку (Рисунок 3).
Рисунок 3: Два примера цветного
распределения в RGB кубе, видимое под двумя
точками обозрения. В частности красное
затемнение компонуется с носовой частью бабуина,
показанного на рисунке 1. Облако рисуется при
помощи GL_POINTS.
Рисунок 4: Всплывающее меню
позволяет загружать 24 битовую RGB картинку,
изменять бэкграунд OpenGL, и смотреть изображение в
диалоговом окне.
Инициализация движка рендеринга
Следующие строки инициализируют движок в
диалоге.
int CColorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
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);
glPointSize(1.0);
glPolygonMode(GL_FRONT,GL_LINE);
glPolygonMode(GL_BACK,GL_LINE);
glShadeModel(GL_SMOOTH);
BuildListCube();
BuildListCloud();
return 0;
}
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)
{
m_GLPixelIndex = 1;
if(!DescribePixelFormat(hDC,m_GLPixelIndex,
sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc))
return FALSE;
}
if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc))
return FALSE;
return TRUE;
}
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;
}
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 куб и облака рендерятся в двух отдельных
списках. Куб - всегда остаётся постоянным, в то
время как облако вычисляется каждый раз при
загрузке новой картинки.
void CColorDlg::OnPaint()
{
CPaintDC dc(this);
RenderScene();
SwapBuffers(dc.m_ps.hdc);
}
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);
::glCallList(2);
::glPopMatrix();
}
void CColorDlg::BuildListCube(BOOL list)
{
GLUquadricObj* pQuadric = gluNewQuadric();
if(list)
::glNewList(1,GL_COMPILE_AND_EXECUTE);
float x = m_Size;
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);
}
void CColorDlg::BuildListCloud()
{
TRACE("Build list cloud...");
unsigned int area = m_Image.GetWidth()
* m_Image.GetHeight();
TRACE("area : %d...",area);
if(area == 0 ||
m_Image.GetDepth() != 24)
return;
TRACE("alloc...");
unsigned char *pTable = new unsigned char[16777216];
memset(pTable,0,16777216);
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");
}
Downloads
Скачать демонстрационный проект -
530 Kb
Скачать исходник - 10 Kb
|