![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
Demo8
![](/Images/OutliningIndicators/None.gif)
bool twinkle; // Twinkling Stars
bool tp; // 'T' Key Pressed?
![](/Images/OutliningIndicators/None.gif)
const num=50; // Number Of Stars To Draw
![](/Images/OutliningIndicators/None.gif)
typedef struct // Create A Structure For Star
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
int r, g, b; // Stars Color
GLfloat dist, // Stars Distance From Center
angle; // Stars Current Angle
}
stars;
stars star[num]; // Need To Keep Track Of 'num' Stars
![](/Images/OutliningIndicators/None.gif)
GLfloat zoom=-15.0f; // Distance Away From Stars
GLfloat tilt=90.0f; // Tilt The View
GLfloat spin; // Spin Stars
![](/Images/OutliningIndicators/None.gif)
GLuint loop; // General Loop Variable
GLuint texture[1]; // Storage For One textures
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
if (!LoadGLTextures()) // Jump To Texture Loading Routine
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return FALSE; // If Texture Didn't Load Return FALSE
}
![](/Images/OutliningIndicators/InBlock.gif)
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
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);
![](/Images/OutliningIndicators/InBlock.gif)
for (loop=0; loop<num; loop++)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
star[loop].angle=0.0f;
star[loop].dist=(float(loop)/num)*5.0f;
star[loop].r=rand()%256;
star[loop].g=rand()%256;
star[loop].b=rand()%256;
}
return TRUE; // Initialization Went OK
}
![](/Images/OutliningIndicators/None.gif)
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture
![](/Images/OutliningIndicators/InBlock.gif)
for (loop=0; loop<num; loop++) // Loop Through All The Stars
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//glPushMatrix();
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)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
glColor4ub(star[(num-loop)-1].r,star[(num-loop)-1].g,star[(num-loop)-1].b,255);
glBegin(GL_QUADS);
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();
}
![](/Images/OutliningIndicators/InBlock.gif)
glRotatef(spin,0.0f,0.0f,1.0f);
glColor4ub(star[loop].r,star[loop].g,star[loop].b,255);
glBegin(GL_QUADS);
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();
![](/Images/OutliningIndicators/InBlock.gif)
spin+=0.01f;
star[loop].angle+=float(loop)/num;
star[loop].dist-=0.01f;
if (star[loop].dist<0.0f)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
star[loop].dist+=5.0f;
star[loop].r=rand()%256;
star[loop].g=rand()%256;
star[loop].b=rand()%256;
}
//glPopMatrix();
}
return TRUE;
}
这里设置OpenGL的渲染方式不打算使用深度测试,如果使用第一课的代码的话,请确认是否已经去掉了glDepthFunc(GL_LEQUAL);和glEnable(GL_DEPTH_TEST);两行。否则,所见到的效果将会一团糟。这里我们使用了纹理映射,可以注意到我们通过混色来启用了纹理映射。
这里我们使用的颜色设置函数是glColor4ub,而不是以前的glColor
4f
。ub意味着参数是Unsigned Byte型的。一个byte的取值范围是0~255。
不过代码中有一处我没有看明白什么意思:
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
教材上给的解释如下,捉摸不透:
现在我们来移动星星。星星开始时位于屏幕的中心。我们要做的第一件事是把场景沿Y轴旋转。如果我们旋转90度的话,X轴不再是自左至右的了,他将由里向外穿出屏幕。为了让大家更清楚些,举个例子。假想您站在房子中间。再设想您左侧的墙上写着-x,前面的墙上写着-z,右面墙上就是+x咯,您身后的墙上则是+z。加入整个房子向右转90度,但您没有动,那么前面的墙上将是-x而不再是-z了。所有其他的墙也都跟着移动。-z出现在右侧,+z出现在左侧,+x出现在您背后。神经错乱了吧?通过旋转场景,我们改变了x和z平面的方向。
第二行代码沿x轴移动一个正值。通常x轴上的正值代表移向了屏幕的右侧(也就是通常的x轴的正向),但这里由于我们绕y轴旋转了坐标系,x轴的正向可以是任意方向。如果我们转180度的话,屏幕的左右侧就镜像反向了。因此,当我们沿 x轴正向移动。
glRotatef(star[loop].angle,
0.0f
,
1.0f
,
0.0f
); // 旋转至当前所画星星的角度
glTranslatef(star[loop].dist,
0.0f
,
0.0f
); // 沿X轴正向移动
接着的代码带点小技巧。星星实际上是一个平面的纹理。现在您在屏幕中心画了个平面的四边形然后贴上纹理,这看起来很不错。一切都如您所想的那样。但是当您当您沿着y轴转上个90度的话,纹理在屏幕上就只剩右侧和左侧的两条边朝着您。看起来就是一条细线。这不是我们所想要的。我们希望星星永远正面朝着我们,而不管屏幕如何旋转或倾斜。
我们通过在绘制星星之前,抵消对星星所作的任何旋转来实现这个愿望。您可以采用逆序来抵消旋转。当我们倾斜屏幕时,我们实际上以当前角度旋转了星星。通过逆序,我们又以当前角度“反旋转”星星。也就是以当前角度的负值来旋转星星。就是说,如果我们将星星旋转了10度的话,又将其旋转-10度来使星星在那个轴上重新面对屏幕。下面的第一行抵消了沿y轴的旋转。然后,我们还需要抵消掉沿x轴的屏幕倾斜。要做到这一点,我们只需要将屏幕再旋转-tilt倾角。在抵消掉x和y轴的旋转后,星星又完全面对着我们了。
glRotatef(-star[loop].angle,
0.0f
,
1.0f
,
0.0f
); // 取消当前星星的角度
glRotatef(-tilt,
1.0f
,
0.0f
,
0.0f
); // 取消屏幕倾斜