NEHE,估计知道OpenGL的人应该都会了解那么一些的。虽然导师让我们从OpenGL转向用VTK实现三维显示,不过这两个的原理其实差不多,因为都是基于计算机图形学的嘛。
Moving Bitmaps In 3D Space,其实实现这个“旋转星空”的效果(这个是我自己命名的,哈哈)主要就是以下步骤:
1.读入BMP图像,这里就是一个星星的图像;
2.将其变为二维纹理;
3.设置混合模式,因为BMP图像是四四方方的,要想弄出个星星的效果,必须让一部分变得透明;
4.0K,接下来就是在虚拟的三维空间里,在虚拟的矩形上贴这个星星生成的二维纹理了。
下面是详细的步骤说明,一起说说NEHE所使用的“算法”(姑且用算法吧,其实也够不上,因为星星移动其实不复杂的):
在实现以下4步之前,还是像往常一样啦,去洞庭散人的博客里,按照《基于MFC的OpenGL编程》Part 2 Setting up OpenGL on Windows把基本的东西先弄弄好。
1.好了,可以读BMP了,这是NEHE写的,感觉很严谨,或者说程序的健壮性比较好吧。
{
FILE *File = NULL;
if(!Filename)
{
return NULL;
}
File = fopen(Filename,"r");
if(File)
{
fclose(File);
return auxDIBImageLoad(Filename);
}
return NULL;
}
2.可以开始生成纹理的工作了,这个其实也没什么可说的,除了本人菜鸟,刚开始不知道怎么把CString转化为char*,呵呵,后来百度了下,用了其中最简单的一个方法,const char* ch = (LPCTSTR)Picname
{
bool Status = FALSE;
AUX_RGBImageRec *TextureImage[1];
memset(TextureImage,0,sizeof(void*)*1);
constchar* ch = (LPCTSTR)Picname;
if(TextureImage[0] = LoadBMP((char*)ch))
{
Status = TRUE;
glGenTextures(1,texture);
glBindTexture(GL_TEXTURE_2D,texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,3,TextureImage[0]->sizeX,
TextureImage[0]->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,
TextureImage[0]->data);
}
if(TextureImage[0])
{
if(TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
return Status;
}
3.\(^o^)/,设置混合模式啦,搞出个透明的效果的代码就在这里啦。貌似在NEHE的教程中没有glDepthMask(GL_FALSE)这一句,结果就不透明了,呵呵,但是它的程序直接拷贝到一个win32 console application里编译运行的时候又是一切OK的,不过这个没什么关系,参考了下红宝书,找出上面这句话添上,就没问题了。
{
if (!LoadGLTextures("Star.bmp")) // Jump To Texture Loading Routine
{
return FALSE; // If Texture Didn't Load Return FALSE
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
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);
glDepthMask (GL_FALSE);
for (int loop=0; loop<num; loop++)
{
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
}
4.在做显示在前嘛,先看看其中使用的数据结构吧。旁边的注释说得很清楚了。
{
int r, g, b; // Stars Color
GLfloat dist, // Stars Distance From Center
angle; // Stars Current Angle
}
stars;
进入正题吧,显示之。我觉得他用的显示过程还是应该说一下的。首先,glLoadIdentity(),这个函数,我以前都是不注意的,虽然很多地方都出现过,都没有去查,这个函数其实相当于初始化,将表示坐标的那个Matrix变成对角线为1,其余为0的4X4矩阵;然后转到屏幕后深度15的地方;接着绕X轴旋转tilt = 90°,绕Y轴旋转,这个角度,是各个STAR随机生成的。角度转好了之后再移动,距离dist也因星星而异,因为图片是片面的所以角度需要转回去。dist是从5.0递减到0,然后再重复。为了显示旋转的效果,坐标又绕Z轴旋转spin度,这个参数的设置时让所有的星星都旋转起来,即星星旋转的角速度。然后画星星。这部分的代码的功能,就是让星星从距离(0,0,-15)为5的地方向(0,0,-15)移动。在这个代码后面贴上运动控制和随机数生成的代码吧。
for (int loop=0; loop<num; loop++) // Loop Through All The Stars
{
glLoadIdentity(); // Reset The View Before We Draw Each Star
glTranslatef(0.0f,0.0f,-15.0f); // 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
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();
}
NEHE所写的程序并不是基于MFC的,我在这里把变量的变化放在OnTimer里面,这样的话程序可以正常运行。如果照搬NEHE,写在上面的代码后面,图像是动不了的。
{
// TODO: Add your message handler code here and/or call default
for(int loop =0; loop < num; loop ++)
{
spin+=0.01f;
star[loop].angle+=float(loop)/num;
star[loop].dist-=0.01f;
if (star[loop].dist<0.0f)
{
star[loop].dist+=5.0f;
star[loop].r=rand()%256;
star[loop].g=rand()%256;
star[loop].b=rand()%256;
}
}
InvalidateRect(NULL,FALSE);
CView::OnTimer(nIDEvent);
}
效果图也贴上吧,和NEHE的其实一样。