Direct3D基础回顾

来源:互联网 发布:步进电机驱动程序源码 编辑:程序博客网 时间:2024/05/05 21:26

Direct3D基础概念

渲染接口机制

1)IDirect3D9 + 显卡适配器标识号
2)设备类型 + 窗口/全屏模式和窗口句柄 (Device存在工作丢失状态)+
顶点运算类型
3)D3DPRESENT_PARAMETERS(后台缓存和深度缓存,窗口,FPS)+ D3DCAPS9(纹理模板等技术)= device对象
device对象存在工作状态和丢失状态
device创建资源缓存到表面,设置DX状态命令操作资源,渲染出来(渲染部分程序一直绘制)

资源管理

资源在SM,AM,VM位置中,存在
类型和大小数量:Type类型 / Format点格式, 大小数量 /
特性:  Pool位置 /Usage静态动态缓存只读只写的使用方式/  D3DLOCK锁定后的操作
的属性。

几何顶点运算和像素光栅化运算

输入组装:贴图模型动画顶点/纹理输入组装几何光照变换和顶点运算:顶点的变换/贴图/光照计算,坐标系变换(模型/世界/观察/裁剪和剔除/投影/屏幕);光栅化和像素运算:顶点序列转换为像素(裁剪剔除检测,和对顶点进行插值得到像素序列),决定将像素写到目标缓存(写入深度缓存模板缓存);输出合并:接收像素着色器的slice,深度测试模板测试,得到最终位置上的像素值。 

DX众多状态命令运用(共存和互斥)的理解

在看到这些规则或互斥命令设置的时候应该思考下原因,该规则为什么会这样?牵涉到的原理是什么?该DX命令或状态本来含义是什么?另外一个DX命令或状态含义又是什么?加上是操作系统调度策略,多线程同步锁定,缓存位置特性,DX状态机机制(Runtime Command buffer->Driver command buffer), DX数据传输性能等方面考虑得出真正的理解各种状态命令设置。

IDirect3D9各专项基础知识

1.IDirect3D9完成后销毁

IDirect3D9根据D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DPRESENT_PARAMETERS,D3DCAPS9,关联的窗口句柄(渲染到的前台缓存的关联窗口)hwnd,D3DCREATE_HARDWARE_VERTEXPROCESSING创建完IDirect3DDevice9 显卡适配器软件抽象对象后,IDirect3D9就可以释放掉了

2.FPS间隔内绘制和Present

D3D图形程序会每分每秒都在Device->Present交换链渲染数据,deltaTime是Process里面上每个函数上次执行到它当前时间点的间隔时间可以做动画处理。当需要控制帧频时候,可以计算恰当Sleep一下来确保帧频FPS Frames  
Per Second。

3.D3DSWAPEFFECT_DISCARD优势

D3DSWAPEFFECT_DISCARD交换链即可指针交换也可以拷贝,才支持MultiSampleType 抗锯齿,抗锯齿缓存类型和水平需要CheckDeviceMultiSampleType来判断。D3DSWAPEFFECT_FLIP模式节省了更多的内存带宽和可以从全屏渲染模式得到的统计信息中获益,窗口模式会用D3DSWAPEFFECT_COPY 。

4.Windowed模式下D3DPRESENT_PARAMETERS的后台缓存参数,hWnd和FPS可以不用填

typedef struct D3DPRESENT_PARAMETERS {

  UINT                BackBufferWidth; // 窗口模式可以为0,全屏模式是EnumAdapterModes的一个返回值

  UINT                BackBufferHeight;// 窗口模式可以为0,全屏模式是EnumAdapterModes的一个返回值

  D3DFORMAT           BackBufferFormat;// 窗口模式可用D3DFMT_UNKNOWN,全屏模式是CheckDeviceType的返回值

  UINT                BackBufferCount;//赋值0将是1D3DSWAPEFFECT_COPY交换表现只能是一个后台缓存,一般为1

  D3DMULTISAMPLE_TYPE MultiSampleType;// D3DWAPEFFECT_DISCARD下才能用多重采样,否则都是D3DMULTSAMPLE_NONE

  DWORD               MultiSampleQuality;//要用CheckDeviceMultiSampleType,[0,CheckDeviceMultiSampleType-1] 

  D3DSWAPEFFECT        SwapEffect;// D3DSWAPEFFECT_COPY只能在后台缓存个数是1, 一般用D3DSWAPEFFECT__DISCARD

  HWND                hDeviceWindow;// 窗口模式下可以为NULL,全屏模式下是CreateDevicehFocusWindow

  BOOL                Windowed;//窗口模式,还是全屏模式

  BOOL                EnableAutoDepthStencil;// depth-stencil Buffer会自动设置为渲染目标,reset时自动重新创建

  D3DFORMAT           AutoDepthStencilFormat;//CheckDepthStencilMatch的返回值

  DWORD               Flags;//一般用D3DPRESENTFLAG__DISCARD_DEPTHSTENCIL,其它Z/S缓存创建且渲染后之前的内容将会丢失,提高性能,D3DPRESENTFLAG_LOCKABLE_BACKBUFFER制定可以锁定表面否则表面是不能被锁定的

  UINT                FullScreen_RefreshRateInHz;// FPS,窗口模式下必须为0(会添加),全屏模式是EnumAdapterModes返回值

  UINT                PresentationInterval;// 一般用D3DPRESENT_INTERVAL_DEFAULT也就是D3DPRESENT_INTERVAL_ONE

} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;

