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");
}
