zoukankan      html  css  js  c++  java
  • DirectX9:基础篇 第二章 建立3D场景的几何描述

    一.简介

    d3dx9mesh.h有关网格模型

    二.灵活的顶点格式

    Direct3D中的顶点不只有空间位置属性,还可以有颜色 法线向量属性等,所以可以自定义一个顶点结构

    1.使用

    struct ColorVertex{
        float _x,_y,_z;          //位置
        DWORD _color;      //颜色
    };

    #define FVF_COLOR(D3DFVF_XYZ | D3DFVF_DIFFUSE)  //包含位置属性和漫反射颜色属

    struct NormaolTexVertex{
        float _x,_y,_z;           //位置
        float _nx,_ny,_nz;     //法线
        float _u,_v;               //纹理坐标
    };

    #define FVF_NORMAL_TEX(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

    //灵活的顶点格式
    struct Vertex{
     
        Vertex(){}
        Vertex(float x,float y,float z){
            _x=x;
            _y=y;
            _z=z;
        }
        float _x,_y,_z;
        static const DWORD FVF;
    };
    const DWORD Vertex::FVF=D3DFVF_XYZ;
     
    bool Setup(){
        
        //根据灵活的顶点格式来创建顶点缓存
        Device->CreateVertexBuffer(
            3*sizeof(Vertex),
            D3DUSAGE_WRITEONLY,
            Vertex::FVF,
            D3DPOOL_MANAGED,
            &Triangle,
            0);
        
    }
     
    bool Display(float timeDelta){
        
        //根据灵活的顶点格式来绑定模型数据
        Device->SetFVF(Vertex::FVF);
    }
    

    2.FVF宏定义

    #define D3DFVF_RESERVED0        0x001
    #define D3DFVF_POSITION_MASK    0x400E
    #define D3DFVF_XYZ              0x002        //包含三维坐标
    #define D3DFVF_XYZRHW           0x004
    #define D3DFVF_XYZB1            0x006
    #define D3DFVF_XYZB2            0x008
    #define D3DFVF_XYZB3            0x00a
    #define D3DFVF_XYZB4            0x00c
    #define D3DFVF_XYZB5            0x00e
    #define D3DFVF_XYZW             0x4002
     
    #define D3DFVF_NORMAL           0x010
    #define D3DFVF_PSIZE            0x020
    #define D3DFVF_DIFFUSE          0x040
    #define D3DFVF_SPECULAR         0x080
     
    #define D3DFVF_TEXCOUNT_MASK    0xf00
    #define D3DFVF_TEXCOUNT_SHIFT   8
    #define D3DFVF_TEX0             0x000
    #define D3DFVF_TEX1             0x100
    #define D3DFVF_TEX2             0x200
    #define D3DFVF_TEX3             0x300
    #define D3DFVF_TEX4             0x400
    #define D3DFVF_TEX5             0x500
    #define D3DFVF_TEX6             0x600
    #define D3DFVF_TEX7             0x700
    #define D3DFVF_TEX8             0x800
     
    #define D3DFVF_LASTBETA_UBYTE4   0x1000
    #define D3DFVF_LASTBETA_D3DCOLOR 0x8000
     
    #define D3DFVF_RESERVED2         0x6000 

    三.顶点缓存

    一个顶点缓存是一个包含顶点数据的连续内存空间,存放在显存之中,比内存快(用于存储网格顶点)

    1.CreateVertexBuffer

    注意:静态缓存处理快,但是更新重绘慢.动态缓存处理慢,但是更新重绘快

    HRESULT IDirect3DDevice9::CreatVertexBuffer(    //创建顶点缓存
         UINT Length,

      DWORD Usage,

        DWORD FVF,

        D3DPOOL Pool,

        IDirect3DVertexBuffer9** ppVertexBuffer,

        HANDLE* pSharedHandle

    );

    Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex)

    Usage:附加属性
     
          (1)D3DUSAGE_DYNAMIC  将缓存设为动态缓存
     
          (2)D3DUSAGE_POINTS   规定缓存将用于存储点图元
     
          (3)D3DUSAGE_SOFTWAREPROCESSING    指定软件顶点运算方法
     
          (4)D3DUSAGE_WRITEONLY    只写

    FVF:存储在顶点缓冲的灵活顶点格式,参考宏定义

    Pool:容纳缓存的内存池

    ppVertexBuffer:用于接收所创建的顶点缓存的指针

    pSharedHandle:不使用,设为0

    //例子
     
    IDirect3DVertexBuffer9* vb;
    device->CreateVertexBuffer(
        8*sizeof(Vertex),
        0,
        D3DFVF_XYZ,
        D3DPOOL_MANAGED,
        &vb,
        0);
    

    2.Lock/Unlock

    HRESULT IDirect3DVertexBuffer9::Lock(

        UINT offsetToLock,

        UINT SizeToLock,

        BYTE** ppbData,
        DWORD Flags
    );

    OffsetToLock:自缓存的起始点到开始锁定的位置的偏移量,单位为字节

    SizeToLock:所要锁定的字节数.
    如果OffsetToLock和SizeToLock都为0表示锁定整个缓存

     //顶点缓存
    IDirect3DVertexBuffer9* Triangle=0;
     
    //访问顶点缓存内存
    Vertex* vertices;
    Triangle->Lock(0,0,(void**)&vertices,0);
    ...
     
    Triangle->Unlock();
    

    3.示例

    //顶点缓存
    IDirect3DVertexBuffer9* Triangle=0;
     
     
    void Cleaup(){
        d3d::Release<IDirect3DVertexBuffer9*>(VB);
    }
     
    bool Setup{
     
        //用D3D设备类来创建顶点缓存内存
        Device->CreateVertexBuffer(
            3*sizeof(Vertex),
            D3DUSAGE_WRITEONLY,
            Vertex::FVF,
            D3DPOOL_MANAGED,   
            &Triangle,
           0);
     
        //访问顶点缓存内存
        Vertex* vertices;
        Triangle->Lock(0,0,(void**)&vertices,0);
        
        vertices[0]=Vertex(-1.0f,0.0f,2.0f);
        vertices[1]=Vertex(0.0f,1.0f,2.0f);
        vertices[2]=Vertex(1.0f,0.0f,2.0f);
     
        Triangle->Unlock();
        
    }
     
     
    bool Display(float timeDelta){
        
        Device->SetStreamSource(0,VB,0,sizeof(Vertex));
    }
    

    四.索引缓存

    一个索引缓存是一个包含索引数据的连续内存空间,存放于显存之中,比内存快

    构建一个3D物体的所有三角形单元中会共享许多公共顶点,为了解决重合顶点问题,用顶点列表(vertex list)和索引列表(index list)来记录坐标(决定顶点应以何种组合方式构成网格的三角形单元)

     

    假设不用索引来表示一个正方形,Vectex v[6]={v0,v1,v2,v1,v2,v3},需要六个顶点坐标

    加入索引之后,Vertect v[4]={v0,v1,v2,v3}  WORD indexList[6]={0,1,2,1,2,3};  只需要记录四个顶点坐标

    因为索引坐标只是一个整数,用来获取顶点坐标的第几个,所以比三维坐标的Vertex更省内存

    1.创建索引缓存

    HRESULT IDirect3DDevice9::CreateIndexBuffer(
        UINT Length,
        DWORD Usage,
        D3DFORMAT Format,
        D3DPOOL Pool,
        IDirect3DIndexBuffer9** ppIndexBuffer,
        HANDLE* pSharedHandle);
     
    Length:为缓存分配的字节数,8个顶点需要8*sizeof(Vertex)
    Usage:附加属性
          (1)D3DUSAGE_DYNAMIC  将缓存设为动态缓存
          (2)D3DUSAGE_POINTS   规定缓存将用于存储点图元
          (3)D3DUSAGE_SOFTWAREPROCESSING    指定软件顶点运算方法
          (4)D3DUSAGE_WRITEONLY    只写
    Format:指定索引的大小
           (1)D3DFMT_INDEX16 表示16位索引
           (2)D3DFMT_INDEX32 表示32位索引
    Pool:容纳缓存的内存池
    ppIndexBuffer:用于接收所创建的索引缓存的指针
    pSharedHandle:不使用,设为0
    
    IDirect3DIndexBuffer9* ib;
    device->CreateIndexBuffer(
        36*sizeof(WORD),
        D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16,
        D3DPOOL_MANAGED,
        &ib,
        0);
    

    2.访问索引缓存

    HRESULT IDirect3DIndexBuffer9::Lock(
        UINT OffsetToLock,
        UINT SizeToLock,
        BYTE** ppbData,
        DWORD Flags
    );
    

    3.示例

    //索引缓存
    IDirect3DIndexBuffer9* IB=0;
     
     
    bool Setup(){
     
        //用D3D设备类来创建索引缓存    
        Device->CreateIndexBuffer(
            36*sizeof(WORD),
            D3DUSAGE_WRITEONLY,
            D3DFMT_INDEX16,    
            D3DPOOL_MANAGED,
            &IB,
            0);
        
        //访问索引缓存
        WORD* Iindices=0;
        IB->LOCK(0,0,(void**)&indices,0);
     
        indices[0]=0;indices[1]=1;indices[2]=2;
        indices[3]  = 0; indices[4]  = 2; indices[5]  = 3;
     
        // back side
        indices[6]  = 4; indices[7]  = 6; indices[8]  = 5;
        indices[9]  = 4; indices[10] = 7; indices[11] = 6;
     
        // left side
        indices[12] = 4; indices[13] = 5; indices[14] = 1;
        indices[15] = 4; indices[16] = 1; indices[17] = 0;
     
        // right side
        indices[18] = 3; indices[19] = 2; indices[20] = 6;
        indices[21] = 3; indices[22] = 6; indices[23] = 7;
     
        // top
        indices[24] = 1; indices[25] = 5; indices[26] = 6;
        indices[27] = 1; indices[28] = 6; indices[29] = 2;
     
        // bottom
        indices[30] = 4; indices[31] = 0; indices[32] = 3;
        indices[33] = 4; indices[34] = 3; indices[35] = 7;
     
        IB->Unlock();
    }
     
    void Cleanup(){
        d3d::Release<IDirect3DIndexBuffer9*>(IB);
    }
     
    bool Display(float timeDelta){
        //绑定模型的索引缓存
        Device->SetIndices(IB);
    }
    

    五.网格

    1.网格简介

    一个网格由一个或多个子集组成,一个子集(subsets)是网格中一组可用相同属性(材质/纹理/绘制状态)进行绘制的三角形单元

    假设一个房子是网格,那么地板/墙/天花板/窗口各有自己的属性,都能用来绘制房子网格

    为了区分不同的子集,给每个子集指定一个唯一的非负整数值,该值为DWORD类型所能容纳任何非负整数

    网格中的每个三角形单元都被赋予了一个属性ID,该ID指定了该三角形单元所属的子集,这些三角形单元的属性ID被存储在网格的属性缓存(Attribute Buffer)中,该属性缓存实际上就是一个DWORD类型的数组.

    由于每个面片(三角形)在属性缓存中都有对应项,所以属性缓存中元素的个数与网格中面皮的个数相等.

    2.网格类(ID3DXMesh)的方法

    HRESULT ID3DMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB)

    HRESULT ID3DMesh::GetIndexBuffer(LPDIRECT3DVERTEXBUFFER9* ppIB)

    DWORD GetFVF()

    DWORD GetNumVertices()
    DWORD GetNumBytesPerVertex()
    DWORD GetNumFaces()

    LockAttributeBuffer()

    LockIndexBuffer()

    LockVertexBuffer()

    UnlockAttributeBuffer()

    UnlockIndexBuffer()

    UnlockVertexBuffer()

    CloneMesh()
    CloneMeshFVF()

    DrawSubset(DWORD AttribID)   //用于绘制由参数AttribId指定的子集中的三角形单元
     
    //例子
    Mesh->DrawSubset(0);  //绘制子集0中的所有三角形单元
     
    for(int i=0;i<numSubsets;i++){
        Device->SetMaterial(mtrls[i]);
        Device->SetTexture(0,textures[i]);
        Mesh->DrawSubset(i);
    }
    

    3.D3D支持网格(ID3DXMESH)的方法

    HRESULT WINAPI D3DXCreateMeshFVF(
        DWORD NumFaces,        //网格所具有的面皮个数
        DWORD NumVertices,          //网格所具有的顶点个数
        DWORD Options,        //创建网格时所使用的创建标记
        DWORD FVF,             // 顶点的灵活格式
        LPDIRECT3DDEVICE9 pDevice,      // 与网格相关的设备指针
        LPD3DXMESH* ppMesh              // 所创建的网格对象的指针
    );

    D3DXCreateMesh()        //创建空网格

    //绘制内置的网格模型
    D3DXCreateTeapot()    //茶壶
    D3DXCreateBox()       //正方体
    D3DXCreateCylinder()
    D3DXCreateTorus()
    D3DXCreateSphere()
    D3DXCreaetPolygon()

    //多个模型一起绘制
     
     
    ID3DXMesh* Objects[5] = {0, 0, 0, 0, 0};
     
    // World matrices for each object.  These matrices
    // specify the locations of the objects in the world.
    D3DXMATRIX ObjWorldMatrices[5];
     
    //
    // Framework Functions
    //
    bool Setup()
    {
     
    	//
    	//茶壶模型 
    	//
     
    	D3DXCreateTeapot(
    		Device,
    		&Objects[0],
    		0);
     
            //
            //立方体
            //
     
    	D3DXCreateBox(
    		Device,
    		2.0f, // width
    		2.0f, // height
    		2.0f, // depth
    		&Objects[1],
    		0);
            
            //
    	//柱体
            //
            
    	D3DXCreateCylinder(
    		Device,
    		1.0f, // radius at negative z end
    		1.0f, // radius at positive z end
    		3.0f, // length of cylinder
    		10,   // slices
    		10,   // stacks
    		&Objects[2],
    		0);
     
            //
            //圆环体
            //
     
    	D3DXCreateTorus(
    		Device,
    		1.0f, // inner radius
    		3.0f, // outer radius
    		10,   // sides
    		10,   // rings
    		&Objects[3],
    		0);
     
            //
            //球面体
            //
     
    	D3DXCreateSphere(
    		Device,
    		1.0f, // radius
    		10,   // slices
    		10,   // stacks
    		&Objects[4],
    		0);
     
     
     
    	//
            //多边形
            //D3DXCreatePolygon()
     
    	D3DXMatrixTranslation(&ObjWorldMatrices[0],  0.0f, 0.0f,  0.0f);
    	D3DXMatrixTranslation(&ObjWorldMatrices[1], -5.0f, 0.0f,  5.0f);
    	D3DXMatrixTranslation(&ObjWorldMatrices[2],  5.0f, 0.0f,  5.0f);
    	D3DXMatrixTranslation(&ObjWorldMatrices[3], -5.0f, 0.0f, -5.0f);
    	D3DXMatrixTranslation(&ObjWorldMatrices[4],  5.0f, 0.0f, -5.0f);
     
    	//
    	// Set the projection matrix.
    	//
     
    	D3DXMATRIX proj;
    	D3DXMatrixPerspectiveFovLH(
    		&proj,
    		D3DX_PI * 0.5f, // 90 - degree
    		(float)Width / (float)Height,
    		1.0f,
    		1000.0f);
    	Device->SetTransform(D3DTS_PROJECTION, &proj);
     
    	//
    	// Switch to wireframe mode.
    	//
     
    	Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
     
    	return true;
    }
    void Cleanup()
    {
    	for(int i = 0; i < 5; i++)
    		d3d::Release<ID3DXMesh*>(Objects[i]);
    }
     
    bool Display(float timeDelta)
    {
    	if( Device )
    	{
    		// Animate the camera:
    		// The camera will circle around the center of the scene.  We use the
    		// sin and cos functions to generate points on the circle, then scale them
    		// by 10 to further the radius.  In addition the camera will move up and down
    		// as it circles about the scene.
    		static float angle = (3.0f * D3DX_PI) / 2.0f;
    		static float cameraHeight = 0.0f;
    		static float cameraHeightDirection = 5.0f;
     
    		D3DXVECTOR3 position( cosf(angle) * 10.0f, cameraHeight, sinf(angle) * 10.0f );
     
    		// the camera is targetted at the origin of the world
    		D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
     
    		// the worlds up vector
    		D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
     
    		D3DXMATRIX V;
    		D3DXMatrixLookAtLH(&V, &position, &target, &up);
    		Device->SetTransform(D3DTS_VIEW, &V);
     
    		// compute the position for the next frame
    		angle += timeDelta;
    		if( angle >= 6.28f )
    			angle = 0.0f;
     
    		// compute the height of the camera for the next frame
    		cameraHeight += cameraHeightDirection * timeDelta;
    		if( cameraHeight >= 10.0f )
    			cameraHeightDirection = -5.0f;
     
    		if( cameraHeight <= -10.0f )
    			cameraHeightDirection = 5.0f;
     
    		//
    		// Draw the Scene:
    		//
     
    		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
    		Device->BeginScene();
     
    		for(int i = 0; i < 5; i++)
    		{
    			// Set the world matrix that positions the object.
    			Device->SetTransform(D3DTS_WORLD, &ObjWorldMatrices[i]);
     
    			// Draw the object using the previously set world matrix.
    			Objects[i]->DrawSubset(0);
    		}
     
    		Device->EndScene();
    		Device->Present(0, 0, 0, 0);
    	}
    	return true;
    }
    
  • 相关阅读:
    熟悉常用的Linux操作
    Python基础之五星红旗
    类似于铁道部12306的城市选择框的实现
    使用Django操作数据库入门
    进程和线程
    线程、进程、携程理解
    CentOS6.8部署Python3.6.8的Django项目
    爬取妹子图片
    聚类算法之DBSCAN
    机器学习算法优缺点总结
  • 原文地址:https://www.cnblogs.com/k5bg/p/11136525.html
Copyright © 2011-2022 走看看