DirectX9:基础篇 第五章 绘制流水线

一.简介

绘制流水线也称为渲染管线,在DirectX的固定渲染管线中有九个步骤

用来创建3D世界几何描述的2D图像,并且设定一个虚拟摄像机把其中需要的部分透视投影到屏幕上

绘制流水线的流程:局部坐标系->世界坐标系->观察坐标系->背面消隐->光照->投影->裁剪->视口坐标系->光栅化

 

 

 

 

三维图形的显示和绘制流水线对照可以发现,观察坐标系光照步骤是可以省略的,而背面消隐也可以省略,它属于优化作用,并不是必须的

 

二.三大坐标系

1.局部坐标系

局部坐标就是模型本身的坐标

参考DirectX2D/3D--9.0:建立3D场景的几何描述

 

2.世界坐标系

D3DXMATRIX matWorld;
pd3dDevice->GetTransform(D3DTS_WORLD,&matWorld);

 

3.观察坐标系

观察坐标系就是摄像机的位置

DirectX是左手坐标系,以屏幕为基准,该坐标系X轴指向右,Y轴指向上,Z轴指向屏幕里面

 

//建立虚拟摄影机,相当于渲染视角
 
D3DXVECTOR3 position(0.0f,0.0f,-5.0f);   //摄像机的位置
D3DXVECTOR3 target(0.0f,0.0f,0.0f);      //观察点的位置
D3DXVECTOR3 up(0.0f,1.0f,0.0f);          //向上的坐标系
 
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V,&position,&target,&up);  //计算观察矩阵
 
Device->SetTransform(D3DTS_VIEW,&V);           //绑定观察矩阵

 

三.摄像机采集数据

1.背面消隐

背面消隐就是消除背面朝向相机的多边形,因为一个物体人眼看过去有正面也有背面,把背面剔除可以优化渲染性能

背面拣选状态也分为三种情况

参考DX3D9:渲染器状态

 

Device->SetRenderState(D3DRS_CULLMODE,DDCULL_NONE);  //禁用背面消隐
Device->SetRenderState(D3DRS_CULLMODE,DDCULL_CW);  //只对顺时针绕序的三角形消隐
Device->SetRenderState(D3DRS_CULLMODE,DDCULL_CCW);  //默认值,只对逆时针绕序的三角形消隐

 

2.光照

D3D有默认的光照,也可以自定义光照系统,如果没有光照就无法看见物体

参考DirectX2D/3D--9.0:光照

 

 

3.投影

在3D图形学中有两种基本的投影方式,平行投影(正投影,orthographic projection)和透视投影(perspective projection)

平行投影中,三维物体的坐标沿平行线投影到观察平面上,保持物体的比例不变

透视投影中,基于物体相对于投影平面的距离来确定投影的大小,不保持物体的比例.

DirectX采用透视投影(Perspective Projection),从视锥体投影到平面上

投影就是从3D空间投影到2D笛卡尔坐标来表示

 

D3DXMATRIX* D3DMatrixPerspectiveFovLH(

                              D3DXMATRIX* pOut,     //获得的投影矩阵

                               FLOAT fovy,              //y轴向上的视角,角度越大视野也越远

                              FLOAT Aspect,           //显示的高宽比

                              FLOAT zn,                  //最近的平面

                             FLOAT zf                    //最远的平面

);                 

 

//获得投影矩阵
 
D3DXMATRIX porj;
D3DXMatrixPerspectiveFovLH(
    &proj,
    D3DX_PI*0.5f,                 //直角
    (float)Width/(float)Height,   //宽高比例
    1.0f,                         //前裁面为1
    1000.0f);                     //后裁面为1000
 
Device->SetTransform(D3DTS_PROJECTION,&proj);

 

4.裁剪

裁剪就是把相机范围之外的物体去除掉,不进行处理,相机只能看到一个锥形范围内的物体.

可视体由可视角度和前剪裁面(Near Plane)与后剪裁面(Far Plane)决定

 

裁剪分为三种情况:

完全包含:三角形完全在可视体内

完全在外:三角形完全在可视体外部

部分在内:三角形一部分在可视体内,一部分在可视体外

 

四.摄像机显示

1.视口坐标系

视口变换就是将投影过后的2D笛卡尔坐标转化为屏幕上的实际坐标,它把剪裁区域映射到窗口区域

视口坐标系是以桌面窗口左上角为原点(0,0),横轴X向右为正,纵轴Y轴向下为正

 

typedef struct _D3DVIEWPORT9 {

    DWORD X;

    DWORD Y;

    DWORD Width;

    DWORD Height;

    DWORD MinZ;  //最小深度缓冲值

    DWORD MaxZ;  //最大深度缓冲值

} D3DVIEWPORT9;

 

D3DVIEWPORT9 vp={0,0,screenWidth,screenHeight,0,1};
Device->SetViewport(&vp);

 

2.光栅化

光栅化就是将一个多边形光栅化为一个个像素,进行着色处理.

图元(Graphics Output Primitive)是用来描述几何图元,图元是组成图像的基本单元,比如三维模型中的点/线/面等

 

HRESULT IDirect3DDevice9::SetStreamSource(

    UINT StreamNumber,

    IDirect3DVertexBuffer9* pStreamData,

    UINT OffsetInBytes,

    UINT Stride

);

 

