r1 - 18 Mar 2009 - 01:34:04 - FeynmanHejianYou are here: TWiki >  Products Web > MG3dPG > MG3dPGV101Section23

场景编程实例

  • 下面将展示一个64个正方体物体在同一个场景中运动的例子,本例程使用浮点数据描述,但是可以替换成定点数运算。在本例中,三维空间中共有64个规则排列的正方体,他们依照统一的轨迹在空间内做旋转和位移运动。在运动的过程中,立方体之间会因为Z值不同而产生遮挡,场景接口将自动为我们完成隐面消除的工作。
  • mG3d作为MiniGUI的组件,应该依照MiniGUI消息驱动的方式进行编程,场景API的使用也不例外。下面的例子中,我们将在窗口的消息处理函数中调用mG3d的场景API完成对多边行生成及渲染工作。

#define MAX_CUBES 4
static HDC hdc, hSceneDC;

int mg3dSceneTestProc(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam)
{
        switch (msg)
        {
                case MSG_CREATE:
                {
                        /* ...... */    
                        
                        /* 得到窗口的DC句柄 */        
                        hdc = GetClientDC(hWnd);
                        
                        /* 为场景建立Memory DC。
                        mG3d组件的多边形的渲染等工作都是在Memory DC中完成的,
                        当在Memory DC中完成了一帧的渲染后,利用BitBlt函数        
                        将Memory DC中的画面拷贝到窗口的DC中加以显示。
                        下面建立的是一个16位色的Memory DC且尺寸与窗口的大小一致 
                        */
                        hSceneDC = CreateMemDC(SCREEN_W, SCREEN_H, 16,
                        MEMDC_FLAG_SWSURFACE, 0, 0, 0, 0);
                        
                        /* 建立场景,因为每个立方体由6个面组成,每个面又由4个顶点组成,
                        一共有64个正方体,所以场景中最多顶点数目为(第一个参数):
                        24 * MAX_CUBES * MAX_CUBES * MAX_CUBES = 6*4*4*4*4;
                        因为每个多边行有六个面,所以场景中最多多边形数目为:
                        6 * MAX_CUBES * MAX_CUBES * MAX_CUBES  = 6*4*4*4 
                        */
                        mg3dCreateScene(24 * MAX_CUBES * MAX_CUBES * MAX_CUBES,
                        6 * MAX_CUBES * MAX_CUBES * MAX_CUBES);
                        
                        /* 设置视口 */                                       
                        mg3dSetProjectionViewport(0, 0, SCREEN_W, SCREEN_H);
                        
                        /* ...... */
                        break;
                }
        }

  • 场景建立了之后,我们可以在消息处理函数中响应某个消息来启动多边形的生成和渲染的流程。本例中,我们响应了键盘按下的消息(光标的左键按下)。

case MSG_KEYDOWN:
{
        if (wParam != SCANCODE_CURSORBLOCKLEFT) {
                break;
        }
        
        /* ...... */        
        
        /* 在一个循环中完成多边形的生成和渲染*/
        for ( ; ; ) {
                
                /* 每渲染一帧之前,应当清空Memory DC
                中的内容 */
                SetBrushColor(hSceneDC, PIXEL_black);
                FillBox(hSceneDC, 0, 0, WNDWIDTH, WNDHEIGHT);
                
                /* 每渲染一帧之前需要初始化场景一次 */  
                mg3dClearScene(hSceneDC);
                
                /* 根据旋转角度的增量生成新的旋转变换矩阵 */
                mg3dGetRotMatrixF(&matrix2, rx, ry, 0);
                mg3dGetRotMatrixF(&matrix3, 0, rot, 0);
                
                /* 64个正方体在空间中的排列方式为:X,Y,Z轴方向上各有4个正方体,共计64个。
                下面的循环针对每一个正方体来计算它的平移运动的偏移量,生成每个正方体最终的运顶变换矩阵。
                在这个例子中,所有正方体共享相同的旋转矩阵,但是每个正方体有自己独特的平移矩阵。
                每次循环都是针对一个正方体,对于同一个正方体上的顶点,它们的变换矩阵是一样的。
                draw_cube函数的主要作用是将一个正方体的六个面加入多边行渲染列表,此时并不真正的渲染
                多边形。
                */
                for (k = MAX_CUBES - 1; k >= 0; k--) {
                        for (j = 0; j < MAX_CUBES; j++) { 
                                for (i = 0; i < MAX_CUBES; i++) {
                                        
                                        /* 得到每个正方体的平移矩阵 */                   
                                        mg3dGetTranslationMatrixF(&matrix1, j*40-MAX_CUBES*20+20,
                                        i*40-MAX_CUBES*20+20, tz+k*40);
                                        
                                        /* 将平移矩阵和上面两个旋转矩阵做乘法,
                                        得到最终的变换矩阵,注意矩阵乘法的相乘顺序 */
                                        mg3dMatrixMulF(&matrix2, &matrix1, &matrix);
                                        mg3dMatrixMulF(&matrix, &matrix3, &matrix);
                                        
                                        draw_cube(&matrix, 6);
                                }
                        }
                }
                
                /* 渲染一幅场景,此时场景中所有的多边形将被真正的“画”在Memory DC上 */
                mg3dRenderScene();
                
                /* 把场景Memory DC中的内容拷贝到窗口DC中,窗口将显示这一帧 */
                BitBlt(hSceneDC, 0, 0, WNDWIDTH, WNDHEIGHT, hdc, 0, 0, 0);
                
                /* 重新计算旋转角度,位移等增量 */
                tz -= 2;
                if (!tz) tz = 40;
                rx += 4;
                ry += 4;
                rot += inc;
                if ((rot >= 25) || (rot <= -25)) inc = -inc;
                
                /* ...... */
        }
        break;
}

  • 先来详细解释一下draw_cube函数中所做的工作。draw_cube针对每一个正方体做处理,而不是针对多边形,它的主要任务是完成多边形的三维空间裁减,投影并加入多边形渲染列表。函数的第一个参数表示需要应用在正方体6个顶点上的变换矩阵,第二个参数表明一个正方体是由多少个多边形组成的,默认是6个。

void draw_cube(mg3dMatrixf *matrix, int num_poly)
{
        int i, j, nv;
        /* out数组是提供给mg3dClipF函数运行时需要的临时缓冲区 */
        int out[12];
        
        /* 正方体一共有6个面,循环每次完成一个面的运算 */
        for (i = 0; i < num_poly; i++) {
                
                /* 每个面都有4个顶点,对每个顶点应用刚才求得的变换矩阵 */
                for (j = 0; j < 4; j++) {
                        v[j] = vertex[cube[i].v[j]];
                        mg3dApplyMatrixF(matrix, v[j].x, v[j].y, v[j].z,
                        &v[j].x, &v[j].y, &v[j].z);
                }
                
                /* 对正方体的每个面做3d裁剪,MG3D_POLYTYPE_GCOL是渲染类型,
                0.1, 1000.表明裁剪的边界;4表明被裁剪的多边形初始有4个顶点,
                pv是保存多边形顶点的数组的指针,pvout指向是裁剪后的多边形顶点数组
                pvtmp,out都是为mg3dClipF提供的临时缓冲区。
                
                值得注意的是,由于多边形裁剪后的顶点数可能大于其原有顶点数,所以
                提供的保存运算结果的数组和临时缓冲区应该尽量的大。
                
                mg3dClipF的返回值就是裁剪后多边形的顶点数。   
                */
                nv = mg3dClipF(hSceneDC, MG3D_POLYTYPE_GCOL, 
                0.1, 1000., 4, 
                (const mg3dVpf**)pv, pvout,
                pvtmp, out);
                
                if (nv) {
                        
                        /* 把裁剪后的各个顶点投影到二维屏幕上 */
                        for (j = 0; j < nv; j++) {
                                mg3dPerspProjectF(vout[j].x, vout[j].y, vout[j].z, 
                                &(vout[j].x), &(vout[j].y));
                        }
                        
                        /* 把这个多边行加入到待渲染多边形链表中 */
                        if (mg3dPolygonZNormalF(&vout[0], &vout[1], &vout[2]) > 0) { 
                                mg3dScenePolygonF(MG3D_POLYTYPE_GCOL, hTextureDC, nv, pvout);
                        }
                }
        }
}

  • 当场景不需要被使用的时候,应当及时的释放所占用的资源。

/* ...... */
/* 释放DC,销毁场景,释放资源 */     
ReleaseDC(hdc);
ReleaseDC(hSceneDC);
mg3dDestroyScene();

-- FeynmanHejian - 17 Mar 2009

Edit | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r1 | More topic actions
 
Powered by TWiki
This site is powered by the TWiki collaboration platformCopyright © by the Feynman Software and/or the contributing authors. All material on this collaboration platform is the property of Feynman Software and/or the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback