NeHe 系列教程之九: 在3D空间中移动位图
英文教程地址:lesson09
本课基于第一课的代码, 利用颜色混合的方法,将一个黑白纹理与随机颜色进行混合,产生绚丽的效果。
首先是定义相关变量和数据结构,如下所示:
namespace {
bool twinkle; // Twinkling Stars
bool tp; // 'T' Key Pressed?
const int num = 50; // Number Of Stars To Draw
typedef struct // Create A Structure For Star
{
int r, g, b; // Stars Color
GLfloat dist; // Stars Distance From Center
GLfloat angle; // Stars Current Angle
}stars; // Structures Name Is Stars
stars star[num]; // Make 'star' Array Of 'num' Using Info From The Structure
GLfloat zoom=-15.0f; // Viewing Distance Away From Stars
GLfloat tilt=90.0f; // Tilt The View
GLfloat spin; // Spin Twinkling Stars
GLuint loop; // General Loop Variable
GLuint texture[1]; // Storage For One Texture
}
加载纹理的代码跟之前课程代码类似。
然后是初始化代码:
void MyGLWidget::initializeGL()
{
loadTextures();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // Enables Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
// glEnable(GL_DEPTH_TEST); // Enables Depth Testing
// glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set The Blending Function For Translucency
glEnable(GL_BLEND); // Enable Blending
for (loop=0; loop<num; loop++) // Create A Loop That Goes Through All The Stars
{
star[loop].angle=0.0f; // Start All The Stars At Angle Zero
star[loop].dist=(float(loop)/num)*5.0f; // Calculate Distance From The Center
star[loop].r=rand()%256; // Give star[loop] A Random Red Intensity
star[loop].g=rand()%256; // Give star[loop] A Random Green Intensity
star[loop].b=rand()%256; // Give star[loop] A Random Blue Intensity
}
}
注意,开启混合的时候要关闭深度测试。
接着是绘制代码,如下所示:
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture
for (loop=0; loop<num; loop++) // Loop Through All The Stars
{
glLoadIdentity(); // Reset The View Before We Draw Each Star
glTranslatef(0.0f,0.0f,zoom); // Zoom Into The Screen (Using The Value In 'zoom')
glRotatef(tilt,1.0f,0.0f,0.0f); // Tilt The View (Using The Value In 'tilt')
glRotatef(star[loop].angle,0.0f,1.0f,0.0f); // Rotate To The Current Stars Angle
glTranslatef(star[loop].dist,0.0f,0.0f); // Move Forward On The X Plane
glRotatef(-star[loop].angle,0.0f,1.0f,0.0f); // Cancel The Current Stars Angle
glRotatef(-tilt,1.0f,0.0f,0.0f); // Cancel The Screen Tilt
if (twinkle) // Twinkling Stars Enabled
{
// Assign A Color Using Bytes
glColor4ub(star[(num-loop)-1].r,star[(num-loop)-1].g,star[(num-loop)-1].b,255);
glBegin(GL_QUADS); // Begin Drawing The Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd(); // Done Drawing The Textured Quad
}
glRotatef(spin,0.0f,0.0f,1.0f); // Rotate The Star On The Z Axis
// Assign A Color Using Bytes
glColor4ub(star[loop].r,star[loop].g,star[loop].b,255);
glBegin(GL_QUADS); // Begin Drawing The Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd(); // Done Drawing The Textured Quad
spin+=0.01f; // Used To Spin The Stars
star[loop].angle += float(loop)/num; // Changes The Angle Of A Star
star[loop].dist -= 0.01f; // Changes The Distance Of A Star
if (star[loop].dist<0.0f) // Is The Star In The Middle Yet
{
star[loop].dist += 5.0f; // Move The Star 5 Units From The Center
star[loop].r = rand()%256; // Give It A New Red Value
star[loop].g = rand()%256; // Give It A New Green Value
star[loop].b = rand()%256; // Give It A New Blue Value
}
}
}
按键T 的处理, 当按下T键时,会有闪烁效果,且亮度更大:
void MyGLWidget::keyReleaseEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_T:
tp = false;
break;
default:
QGLWidget::keyReleaseEvent(e);
}
}
void MyGLWidget::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_F:
fullscreen = !fullscreen;
if (fullscreen) {
showFullScreen();
} else {
resize(640, 480);
showNormal();
}
break;
case Qt::Key_T:
if (!tp) {
tp = TRUE;
twinkle = !twinkle;
}
break;
case Qt::Key_Up:
tilt -= 0.5f;
break;
case Qt::Key_Down:
tilt += 0.5f;
break;
case Qt::Key_PageUp:
zoom -= 0.2f;
break;
case Qt::Key_PageDown:
zoom += 0.2f;
break;
case Qt::Key_Escape:
QMessageBox::StandardButton reply;
reply = QMessageBox::question(NULL, "NeHe",
"Do you want to exit?",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes);
if (reply == QMessageBox::Yes) {
qApp->quit();
}
break;
default:
QGLWidget::keyPressEvent(e);
break;
}
}
运行效果如下所示: (T 键按下)