• MFC环境下实现旋转星空效果,以及在这之中遇到的一些问题。(COPY NEHELESSON9)


    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写的,感觉很严谨,或者说程序的健壮性比较好吧。

    AUX_RGBImageRec* COpenglDemoView::LoadBMP(char* Filename)
    {
    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 COpenglDemoView::LoadGLTextures(CString 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的,不过这个没什么关系,参考了下红宝书,找出上面这句话添上,就没问题了。

    BOOL COpenglDemoView::InitTex(void)
    {
    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.在做显示在前嘛,先看看其中使用的数据结构吧。旁边的注释说得很清楚了。

    typedef struct// Create A Structure For Star
    {
    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)移动。在这个代码后面贴上运动控制和随机数生成的代码吧。

    代码
    glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture

    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,写在上面的代码后面,图像是动不了的。

    void COpenglDemoView::OnTimer(UINT_PTR nIDEvent)
    {
    // 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的其实一样。

  • 相关阅读:
    maven 设置日志级别
    浏览器工作原理:浅析浏览器中的页面
    浏览器工作原理:浅析浏览器中的页面
    解决uniapp的websocket连接在web和安卓正常,iOS连接不上的问题
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浏览器工作原理:浅析页面循环系统
    浅析如何使用WebSocket、SockJS、STOMP实现消息实时通讯功能:websocket/SocketJS/Stomp是什么及三者的关系、stomp协议格式、如何开启stomp、如何处理客服端发送的stomp、如何发消息给客服端、如何在任何地方发消息、如何给目标或指定用户发消息
    解决sockjs、stomp在uni-app端使用的坑
    浏览器工作原理:浅析页面循环系统
  • 原文地址:https://www.cnblogs.com/unsigned/p/1698520.html
Copyright © 2020-2023  润新知