5.通常D3DPRESENT_PARAMETERS的hWnd

就是CreateDevice的fFocusWnd,hDevice绘制出来的图形将渲染到该窗口上。但是视频监控中可以多个hWnd,但当前显卡的fFocusWnd只有一个。

6.检查或获取后台缓存表面格式CheckDeviceType函数

// 1.检查指定的表面像素格式,是否在指定的适配器类型、适配器像素格式下可用。
bool D3DCheckAdapter::GetBackBufferFormat(IDirect3D9 *pD3D, const D3DDEVTYPE deviceType, const bool bWindow, D3DFORMAT &fmt)
{
 if(pD3D == NULL)
 {
  return false;
 }
 D3DDISPLAYMODE adapterMode;
 pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &adapterMode);
 if(D3D_OK != pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, deviceType, adapterMode.Format, fmt, bWindow))
 {
  fmt = adapterMode.Format;
 };
 return true;
}

7.对于指定的资源使用方式CheckDeviceFormat

资源类型,资源像素格式;在默认的显卡适配器下是否支持CheckDeviceFormat
bool D3DCheckAdapter::CheckResourceFormat(IDirect3D9 *pD3D, const DWORD nSrcUsage, const D3DRESOURCETYPE srcType,const D3DFORMAT srcFmt)
{
 if(pD3D == NULL)
 {
  return false;
 }
 D3DDISPLAYMODE displayMode;
 pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode);
 if(D3D_OK == pD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, displayMode.Format, nSrcUsage, srcType, srcFmt))
 {
  return true;
 }
 return false;
}

8.D3DUSAGE使用方式

D3DUSAGE_DYNAMIC:
默认创建的缓存是静态的,使用D3DUSAGE_DYNAMIC创建的缓存是动态的,D3DUSAGE_DYNAMIC不能在存储类型为D3DPOOL_MANAGED的资源中使用,可以在D3DPOOL_DEFAULT,D3DPOOL_SYSTEMMEM中使用。 D3DLOCK_DISCARD(锁定可放弃),D3DLOCK_NOOVERWRITE(锁定不能重写)只能在D3DUSAGE_DYNAMIC情况下使用

D3DUSAGE_WRITEONLY :

D3DPOOL_DEFAULT中需要使用D3DUSAGE_WRITEONLY,不然会影响性能。可以是各种D3DPOOL类型,写和渲染性能更高,尝试读取该标识的资源将失败。

D3DUSAGE_DEPTHSTENCIL:

只能在D3DPOOL_DEFAULT的深度模板缓存中使用。

D3DUSAGE_RTPATCHES:

Set to indicate that thevertex buffer is to be used for drawing high-order primitives.

顶点缓存用于高级几何体,高级几何体包括动画,人物模型,地形和水等复杂物体。

D3DUSAGE_AUTOGENMIPMAP:

资源类型是多级纹理使用,体积纹理,深度模板缓存表面或纹理的不能使用;在存储类型是D3DPOOL_SYSTEMMEM的不能使用。

9.D3DPOOL存储类型

D3DPOOL_DEFAULT:

此类资源不由D3D管理,常驻在显存或者AGP内存中渲染效率高;丢失需要重新创建;锁定读比较麻烦,一般设置为D3DUSAGE_WRITEONLY。

D3DPOOL_DEFAULT内存池中的纹理是不能锁定的,除非是D3DUSAGE_DYNAMIC使用方式的纹理或者是私有、FOURCC、驱动格式的纹理。与texture不同的是,swapchain back buffers, render targets, vertex buffers和indexbuffers都是可以锁定的。

例子:游戏中使用的光标贴图放置在显存中;如果数据需要高频率更新(不断的Lock, Unlock),也需要使用D3DPOOL_DEFAULT,同时使用D3DUSAGE_DYNAMIC标记。这意味着此资源会被创建在AGP Memory中。其它非常用贴图资源不建议使用D3DPOOL_DEFAULT,应该用D3DPOOL_MANAGED。

