Программа имитации освещения Фонга с помощью мультитекстурирования
#include "stdafx.h"
#include "FS.h"
#include "GLScene.h"
#pragma warning(disable: 4305 4309 4244)
CGLScene::CGLScene()
{
rect.left = 0; rect.right = 640; rect.top = 0 ; rect.bottom = 480;
texdim = 128;
objangle[0] = 0.f; objangle[1] = 0.f;
objpos[0] = 0.f; objpos[1] = 0.f;
color[0] = 1.f; color[1] = 1.f; color[2] = 1.f; color[3] = 1.f;
zero[0] = 0.f; zero[1] = 0.f; zero[2] = 0.f; zero[3] = 1.f;
one[0] = 1.f; one[1] = 1.f; one[2] = 1.f; one[3] = 1.f;
lighttex = 0;
lightpos[0] = 0.f; lightpos[1] = 0.f; lightpos[2] = 1.f; lightpos[3] = 0.f;
lightchanged[0] = GL_TRUE; lightchanged[1] = GL_TRUE;
}
CGLScene::~CGLScene()
{ if (lighttex) delete [] lighttex; }
void CGLScene::Resize(int cx, int cy)
{
rect.left = 0; rect.top = 0;
rect.right = cx; rect.bottom = cy;
glViewport(0, 0, rect.right - rect.left, rect.bottom - rect.top);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-100., 100., -100., 100., 300., 600.);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0., 0., 450., 0., 0., 0., 0., 1., 0.);
}
void CGLScene::MakeHighlight(int intens)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix(); // предполагаем, что ModelView
glLoadIdentity();
glTranslatef(0.f, 0.f, -texdim/2.f);
glMatrixMode(GL_PROJECTION); // подготавливаемся к параллельному проецированию
glPushMatrix();
glLoadIdentity();
glOrtho(-texdim/2., texdim/2., -texdim/2., texdim/2., 0., texdim/2.);
glPushAttrib(GL_LIGHTING_BIT|GL_VIEWPORT_BIT); // изменяем размеры Viewport'a под размеры текстуры
glViewport(0, 0, texdim, texdim);
glEnable(GL_LIGHTING); // включаем освещение
glLightfv(GL_LIGHT0, GL_DIFFUSE, zero);
glLightfv(GL_LIGHT0, GL_POSITION, lightpos); // положение источника
glMateriali(GL_FRONT, GL_SHININESS, intens); // задаём степень светимости
glMaterialfv(GL_FRONT, GL_AMBIENT, zero); // остальные параметры -> ноль
glMaterialfv(GL_FRONT, GL_DIFFUSE, zero);
glMaterialfv(GL_FRONT, GL_SPECULAR, color); // цвет
glDisable(GL_TEXTURE_2D);
glCallList(1); // рисуем блик
glEnable(GL_TEXTURE_2D); // восстанавливаем установки GL
glPopAttrib();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glReadPixels(0, 0, texdim, texdim, GL_RGB, GL_FLOAT, lighttex); // читаем содержимое Framebuffer'a
glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); // присвоить созданной текстуре идентификатор
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texdim, texdim, GL_RGB, GL_FLOAT, lighttex);
}
void CGLScene::Render()
{
objangle[X]+=5.0f; objangle[Y]+=7.0f;
//objangle[X]=60; objangle[Y]=90;
static GLfloat ax=0.0f, ay=0.0f, az=0.0f;
GLfloat ca, sa;
GLfloat x=lightpos[0], y=lightpos[1], z=lightpos[2];
ax+=2.0f*M_PI/180.0f; ay+=3.0f*M_PI/180.0f; az+=4.0f*M_PI/180.0f;
ca=cos(az); sa=sin(az); // вращение вокруг оси OZ
lightpos[0]=ca - sa;
lightpos[1]=sa + ca;
lightchanged[0]=GL_TRUE; lightchanged[1]=GL_TRUE;
RenderTexHighlight(); // на каждом кадре - пересчёт блика
}
void CGLScene::RenderTexHighlight()
{
// положение источника изменилось
if(lightchanged[UPDATE_TEX]) {
MakeHighlight(128);
lightchanged[UPDATE_TEX] = GL_FALSE;
}
if(lightchanged[UPDATE_OGL])
{
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
lightchanged[UPDATE_OGL] = GL_FALSE;
}
glPushMatrix(); // предполагаем, что ModelView
glTranslatef(objpos[X], objpos[Y], 0.f);
glRotatef(objangle[Y], 0.f, 1.f, 0.f);
glRotatef(objangle[X], 1.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// рисуем диффузную составляющую света
glEnable(GL_LIGHTING);
glBindTexture(GL_TEXTURE_2D, SURF_TEX);
glCallList(2);
glDisable(GL_LIGHTING);
// блик
glClearColor(0.75, 0.75, 0.75, 1);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glDepthFunc(GL_LEQUAL);
glCallList(2);
glDepthFunc(GL_LESS);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_BLEND);
glPopMatrix(); //
SwapBuffers(wglGetCurrentDC());
glFlush();
}
void CGLScene::PrepareGL()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// параметры автогенерации координат текстуры
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glMateriali(GL_FRONT, GL_SHININESS, 128);
glCullFace(GL_BACK);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
lightchanged[UPDATE_TEX] = GL_TRUE;
lightchanged[UPDATE_OGL] = GL_TRUE;
// генерируем простую текстуру
int texwid = 128, texht = 128;
GLbyte *tex=new GLbyte[texwid * texht * 3];
GLbyte *ptr=tex;
for (int i = 0; i < texht; ++i) {
for (int j = 0; j < texwid; ++j) {
if ((i ^ j) & 8) {ptr[0] = 0xff; ptr[1] = 0xff; ptr[2] = 0xff;}
else {ptr[0] = i*512/texht;
ptr[1] = j*512/texwid;
ptr[2] = 196;}
ptr += 3;
}
}
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texwid, texht, GL_RGB, GL_UNSIGNED_BYTE, tex);
delete [] tex;
lighttex = new GLfloat[texdim * texdim * 3];
GLUquadricObj *q;
q=gluNewQuadric();
glNewList(1, GL_COMPILE);
gluSphere(q, (GLdouble)texdim/2., 50, 50);// сфера для блика
glEndList();
gluDeleteQuadric(q);
GLUquadricObj *quadric = gluNewQuadric();
gluQuadricTexture(quadric, GL_TRUE);
glNewList(2, GL_COMPILE);
gluSphere(quadric, 70., 20, 20);// сфера, выводимая в буфер кадра
glEndList();
gluDeleteQuadric(quadric);
glClearColor(1.0, 1.0, 1.0, 1.0);
}