HRESULT IDirect3DDevice9::DrawPrimitive(

    D3DPRIMITIVETYPE PrimitiveType,  //图元类型

    UINT StartVertex,  //起始点的索引位置                

    UINT PrimitiveCount  //绘制图元个数

);

 

//绑定资源流
Device->SetStreamSource(0, vb, 0, sizeof(Vertex));
 
//设置顶点格式
Device->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
 
//设置索引缓冲区
Device->SetIndices(ib);
 
 
//绘制图元方式
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
Device->Present(0,0,0,0);

 

五.完整版

参考代码->DirectX2D/3D--9.0:初始化,代码都不变,添加了一些新代码

 

1.三角形绘制

IDirect3DVertexBuffer9* Triangle=0;
 
//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(){
 
    //
    //Create the vertex buffer
    //
 
    Device->CreateVertexBuffer(
        3*sizeof(Vertex),      //size in bytes
        D3DUSAGE_WRITEONLY,    //flags
        Vertex::FVF,           //vertex format
        D3DPOOL_MANAGED,       //managed memory pool
        &Triangle,             //return create vertex buffer
        0);
 
    //
    //Fill the buffers with the triangle data
    //      
 
    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();
 
    //
    //Set the projection matrix
    //
 
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
        &proj,
        D3DX_PI*0.5f,
        (float)Width/(float)Height,
        1.0f,
        1000.0f);
    Device->SetTransform(D3DTS_PROJECTION,&proj);
 
    //
    //Set wireframe mode render state
    //
    Device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
 
    return true;
    
}
 
void Cleanup(){
    d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
}
 
bool Display(float timeDelta){
    if(Device){
        Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
        Device->BeginScene();
        
        Device->SetStreamSource(0,Triangle,0,sizeof(Vertex));
        Device->SetFVF(Vertex::FVF);
 
        //Draw one triangle
        Device->DrawPrimitive(D3DPI_TRIANGLELIST,0,1);
        
        Device->EndScene();
        Device->Present(0,0,0,0);
    }
    return true;
}

 

2.正方形绘制

IDirect3DVertexBuffer9* VB=0;
IDirect3DIndexBuffer9* IB=0;
 
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(
        8*sizeof(Vertex),
        D3DUSAGE_WRITEONLY,
        Vertex::FVF,
        D3DPOOL_MANAGED,
        &VB,
        0);
 
    Device->CreateIndexBuffer(
        36*sizeof(WORD),
        D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16,
        D3DPOOL_MANAGED,
        &IB,
        0);
 
    Vertex* vertices;
    VB->Lock(0,0,(void**)&vertices,0);
 
    vertices[0]=Vertex(-1.0f,-1.0f,-1.0f);
    vertices[1]=Vertex(-1.0f,1.0f,-1.0f);
    vertices[2]=Vertex(1.0f,1.0f,-1.0f);
    vertices[3]=Vertex(1.0f,-1.0f,-1.0f);
    vertices[4]=Vertex(-1.0f,-1.0f,1.0f);
    vertices[5]=Vertex(-1.0f,1.0f,1.0f);
    vertices[6]=Vertex(1.0f,1.0f,1.0f);
    vertices[7]=Vertex(1.0f,-1.0f,1.0f);
 
    VB->Unlock();
    
    WORD* indices=0;
    IB->Lock(0,0,(void**)&indices,0);
 
    //front side
    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();
 
    D3DXVECTOR3 position(0.0f,0.0f,-5.0f);
    D3DXVECTOR3 target(0.0f,0.0f,0.0f);
    D3DXVECTOR3 up(0.0f,1.0f,0.0f);
    D3DXMATRIX V;
    D3DXMatrixLookAtLH(&V,&position,&target,&up);
 
    Device->SetTransform(D3DTS_VIEW,&V);
 
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
        &proj,
        D3DX_PI*0.5f,
        (float)Width/(float)Height,
        1.0f,
        1000.0f);
    Device->SetTransform(D3DTS_PROJECTION,&proj);
 
    Device->SetRenderState(D3DRS_FILEMODE,D3DFILL_WIREFRAME);
    
    return true;
}
 
void Cleanup(){
    d3d::Release<IDirect3DVertexBuffer9*>(VB);
    d3d::Release<IDirect3DIndexBuffer9*>(IB);
}
 
bool Display(float timeDelta){
 
    if(Device){
        
        D3DXMATRIX Rx,Ry;
        D3DXMatrixRotationX(&Rx,3.14f/4.0f);
 
        static float y=0.0f;
        D3DXMatrixRotationY(&Ry,y);
        y+=timeDelta;
 
        if(y>=6.28f)
            y=0.0f;
 
        D3DXMATRIX p=Rx*Ry;
        Device->SetTransform(D3DTS_WORLD,&p);
 
        Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
        Device->BeginScene();
        
        Device->SetStreamSource(0,VB,0,sizeof(Vertex));
        Device->SetIndices(IB);
        Device->SetFVF(Vertex::FVF);
        
        Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
        Device->EndScene();
        Device->Present(0,0,0,0);
    }
    return true;
}

 

六.简化版

 

 

posted @ 2019-07-08 14:05  言午丶  阅读(1039)  评论(0编辑  收藏  举报