D3DPOOL_MANAGED:

交给D3D托管,渲染效率一般(系统RAM/AGP内存/显存中都有,一般不在显存中); 设备丢失会自动恢复; 锁定读写效率较高。 资源交给D3D自动管理,资源会在系统内存中备份一份,在资源需要渲染的时候,会自动拷贝一份到AGP内存、显存中进行渲染。 当设备丢失时,D3D会自动恢复显存中的数据。 D3DPOOL_MANAGED的资源可以自由的锁定。 

适用情况:由于D3D自己的资源管理方案很高效、使用简单,游戏中大部分资源都可以使用此标识创建。

例子:游戏中使用的大部分纹理贴图,静态模型。

D3DPOOL_SYSTEMMEM:

直接放置在系统中,渲染效率较差需要用UpdateSurface或UpdateTexture拷贝到D3DPOOL_DEFAULT创建的资源,

设备丢失时候不需要重新创建资源,锁定很方便CPU处理较快。

对于需要高频CPU读写处理的数据,推荐使用这种方式。


10.CPU锁定资源的方式D3DLOCK

D3DLOCK_DISCARD

使用方式会强制为:D3DUSAGE_DYNAMIC。

CPU不会因锁定而等待,可以有效的提高程序性能。

原缓存指针在使用后被丢弃。表示不会读取资源,只会全写资源,这样驱动和RUNTIME配合来了个瞒天过海。立即返回给应用程序另外块VM地址指针,而原指针在本次UNLOCK之后被丢弃不再使用,这样CPU LOCK无需等待GPU使用资源完毕,能继续操作图形资源(顶点缓冲和索引缓冲),这技术叫VB IB换名(renaming)。

D3DLOCK_NOOVERWRITE:

使用方式会强制为:D3DUSAGE_DYNAMIC,可以进行动态更新。这个标记可以使用在当应用程序,需要将资源数据append data附加到末尾的时候

D3DLOCK_DISCARD和D3DLOCK_NOOVERWRITE只能在D3DUSAGE_DYNAMIC中使用。


D3DLOCK_DONOTWAIT:

当显卡驱动没有能够马上锁定表面的时候,允许应用程序返回CPU循环。如果没有能够马上锁定,将会返回D3DERR_WASSTILLDRAWING。这个锁定只能用在用CreateOffscreenPlainSurface, CreateRenderTarget,or CreateDepthStencilSurface创建的表面,这个标记通常可以被后台缓存使用.


D3DLOCK_READONLY:

应用程序不能写这块缓存。这个选项让资源保存在非本地的格式,可以节省解锁时候的再压缩,可以提高锁定解锁效率。可以有效的提高程序的性能

总结:D3DPOOL_DEFAULT,D3DPOOL_SYSTEMMEMD3DUSAGE_DYNAMICD3DLOCK_DISCARD能有更好的性能,CPU锁定操作表面的效率更高。

           D3DPOOL_DEFAULTD3DUSAGE_WRITEONLY可以显著提高性能。

          D3DPOOL_MANAGED适用大多数资源,不能使用D3DUSAGE_DYNAMICD3DLOCK_DISCARD使用方式用D3DUSAGE_WRITEONLY即可,锁定Lock时候用0即可,非用D3DLOCK_DONOTWAIT可以提高性能; 关于这些资源的利用需要更好的参考开源引擎。



11.D3D Runtime/Driver buffer用户态内核态命令分发机制

当应用程序调用一个D3D API时,RUNTIME将调用转换成设备无关的命令,然后将命令缓冲到这个COMMANDBUFFER中。

这个BUFFER的大小是根据任务负载动态改变的,当这个BUFFER满员之后,RUNTIME会让所有命令FLUSH到KERNEL模式下的驱动DriverBuffer中。

(1)理解D3D调试的状态信息,传递刷新命令,命令丢弃

Ignoring redundantSetRenderState - X


(2)用异步IDirect3DQuery9测定GPU工作时间

(3)理解清空缓存命令和模式切换

如下情况可能清空RUNTIME COMMAND BUFFER,并引起一个模式切换

1).Lock method(某些条件下和某些LOCK标志)

2).创建设备、顶点缓冲、索引缓冲和纹理

3.)完全释放设备、顶点缓冲、索引缓冲和纹理资源

4).调用ValidateDevice

5).调用Present

6).COMMAND BUFFER已满

7).用D3DGETDATA_FLUSH调用GetData函数

GPU处理完D3DQUERYTYPE_EVENT类型查询在CB中加入的D3DISSUE_END标记后,会将查询对象状态置SIGNALED状态,

所以CPU等待查询一定是异步的。


(4)理解D3DPOOL_MANAGED会用比较大的存取空间,设备丢失后不用重新拷贝资源到VM中


(5)每个FRAME的标志就是BEGINSCENE/ENDSCENE对


(6)用EvictManagedResources函数强制清空VM中的所有MANAGED资源,一般情况下不要使用,但是在关卡切换时候非常有用。


(7)CPU写AM,合理使用D3DUSAGE_DYNAMIC,D3DPOOL_MANAGED随机写资源要使用D3DPOOL_MANAGED,顺序写用D3DUSAGE_DYNAMIC


(8)合理的使用AM, 高频修改的纹理不用D3DUSAGE_TEXTURE创建所以此类资源最好以D3DPOOL_DEFAULT和D3DPOOL_SYSTEMMEM各创建一份RENDERTARGET不要用D3DPOOL_MANAGED创建。


(9)Lock D3DPOOL_DEFAULT资源时Runtime会来回拷贝资源


(10)D3DLOCK_DISCARD能够有效的提高CPU Lock的性能,使得CPU和GPU可以并行工作。


(11)D3DUSAGE_WRITEONLY的性能优势

如果资源D3DUSAGE属性不是WRITEONLY的,则系统还需要先从VM里拷贝一份原始数据到临时缓冲区,这就是为什么不指定WRITEONLY会降低程序性能的原因

总结:

EvictManagedResources清空所有Manager中的资源,切换关卡或者副本时候,确实可以很好的做到提高性能。

高频访问的纹理,最好以D3DPOOL_DEFAULT和D3DPOOL_SYSTEMMEM各创建一份

D3DLOCK_DISCARD能够有效的提高CPU Lock的性能D3DUSAGE_WRITEONLY能防止缓存来回拷贝提高缓存性能。


12.透视投影D3DXMatrixPerspectiveFovLH

使用:

D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
            &proj,
            D3DX_PI * 0.5f, // 90 - degree
            (float)Width / (float)Height,
            1.0f,
            1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj); // 设置变换矩阵和状态,没有真正开始变换,提交后交给图形硬件

1.镜头平移:改变cameraPos用来计算观察位置

2.镜头拉近拉远缩放物体对象:

1).设置观察点的位置,cameraPos用来计算观察位置(没有忽略z值故可以)。

2) fovy z轴和zy上斜线之间夹角变小,那么物体也会变大(aspect不能随便变换否则就不等比例了)。

3.镜头拉高拉低:

1)cameraPos来拉高,y变就可以了,fovy变大那么物体就变小了(3D投影变换不需要这样考虑)

根本原因是:透视投影变换,透视投影中,x,y会被Zoomx,Zoomy放大缩小变换,所以改变CameraPos就可以改变物体的x,y位置,同时可以改变透视投影后的x,y大小值实现近大远小;当然改变fovy值如果fovy变大那么zoomx,zoomy边小,fovy值变小,zoomx,zoomy变大,也可以改变物体的缩放大小。z值是用来深度剔除的,dx中是[0,1],opengl中是[-1,1]。

原型:

D3DXMATRIX* D3DXMatrixPerspectiveFovLH(

  _Inout_  D3DXMATRIX *pOut,

  _In_     FLOAT  fovy, 

  _In_     FLOAT  aspect, 

  _In_     FLOAT  zn,  

  _In_     FLOAT  zf

);

pOut透视变换矩阵,将视锥内的物体变换到(-1,-1,-1)->(1,1,1)的正方体内。

fovy视锥体的上下夹角(6面体),z轴平分该夹角。

 fovy变小时候,因为也要在屏幕90度中用,所以高度方向被放大了,反之fovy变大,高度方向变小。

aspectaspect = w / h,fovy = 90度,由投影矩阵的计算过程,投影yScale = cot(fovy/2); xScale = yScale /aspect.

当屏幕w:h = 100:20时,当aspect = 5:1,那么视锥内的[5,1]正方形截面世界将被变换映射到(1,1)的平面内,

xScale压缩了1/5,当透视投影映射到屏幕坐标时候[5,1],xScale方向需要根据屏幕放大5倍,这样视锥体里面的世界等比缩放到屏幕。

aspect = 1变小;那么yScale = 1, xScale = 1,视锥体内的xy正方形截面[1,1]世界被放置到(1,1); 映射到屏幕为[5,1]xScale映射到屏幕被放大了5倍,yScale不变。

aspect = 10变大,那么yScale = 1,xScale = 1/10,视锥体内的xy正方形截面[10,1]世界->(1,1)->[5,1],xScale被缩小了2倍,yScale不变。

znzfz近裁剪面,z远裁剪面,z视锥体depth深度的改变,映射到屏幕上,也是zn深度变大了,那么屏幕上物体变小了,zn深度变小了,那么屏幕上物体将变大。

透视投影矩阵:

xScale     0          0               00        yScale       0               00          0       zf/(zf-zn)         10          0       -zn*zf/(zf-zn)     0where:yScale = cot(fovY/2)xScale = yScale / aspect ratio


13.D3DXMatrixOrthoLH正交投影

作用:生成一个左手坐标系正交投影矩阵,用于视图坐标到投影坐标系的2D转换。
使用:
D3DXMatrix mOrtho
D3DXMatrixOrthoLH(&mOrtho, WINDOW_WIDTH, WINDOW_HEIGHT, 0.1f, 1000.0f);

g_pd3dDevice->SetTransform(D3DTS_PROJECTION,&mOrtho); // 设置变换矩阵和状态,没有真正开始变换,提交后交给图形硬件实现变换

1.镜头平移:改变cameraPos用来计算观察位置

2.镜头拉近放大物体对象:

1).Z深度值被丢弃了,可以通过放大屏幕投影来变大,那么需要放大正交投影的值,因为正交投影后2/w2/h,所以可以通过缩小正交投影传入的w、h来实现放大;放大传入的w、h可以实现模拟的远离。

3.镜头拉高拉低:

1)cameraPos,x平移,y值变大来拉高;通过放大传入的w、h可以实现模拟的远离缩小

原型:

D3DXMATRIX* D3DXMatrixOrthoLH(
  _Inout_  D3DXMATRIX *pOut, // 输出的变幻矩阵
  _In_     FLOAT w, // 屏幕的宽度
  _In_     FLOAT h, // 屏幕的高度
  _In_     FLOAT zn, // z深度缓存最小值
  _In_     FLOAT zf // z深度缓存最大值
);

得到的变换矩阵为:
2/w  0    0           0
0    2/h  0           0
0    0    1/(zf-zn)   0
0    0    zn/(zn-zf)  1

正交变换的原理:

该正交矩阵x值缩放为2/w, y为2/h是因为裁剪空间需要变换到这个值,因为裁剪空间转换为正交投影后需要除以w = z,那么x,y被变换到[-1,1]所以要有2/w,2/h。的标准的再变换到屏幕中需要除以2的。z值是被变换到[0,1]的。

14.D3D渲染状态汇总

0)、填充模式 SetRenderState(D3DRS_FILLMODE, …); 可设置的模式有:D3DFILL_POINT,D3DFILL_WIREFRAME,D3DFILL_SOLID,分别为点模式、线框模式及实填充模式。

1)、着色模式 SetRenderState(D3DRS_SHADEMODE, …); 可设置的着色模式为:D3DSHADE_GOURAND(默认),D3DSHADE_FLAT,D3DSHADE_PHONG

2)、CullFace相关 SetRenderState(D3DRS_CULLMODE, …); 可设置的Cull模式为:D3DCULL_NONE, D3DCULL_CW, D3DCULL_CCW, 分别为:不剔除背面,按顺时针方向确定背面,按逆时针方向确定背面

3)、ZBuffer相关 SetRenderState(D3DRS_ZENABLE, …); 可设置的值有:D3DZB_FALSE, D3DZB_TRUE, D3DZB_USEW, 分别表示禁用深度缓冲、启用Z-深度缓冲,启用W-深度缓冲

4).全景图形抗锯齿

SetRenderState(D3DRS_MUTISAMPLEANTIALIAS, TRUE)   //抗锯齿
SetRenderState(D3DRS_MUTISAMPLEANTIALIAS, FALSE)   //不抗锯齿

5).设置光照模式

SetRenderState(D3DRS_AMBIENT, D3DCOLOR ambientColor); //为整个场景设置环境光

SetRenderState(D3DRS_SPECULARENABLE, TRUE);   //激活镜面反射计算(D3D默认情况下关闭)

6).设置纹理过滤器

D3DSAMP_MAGFILTER是放大过滤纹理,D3DSAMP_MINFILTER是缩小过滤纹理。

//线性纹理 

SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

  //最近点采样

SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ POINT);

SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

  //各向异性纹理过滤

SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC)

SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ ANISOTROPIC);

7).设置融合

源:SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );

目的:SetRenderState( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA);

第二个参数是 D3DBLEND的枚举结构。


15.D3D渲染物体基本函数

1)CreateVertexBuffer

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);                 // not used - set to 0

2)SetTransform

Device->SetTransform(D3DTS_PROJECTION, &proj); 

3)SetRenderState

设置渲染状态,和状态对应的枚举类型(渲染状态去掉RS_)的值

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

HRESULT SetRenderState(

  [in]  D3DRENDERSTATETYPE State,

  [in]  DWORD Value

);

5)BeginScene

开始在后台缓存区渲染图形,场景渲染开始的标记

任何连续的内存在渲染执行之前需要Present提交到runtime的,都需要BegineScene/EndScene对括起来

(IDirect3DSwapChain9::Present也一样).BegineScene/EndScene对只能并行使用,不能串行使用。

多个BegineScene/EndScene对并行是会对性能有损失的,尽量少用。

6).EndScene

结束在后台缓存区渲染图形 ,这个函数返回,那么资源已经由runtime/driver管理进行排队渲染了,这个函数是非同步的,因此这个函数返回不能保证已经渲染

完了。

7).SetStreamSource

绑定一个顶点缓存到一个设备数据流。
Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex));
HRESULT SetStreamSource(
  [in]  UINT StreamNumber,//指定一个数据流,从[0, streamNum-1].
  [in]  IDirect3DVertexBuffer9 *pStreamData, // 绑定到设备数据流的顶点缓存指针
  [in]  UINT OffsetInBytes,// 输入的顶点缓存的偏移,从0开始是输入整个缓存
  [in]  UINT Stride// 组件的字节跨度,一般是顶点的字节数(特别是FVF vertex shader中),declaration的时候
                  // 必须大于或者等于stream size. 如果顶点缓存被渲染多次的时跨度要用0表示,告诉runtime不要增长顶点缓存偏移。
);

8)SetFVF设置当前的顶点流声明

Device->SetFVF(Vertex::FVF);

IDirect3DDevice9::SetFVF to use the fixed function pipeline指明用固定功能渲染管道。

IDirect3DDevice9::SetVertexDeclaration可以指明用顶点着色器。

9).DrawPrimitive

渲染一个没有索引编制的序列,在数据输入流SetStreamSource中指定的类型的基础几何数据。

Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

HRESULT DrawPrimitive(

  [in]  D3DPRIMITIVETYPE PrimitiveType, // 基础图元的类型D3DPRIMITIVETYPE

  [in]  UINT StartVertex, // 渲染开始的顶点下标

  [in]  UINT PrimitiveCount // 指定图元类型的个数(和图元类型相关),最大个数需要检测D3DCAPS0支持.

);

10).IDirect3DVertexBuffer9

Lock锁定顶点缓存区域和获取顶点缓存的内存指针

IDirect3DVertexBuffer9* Triangle = CreateVertexBuffer(xxx); 

Triangle->Lock(0, 0, (void**)&vertices, 0);

HRESULT Lock(

  [in]   UINT OffsetToLock, // 锁定的起始位置,0是最开始位置

  [in]   UINT SizeToLock, // 锁定的大小,0是全部

  [out]  VOID **ppbData, // 顶点缓存内存指针

  [in]   DWORD Flags // D3DLOCK 0/1个或者多个组合

);

11)CreateIndexBuffer

Device->CreateIndexBuffer(

        36 * sizeof(unsigned short), // 索引缓存的字节数,个数是三角形的个数*3,索引缓存个数还是没有减少的。

        D3DUSAGE_WRITEONLY, // 使用类型为只读类型,获取指针然后写入数据,数据将会批量提交

        D3DFMT_INDEX16, // D3DFMT_INDEX16是16bit,D3DFMT_INDEX32是32bit

        D3DPOOL_MANAGED, // D3DPOOL类型,创建在SM中,需要时候拷贝到AGP内存/显存中

        &IB,

        0);//保留

填充索引缓存, DX中三角形顺时针(左手定则)为正面, 逆时针为背面会被消隐,填充索引缓存时候正向该三角形,左手坐标系顺时针绕向填充即可;OGL则相反。 索引缓存的正向三角形,那么三角形顶点顺序都是顺时针的(平视该三角形)。

Device->SetIndices(IB);关联到数据流。

12)DrawIndexedPrimitive

 Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

HRESULT DrawIndexedPrimitive(

  [in]  D3DPRIMITIVETYPE Type, // 图元的类型,不能使用D3DPT_POINTLIST  [in]  INT BaseVertexIndex, // 顶点缓存的第一个顶点索引的偏移位置,偏移是因为当多个顶点缓存合并成一块全局缓存中时每块都有一个基准的offset值。  [in]  UINT MinIndex, // 顶点缓存开始渲染的最小值  [in]  UINT NumVertices, // 顶点的个数第一个是 BaseVertexIndex + MinIndex开始算的个数  [in]  UINT StartIndex, // 索引缓存开始的位置  [in]  UINT PrimitiveCount // 图元的个数,2 * 6 = 12个三角形);

16.D3D数学基础

1).点乘D3DXVec3Dot
相等加减直接
D3DXVec3Length
D3DXVec3Normalize
数乘直接
2)点乘D3DXVec3Dot,主要计算夹角(投影角)
V1( x1, y1).V2(x2, y2) = x1*x2 + y1*y2
A.B = |A||B|Cos(θ)
FLOAT D3DXVec3Dot(
  _In_  const D3DXVECTOR3 *pV1,
  _In_  const D3DXVECTOR3 *pV2
);

