zoukankan      html  css  js  c++  java
  • Direct3D使用顶点缓存和索引缓存进行绘制

    1. 使用顶点缓存绘制静止图形

    效果图
    enter image description here

    1.0 模型表示

    • 本例中只有一个三角形mesh,需要三个顶点来描述。FVF顶点格式如下定义
    struct Vertex
    {
    	float _x, _y, _z, _rhw;
    	DWORD _color;
    	Vertex(float x, float y, float z, float rhw, DWORD color):
    				_x(x), _y(y), _z(z), _rhw(rhw), _color(color){}
    	static const DWORD FVF;
    };
    const DWORD Vertex::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
    
    • D3DFVF_XYZRHW和D3DFVF_XYZ的区别

      • D3DFVF_XYZRHW设置的坐标是屏幕坐标,客户区左上角为(0,0),不需要进行一系列变换,D3DFVF_XYZ设置的坐标必须经过一系列变换才能在屏幕上显示
      • D3DFVF_XYZRHW默认有光照,D3DFVF_XYZ默认没有光照。因此使用D3DFVF_XYZ时需要设置光照
      device->SetRenderState(D3DRS_LIGHTING, false);
      
    • 由于不需要进行各类坐标变换,因此只要直接设置顶点缓存即可

    IDirect3DVertexBuffer *pVB = NULL;
    Device->CreateVertexBuffer(3 * sizeof(Vertex),
    						   D3DUSAGE_WRITEONLY,
    						   Vertex::FVF,
    						   D3DPOOL_MANAGED,
    						   &pVB,
    						   NULL);
    //然后填充顶点缓存
    Vertex *vertices;
    pVB->Lock(0, 0, (void**)&vertices, 0); 
    //第三个参数传入了void**,意味着可能更改指针自身的值,而数组名指向的地址是不可以被更改的,因而上一行必须定义为指针,定义为数组会出错,下面开始填充
    vertices[0] = Vertex(400.0f, 150.0f, 0.0f, 1.0f, 0xffff0000);
    vertices[1] = Vertex(600.0f, 450.0f, 0.0f, 1.0f, 0xff00ff00);
    vertices[2] = Vertex(200.0f, 450.0f, 0.0f, 1.0f, 0xff0000ff);
    
    pVB->Unlock();
    
    • 参数中D3DUSAGE的取值

      • 0:默认属性,无附加属性
      • D3DUSAGE_DYNAMIC:将缓存设置为动态缓存
      • D3DUSAGE_POINTS:标记规定缓存用于储存点图元
      • D3DUSAGE_SOFTWAREPROCESSING:指定软件顶点运算方式
      • D3DUSAGE_WRITEONLY:规定程序对缓存的操作模式为”只写“
    • 至此完成了模型的定义,接下来就可以进行绘制了

    • 缓存区域

      • 创建缓存时,不使用D3DUSAGE_DYNAMIC标记的话,缓存默认为静态缓存,一般放置在显存中,这类缓存中的数据的处理速度极快,但对其进行IO操作则非常慢,因此这类储存区常用于储存不需经常访问或修改的数据,如地形数据。
      • 若是用来D3DUSAGE_DYNAMIC,则创建的是一块动态缓存,这类缓存常被放置在AGP/PCIe储存区中,AGP/PCIe储存区也是内存的一部分,但是可以通过AGP/PCIe通道直接访问,因此访问速度高于内存,如果程序需要频繁更新缓存内容,则应该使用这类缓存

    显卡缓存层次结构

    enter image description here

    1.1 绘制

    我们编制的D3D框架中,绘制图象的工作在Render函数中完成,Render的基本结构如下,我们的绘制代码就将填充在BeginScene和EndScene之间

    bool Render(float DeltaTime)
    {
    	Device->Clear(...);
    	if(Device->BeginScene())
    	{
    		//TODO: Drawing codes
    		Device->EndScene();
    	}
    	Device->Present(...);
    	return true;
    }
    
    • 绘制工作分为四步

      • 将绘制数据来源设置为顶点缓存
      Device->SetStreamSource(...);
      
      • 设置FVF格式
      Device->SetFVF(...);
      
      • (可选)设置索引缓存的地址
      Device->SetIndices(...);
      
      • 绘制图元
      Device->DrawPrimitive(...);
      
    • 在本例中代码即为

    bool Render(float DelteTime)
    {
    
    	//Set BackBuffer to white
    	pD3DDEV->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
    
    	//Set Wireframe
    	//pD3DDEV->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
    
    	//Render
    	if( SUCCEEDED(pD3DDEV->BeginScene()) )
    	{
    		//All actual render operations should be enclosed by BeginScene and EndScene
    
    		//Step 1. Set Source of data stream
    		pD3DDEV->SetStreamSource(0, pVB, 0, sizeof(COLORED_VERTEX));
    
    		//Step 2. Set Vertex Format, aka. FVF
    		pD3DDEV->SetFVF(D3DFVF_COLOREDVERTEX);
    
    		//Step 3(Optional). Set Index Buffer, only needed when using index buffer
    
    		//Step 4. Draw
    		pD3DDEV->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
    
    		//Finish Drawing
    		pD3DDEV->EndScene();
    	}
    
    	//Present BackBuffer
    	pD3DDEV->Present(NULL, NULL, NULL, NULL);
    
    	return true;
    }
    
    

    2. 使用索引缓存绘制动态图像

    效果图

    enter image description here

    enter image description here

    要说明的是,这儿直接使用顶点缓存也是可以的,但是正如图中所示,一个立方体有8个顶点,但描述这个立方体需要36个顶点,每个顶点被使用了四次,如果这儿使用索引缓存,则顶点缓存只需要储存8个顶点即可

    • 顶点缓存的建立和上个例子一样,建立索引缓存的方式和建立顶点缓存类似,相比顶点缓存,多出了一个描述索引格式的参数。以三角形为例
    Device->CreateIndexBuffer(3 * sizeof(DWORD),
    							   D3DUSAGE_WRITEONLY,
    							   D3DFMT_INDEX16,
    							   D3DPOOL_MANAGED,
    							   &pIB,
    							   0);
    WORD *indices = 0;
    
    pIB->Lock(0, 0, (void**)&indices, 0);
    
    indices[0] = 0;
    indices[1] = 1;
    indices[2] = 2;
    
    pIB->Unlock();
    
    • 由于我们要建立动态图像,所以D3DFVF_XYZRHW格式不再适合,需要使用D3DFVF_XYZ格式并设置各类变换矩阵

      • 取景变换矩阵:EyeAt为摄像机的坐标,LookAt为摄像机的取景点坐标,up为坐标系”上“方向矢量,D3DXMatrixLookAtLH最后的LH说明这是左手坐标系
      D3DXMATRIX cam;
      D3DXVECTOR3 EyeAt(0.0f, 0.0f, -3.0f);
      D3DXVECTOR3 LookAt(0.0f, 0.0f, 0.0f);
      D3DXVECTOR3	up(0.0f, 1.0f, 0.0f);
      D3DXMatrixLookAtLH(&cam, &EyeAt, &LookAt, &up);
      pD3DDEV->SetTransform(D3DTS_VIEW, &cam);
      
      • 投影变换矩阵
      D3DXMATRIX proj;
      D3DXMatrixPerspectiveFovLH(&proj,
      						   D3DX_PI * 0.5f, //FoV, Field of View
      						   800.0f/ 600.0f, //Aspect Ratio
      						   1.0f, //Z-near
      						   100.0f); //Z-far
      pD3DDEV->SetTransform(D3DTS_PROJECTION, &proj);
      
      • 世界变换,由于我们要让三维场景中的物体旋转,因此世界变换矩阵每帧都需要更新,因此将其放在Render函数内进行更新
      D3DXMATRIX ry;
      
      static float y = 0.0f;
      D3DXMatrixRotationY(&ry, y);
      y += DeltaTime;
      
      if( y >= 6.28f )
      	y = 0.0f;
      
      pD3DDEV->SetTransform(D3DTS_WORLD, &ry);
      
    • 绘图模式:由于三角形旋转过程中会将背面转向摄像机,因此要取消背面消隐,否则背面旋转到面向摄像机的时候不会显示,此外,前面也提过,使用D3DFVF_XYZ时要关闭光照

      Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
      Device->SetRenderState(D3DRS_LIGHTING, false);	
      
    • 由于图形旋转过程中,有了Z方向的变化,因此在绘图前清除缓冲区时要一并清除Z缓存

      pD3DDEV->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
      
      

    Written with StackEdit.

  • 相关阅读:
    js实现点击图片 弹出放大效果
    Linux 命令
    前台input输入框,输入内容并同步增加输入框长度
    Git
    Git 常用命令
    Windows环境git执行git add命令warning: ....
    Tomcat配置https、访问http自动跳转至https
    An internal error occurred during: "Importing Maven projects". Unsupported IClasspathEntry kind=4
    自定义滚动条mCustomScrollbar
    本地项目,发布至服务器
  • 原文地址:https://www.cnblogs.com/current/p/3997574.html
Copyright © 2011-2022 走看看