3D游戏从头编--第五回:索引顶点

::金点时空::


第五回:索引顶点

  "你能不能快点写呀?",一个做游戏策划的朋友在网上问我。没想到我写的这篇教程还是有人关心的嘛,呵呵,嘴里虽然不说什么,但心里还是有一点小小的得意^_^。
  本来打算这次讲摄象机的,但发现还有一个很重要的渲染方法没有讲,那就是索引顶点的渲染,这个要是不说的话,以后做到MAX插件导出的时候就会一头雾水了,为什么?因为我就是在还没有搞清楚这个的时候就去做插件了。
  什么是索引顶点呢?上次我们讲的渲染是直接把所有顶点的数据按顺序放到顶点缓冲中,然后每次取3个点的数据出来渲染成一个三角形,但是大家有没有考虑过,在一个3D模型中一个点可能要同时处于多个三角形面上,如果直接把顶点数据放进缓冲区,那么重复的顶点就会占用多余的内存。
  怎么解决这个问题呢?
  答案就是我们今天的主题--索引顶点!
  我们把顶点的具体数据和代表三角形的3个顶点的索引分开,顶点数据还是放到顶点缓冲区中,方法同上回。
  今天我们这样用5个顶点做例子:

  // 顶点原始数据
  CUSTOMVERTEX g_Vertices[] =
  {
     { -1.0f,-1.0f, 0.0f, 0xffff0000, }, // A红色
     { 1.0f,-1.0f, 0.0f, 0xff0000ff, }, // B兰色
     { 1.0f, 0.0f, 0.0f, 0xff00ff00, }, // C绿色
     { 0.0f, 1.0f, 0.0f, 0xffff00ff, }, // D洋红
     { -1.0f, 0.0f, 0.0f, 0xffffffff, }, // E白色
  };

  这五个点具体到图上是这样的:

   3D游戏从头编--第五回:索引顶点_第1张图片

  那索引数据放到哪里呢?我们需要用到一个叫做索引缓冲的东西,看程序:

  LPDIRECT3DINDEXBUFFER8 g_pIB = NULL; // 索引缓冲区

  // 创建索引缓冲区
  if( FAILED( g_pd3dDevice->CreateIndexBuffer( 6*sizeof(WORD),
                         0,
                         D3DFMT_INDEX16,
                         D3DPOOL_DEFAULT,
                         &g_pIB ) ) )
  {
    return E_FAIL;
  }


  第一个参数表示缓冲区大小,我们给出了6个点。
  第二个参数暂时不管,填0。
  第三个参数是索引的格式,我们用16位存储索引值(也就是说最大65535个顶点)。
  第四个参数表示通过什么方式创建,用缺省值就好了
  第五个参数返回缓冲区指针。

  创建的方法和上次讲的顶点缓冲大同小异,创建好了后,我们填入数据:

  // 填充顶点缓冲区
  WORD* pi;
  if( FAILED( g_pIB->Lock( 0, 12, (BYTE**)&pi, 0 ) ) )
    return E_FAIL;
  pi[0] = 0; // A
  pi[1] = 1; // B
  pi[2] = 2; // C
  pi[3] = 0; // A
  pi[4] = 3; // D
  pi[5] = 4; // E
  g_pIB->Unlock();

  好,六个点正好是两个三角形,按我们添的数据,这两个三角形应该是这样的:
3D游戏从头编--第五回:索引顶点_第2张图片
  

  现在我们就有了两个缓冲区,一个顶点缓冲区,放了5个原始顶点的数据;一个索引缓冲区,放了6个索引值,代表了两个三角形的面。
  OK,准备工作就绪了,最重要的是怎么把它们渲染出来,看程序:

  // --渲染图形--

  // 指定渲染源
  g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
  g_pd3dDevice->SetIndices(g_pIB, 0);

  // 指定自定义的FVF
  g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );

  // 渲染
  g_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 5, 0, 2);

  和上回的渲染部分比较一下,很明显,多了一个SetIndeces()的步骤。还有就是最后的渲染也由DrawPrimitive()变成了  DrawIndexedPrimivive()。
  DrawIndexedPrimivive()一共有五个参数,我们来简要说明一下(具体查dx8帮助)

  D3DPRIMITIVETYPE Type, // 渲染类型(点、线、面等)
  UINT MinIndex, // 顶点缓冲区中顶点的起始值,一般为0
  UINT NumVertices, // 顶点缓冲区中的顶点数量
  UINT StartIndex, // 索引缓冲区中索引的起始值
  UINT PrimitiveCount // 要渲染图形的数量

  具体程序运行的效果如下(万幸和设想的正好是一样):

   

  呼、呼……讲的都要累死了,你们差不多也应该明白了吧?如果这样都不行的话,那我就只好去准备绳子了,千万不要拦我……
  啊!才发现11点了都,我睡觉的时间到了,下回见

[下载本回完整源程序]

主页:http://www.gpgame.com
邮件:[email protected]
soft于2002-7-28晚


返回

金点时空 2000/7/28

www.gpgame.net

你可能感兴趣的:(游戏,工作,null,存储,byte,图形)