3).叉乘D3DXVec3Cross
叉乘D3DXVec3Cross,主要计算平面的法向量
|A x B| = |A||B|Sin(θ)
a= [a1, a2, a3] =a1i+ a2j+ a3k
b= [b1,b2,b3]=b1i+ b2j+ b3k ;
a × b= [a2b3-a3b2,a3b1-a1b3, a1b2-a2b1]
D3DXVECTOR3* D3DXVec3Cross(
  _Inout_  D3DXVECTOR3 *pOut,
  _In_     const D3DXVECTOR3 *pV1,
  _In_     const D3DXVECTOR3 *pV2
);
4)单位/转置/逆矩阵
单位矩阵:D3DXMatrixIdentity
D3DXMATRIX* D3DXMatrixIdentity(
  _Inout_  D3DXMATRIX *pOut
);

5)转置D3DXMatrixTranspose
D3DXMATRIX* D3DXMatrixTranspose(
  _Inout_  D3DXMATRIX *pOut,
  _In_     const D3DXMATRIX *pM
);

6)逆D3DXMatrixInverse
D3DXMATRIX* D3DXMatrixInverse(
  _Inout_  D3DXMATRIX *pOut,
  _Inout_  FLOAT *pDeterminant, // 行列式的值,如果行列式值为NULL也是可以的,否则用伴随矩阵/行列式值求得矩阵的逆
  _In_     const D3DXMATRIX *pM
);

7)平移D3DXMatrixTranslation
D3DXMATRIX* D3DXMatrixTranslation(  _Inout_  D3DXMATRIX *pOut,  _In_     FLOAT x,  _In_     FLOAT y,  _In_     FLOAT z);

8)旋转D3DXMatrixRotationX/Y/Z
D3DXMATRIX* D3DXMatrixRotationX(  _Inout_  D3DXMATRIX *pOut,  _In_     FLOAT Angle // 弧度角,旋转方向是从旋转轴的正方向往原点看的顺时针方向);

9)缩放D3DXMatrixScaling
D3DXMATRIX* D3DXMatrixScaling(  _Inout_  D3DXMATRIX *pOut,  _In_     FLOAT sx,  _In_     FLOAT sy,  _In_     FLOAT sz);
10)3D点/向量乘以矩阵实现真正物体变换-向量是不考虑位移的/3D点却是要考虑位移的
点乘矩阵:D3DXVec3TransformCoord将结果向量第四个设置为1,D3DXVec3TransformNormal将结果向量第四个设置为0.
//Coordinate是坐标系,基于坐标点的变换,需要将向量解释为2D/3D点
//变换向量将第四位置为1,需要考虑平移(pV->x, pV->y, pV->z, 1)
D3DXVECTOR3* D3DXVec3TransformCoord(  _Inout_  D3DXVECTOR3 *pOut,  _In_     const D3DXVECTOR3 *pV,  _In_     const D3DXMATRIX *pM // 都是考虑平移的矩阵);
// Normal是法向量,就是纯向量的变换,向量是只有大小和方向的,需要将向量解释为2D/3D纯向量
//变换向量将第四位置为0,也就是忽略平移(pV->x, pV->y, pV->z, 0)
D3DXVECTOR3* D3DXVec3TransformNormal(  _Inout_  D3DXVECTOR3 *pOut,  _In_     const D3DXVECTOR3 *pV,  _In_     const D3DXMATRIX *pM //都是考虑平移的矩阵
);

点数组和向量数组乘以矩阵:D3DXVec3TransformCoordArray/D3DXVec3TransformNormalArray.
D3DXVECTOR3* D3DXVec3TransformCoordArray(  _Inout_  D3DXVECTOR3 *pOut,  _In_     UINT OutStride, // 输出数组元素的字节步长,sizeof(D3DVECTOR3)或者sizeof(VERTTEX)都可以  _In_     const D3DXVECTOR3 *pV,  _In_     UINT VStride, // 输入数组元素的步长sizeof(D3DXVECTOR3)  _In_     const D3DXMATRIX *pM,  _In_     UINT n);
D3DXVECTOR3* D3DXVec3TransformNormalArray(  _Inout_  D3DXVECTOR3 *pOut,  _In_     UINT OutStride,// 输出数组步长  _In_     const D3DXVECTOR3 *pV,  _In_     UINT VStride, // 输入数组步长  _In_     const D3DXMATRIX *pM,  _In_     UINT n);
D3DXVec3TransformNormalArray参数和CoordArray一样。

17.视图变换D3DXMatrixLookAtLH

D3DXMATRIX* D3DXMatrixLookAtLH(
  _Inout_       D3DXMATRIX  *pOut,
  _In_    const D3DXVECTOR3 *pEye, // 视图坐标系中新的观察点的位置(可以解释为新的摄像机位置from)
  _In_    const D3DXVECTOR3 *pAt, // 摄像机观察的目标点(标准化后是z轴朝向),一般是(0,0,0)原世界坐标系位置。
  _In_    const D3DXVECTOR3 *pUp // 向上的方向,一般是(0,1,0)
);

返回的新坐标系是:

zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis) // z轴的方向基本就是Up的方向
    
 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  1

/* 之前变换物体,都是假设物体变换到了一个新的坐标系,然后将新坐标系分解得到新的坐标系用旧坐标系的表示,行为新的基向量,列为所有新基向量

在某个轴(原轴)上的贡献,这个新的假设的坐标系就是变换矩阵。

变换物体和变换坐标系之间存在相反的量变换即可,变换顺序可以不用相反。而惯性坐标系到物体坐标系,或者物体坐标系到惯性坐标系之间变换,

却需要相反的量和相反的顺序来进行。

如今,不是变换物体了,而是变换坐标系,是将旧的坐标系变换到一个新的坐标系,所有物体都要相对于新的坐标系来描述位置。一般在世界坐标系到观察坐标系之间,不会缩放而是进行了旋转和平移,

显然上述矩阵的3X3部分负责旋转,后面的dot负值负责平移。平移部分很显然,用新的坐标轴点乘eye也就是投影到eys上的量是相对平移,因为新的坐标系如果是正向平移,

那么世界坐标系中的所有物体需要减去平移的值,如果新坐标系是反向平移那么世界坐标系中所有物体需要加上平移的值。

至于旋转部分,?

*/

18.D3D颜色

0x000000是黑色,0xffffff是白色; Alpha当0x00时候是完全透明的,0xff是完全不透明的

typedef DWORD D3DCOLOR;

D3DCOLOR的创建:

1).D3DCOLOR brightRed = D3DCOLOR_ARGB(255, 255, 0, 0);

2).D3DCOLOR brightGreen = D3DCOLOR_XRGB(0, 255, 0);

