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

一.简介

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

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

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

 

 

 

 

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

 

二.三大坐标系

1.局部坐标系

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

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

 

2.世界坐标系

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

 

3.观察坐标系

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

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

 

1
2
3
4
5
6
7
8
9
10
//建立虚拟摄影机,相当于渲染视角
  
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:渲染器状态

 

1
2
3
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                    //最远的平面

);                 

 

1
2
3
4
5
6
7
8
9
10
11
//获得投影矩阵
  
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;

 

1
2
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  //绘制图元个数

);

 

1
2
3
4
5
6
7
8
9
10
11
12
13
//绑定资源流
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.三角形绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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.正方形绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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 @   言午丶  阅读(1142)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示