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");
}
Оставить комментарий
Оставлять комментарии могут только зарегистрированные пользователи.
Если вы не являетесь зарегистрированным пользователем, то вам необходимо зарегистрироваться. Регистрация бесплатна. Если вы уже зарегистрированы на CodeNet, то вам необходимо ввести логин и пароль в верхней (Alt-U) части страницы.