#define D3DCOLOR_XRGB(r, g, b)  D3DCOLOR_ARGB(0xff, r, g, b)

3).D3DCOLOR brightBlue = 0xff0000ff;

D3DCOLORVALUE / D3DXCOLOR表示每个颜色float 32位的128位颜色

float的值范围在[0,1],0为黑色,1为白色。

typedef struct _D3DCOLORVALUE {
float r;
float g;
float b;
float a;
} D3DCOLORVALUE;

D3DXCOLOR是D3DCOLORVALUE的类表示,提供了一系列函数。

D3DCOLORVALUE和D3DXCOLOR都可以用一个4D向量来表示,颜色的运算可以类似向量的运算。

一般顶点颜色都是用D3DCOLOR 32位来实现, 在Shader HLSL编程中的顶点着色器就会用D3DCOLORVALUE/D3DXCOLOR的128位颜色进行逼真着色

颜色位移的例子:
uint32_t Color::to_ARGB32() const {
 uint32_t c=(uint8_t)(a*255); // 例如0x0000007F
 c<<=8;      //0x00007F00
 c|=(uint8_t)(r*255);   //0x00007F10
 c<<=8;  //0x007F1000
 c|=(uint8_t)(g*255);  //0x007F1011
 c<<=8; //0x7F101100
 c|=(uint8_t)(b*255);  //0x7F101112
unsigned char red = (unsigned char)(color >> 16);
int nRed = (int)red; // 输出16
 return c; //0x7F101112
}
左右移动只是数值上的操作,ARGB颜色格式在内存中数值就是一个unsigned int整型:ARGB;存储方式在内存中的由底地址到高地址为:BGRA的字节顺序。

19.D3D大小和方向

  1. D3D的(0,0,0)原点在屏幕的中间。
  2. Z轴方向-270度是正对着绘制的物体?。
  3. 点的大小。

Vertex* vertices;

Triangle->Lock(0, 0, (void**)&vertices, 0);

vertices[0] = Vertex(-10.0f, -9.99f, 10.0f);// z改为0.0f那么在屏幕上最近处看不到物体,顶点的大小和z值相关(z值为视体截面的正方形半边长)

vertices[1] = Vertex( 0.0f, 9.99f, 10.0f);

vertices[2] = Vertex( 10.0f, -9.99f, 10.0f);

0 0
原创粉丝点击