一、D3D中的绘制

顶点缓存和索引缓存:IDirect3DVertexBuffer9 IDirect3DIndexBuffer

使用这两缓存而不是用数组来存储数据的原因是,缓存可以被放置在显存中,进行绘制时,使用显存中的数据将获得比使用系统内存中的数据快得多的绘制速度。

静态缓存(static buffer)一般放置在显存中,不需要进行修改,比如地形和城市建筑等。静态缓存必须在程序初始化时用几何体的数据进行填充。

动态缓存(dynamic buffer)一般放置在AGP存储区中,放置动态的内容。优点是更新速度相当快(快速的CPU写操作,方便修改),缺点是处理速度慢,因为在绘制前数据必须传输到显存中。

对显存和AGP存储区进行读操作非常慢,所以,如果您需要程序运行时读取几何数据,最好在系统内存中保留一份副本,然后在需要时对其进行读操作。

Device->CreateVertexBuffer()

Device->CreateIndexBuffer()

D3DVERTEXBUFFER_DESC

D3DINDEXBUFFER_DESC

设置绘制状态:

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

还有很多其他绘制状态可供设置,每个状态都有自己的默认值。

绘制前的准备工作:

(1)指定数据流输入源

Device->SetStreamSource(StreamNum, pStreamData, OffsetInBytes, Stride);

(2)设置定点格式:

Device->SetFVF(D3DFVF_XYZ |D3DFVF_DIFFUSE | D3DFVF_TEX1);

(3)设置索引缓存:

Device->SetIndices(ib);

使用顶点缓存和索引缓存进行绘制:

Device->BeginScene();

         Device->DrawPrimitive(…);

         Device->DrawIndexedPrimitive(…);

Device->EndScene();

绘制Mesh:

ID3DXMesh* mesh = 0;

D3DXCreateTeapot(Device, &mesh, 0);

    Device->BeginScene();

         mesh->DrawSubset(0);

Device->EndScene();

mesh ->Release();

mesh = 0;

D3DX库提供了一些简单的创建几何体的方法D3DXCreate*,可以方便的创建几种常见的模型。

二、颜色

图元的颜色由构成该图元的顶点的颜色决定。 D3DCOLOR(DWORD) D3DCOLORVALUE D3DXCOLOR

FVF:D3DFVF_DIFFUSE

多边形着色(光栅化阶段):根据顶点的颜色来计算构成图元的像素的颜色。有两种着色模式:

平面着色(flat shading)由构成图元的第一个顶点的颜色决定。缺点是块状颜色、没有平滑过渡。

平滑着色(gouraud shading/smooth shading)图元中各像素的颜色值由个顶点的颜色经线性插值得到。

    Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);

    Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

    Device->SetRenderState(D3DRS_LIGHTING, false);

颜色可以看做4D向量,并做加法、减法、对应位的乘法。

三、光照

三种类型的光照:

环境光(Ambient Light);漫射光(Diffuse Light);镜面光(Specular Light)。

每个光源发出的光都有上述三种光照组成。

D3DCOLORVALUE   Diffuse;

D3DCOLORVALUE   Specular;

D3DCOLORVALUE   Ambient;

镜面光计算量很大,D3D默认为不开启,手动开启代码为:

    Device->SetRenderState(D3DRS_SPECULARENABLE, true);  // 启用镜面高光

    Device->SetRenderState(D3DRS_LIGHTING, true);  // 开启光照,默认即是开启的

D3D支持三种光源:

点光源(Point lights),方向光(Directional lights),聚光灯(Spot lights)

对应的类定义:struct D3DLIGHT9

D3DLIGHT9 dirLight;

::ZeroMemory(&dir, sizeof(dir));

dir.Type      = D3DLIGHT_DIRECTIONAL;

dir.Diffuse   = d3d::WHITE;

dir.Specular  = d3d::WHITE * 0.3f;

dir.Ambient   = d3d::WHITE * 0.6f;

dir.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);

     Device->SetLight(0, &dirLight);  // 注册一个光源:

Device->LightEnable(0, true);  // 设置光源的开启状态:

 

材质:

材质用来模拟物体表面对各种颜色光的反射比例。

D3DMATERIAL9 mtrl;

mtrl.Ambient  = d3d::WHITE;

mtrl.Diffuse  = d3d::WHITE;

mtrl.Specular = d3d::WHITE;

mtrl.Emissive = d3d::BLACK;

mtrl.Power    = 5.0f;

Device->SetMaterial(mtrl); // 设置当前材质

DrawObject();

顶点法线:

由于光照计算是对每个顶点进行的,所以每个顶点需要有局部朝向(法线)。

用面的法向量代替顶点的法向量效果会不平滑,所以更好的是取顶点共享的面的法向量的均值。

绘制时,使所有法向量规范化。

Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);

D3DFVF_NORMAL

四、纹理映射       

纹理数据结构:LPDIRECT3DTEXTURE9

进行纹理映射的时间:光栅化时进行,也就是3D三角形已经被变换至屏幕坐标系时。

创建贴图纹理:

D3DXCreateTextureFromFile(device, file, texture);

设置当前纹理:

Device->SetTexture(0, tex);

若第二个参数设为0,表示禁用某一层纹理。

在D3D中,最多可以设置8层纹理,用一个从0开始的索引标记每层。

多重纹理(multitexturing):对多层纹理进行组合以创建一幅更细致的图像。

纹理过滤器:缩小过滤器、放大过滤器

D3D提供了3中类型的filter:

最近点采样(nearest point sampling)默认,速度快,效果差。

线性纹理过滤linear filtering)速度较快,效果相当好。

各向异性纹理过滤(anisotropic filtering)效果最好,速度最慢;可以单独设置各向异性的质量水平

Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

多级渐进纹理Mipmap

Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

多级渐进纹理过滤器,可以取以下三个值:

D3DTEXF_NONE:禁用Mipmap

D3DTEXF_POINT:选择最接近的一级纹理

D3DTEXF_LINEAR:选择最接近的两个纹理,然后进行线性组合,从而形成最终的颜色值。

寻址模式(address mode)

D3D定义了4种用来处理纹理坐标值超出[0, 1]区间的纹理映射模式:

D3DTADDRESS_WRAP重复

D3DTADDRESS_BORDER边界

D3DTADDRESS_CLAMP箔拉

D3DTADDRESS_MIRROR镜像

Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);

Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

五、融合(blending)

将当前计算得到的像素(源像素)颜色值与先前计算所得的像素(目标像素)颜色值进行合成的做法称为融合。

blending在光栅化时进行。

Blending时的渲染顺序很重要,直接影响最终渲染的效果:首先绘制那些不需要进行融合的物体,然后将需要进行融合的物体按照相对于camera的深度值进行排序。如果已经处于观察空间中,则只需要对此时的z分量进行排序。最后自后往前依次绘制需要融合的物体。总之就是先绘制后面的再绘制前面的。

D3D中blending默认是关闭的,可以通过如下方式开启:

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

在渲染透明效果时,先开启该状态。blending的开销并不低,所以(1)只在需要的时候开启,渲染完毕再关闭之;(2)最好进行一些批处理。

融合因子:

Device->SetRenderState(D3DRS_SRCBLEND, source);

Device->SetRenderState(D3DRS_DESTBLEND, destination);

源和目标融合因子的默认值分别是D3DBLEND_SRCALPHA和D3DBLEND_INVSRCALPHA。

Alpha分量主要用于指定像素的透明度。

Alpha值的来源主要有以下两种(一定要设置):

(1)       Alpha通道:如果纹理有alpha通道,则alpha值就取自该alpha通道;

// 根据diffuse color计算alpha

Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

(2)       材质:如果纹理没有alpha通道,则alpha值就取自顶点颜色。

// 根据diffuse color计算alpha

Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);

Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

可以将材质中的alpha值设为0.5来获得透明顶点颜色。

在代码中经常需要切换光照是否开启D3DRS_LIGHTING、Alpha来源(贴图或是顶点颜色)、是否开启融合D3DRS_ALPHABLENDENABLE等状态。

Alpha Blending是我们可以将当前要光栅化的图元中的像素与当前后台缓存中同一位置的像素进行融合。融合因子控制融合方式。

Alpha信息来源也可以手动设置:贴图Alpha通道或是材质的漫反射分量。

六、模板缓存(Stencil buffer)

三大缓存:后台缓存(back buffer)、深度缓存(depth buffer)、模板缓存(stencil buffer)。可用Clear函数对这三类缓存进行清空操作:

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xff000000, 1.0f, 0L);

设置深度缓存开启状态,即是否允许写入depth buffer:

Device->SetRenderState(D3DRS_ZWRITEENABLE, false);

设置模板缓存开启状态,即是否允许写入stencil buffer:

Device->SetRenderState(D3DRS_STENCILENABLE,    true);

Stencil buffer和Depth buffer共享同一个表面存储区,所以二者是同时创建的,可以用D3DFORMAT类型指定Stencil/Depth分别占一个像素的多少位。

模板测试的结果决定了像素的颜色值是否要被写入到渲染目标,像素的深度值是否要被写入深度缓冲。

Stencil可用于阻止某些像素的光栅化,即动态地、有针对性地决定是否将某个像素写入后台缓存中。

查询设备是否支持模板缓存;

开启模板缓存:

Device->SetRenderState(D3DRS_STENCILENABLE,    true);

模板测试(Stencil-Test)

公式: (ref & mask) ComparisonOperation (value & mask)

Ref模板参考值,默认为0,通过D3DRS_STENCILREF设置。

Mask模板掩码,默认为0xffffffff,通过D3DRS_STENCILMASK设置,用于屏蔽ref和mask的某些位。

CoparisonOperation比较函数,通过D3DRS_STENCILFUNC设置。

Value当前像素对应的模板缓存中的值。

模板测试更新:

(1)当stencil-test失败时的行为,通过D3DRS_STENCILFAIL设置

(2)当z-test失败时的行为,通过D3DRS_STENCILZFAIL设置

(3)当z-test和stencil-test都成功时的行为,通过D3DRS_STENCILPASS设置

模板写入掩码(stencil-write mask)

通过D3DRS_STENCILWRITEMASK设置,用于屏蔽写入stencil buffer的某些对应位。

Device->SetRenderState(D3DRS_STENCILENABLE,    true);

Device->SetRenderState(D3DRS_STENCILFUNC,      D3DCMP_ALWAYS);

Device->SetRenderState(D3DRS_STENCILREF,       0x1);

Device->SetRenderState(D3DRS_STENCILMASK,      0xffffffff);

Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);

Device->SetRenderState(D3DRS_STENCILZFAIL,     D3DSTENCILOP_KEEP);

Device->SetRenderState(D3DRS_STENCILFAIL,      D3DSTENCILOP_KEEP);

Device->SetRenderState(D3DRS_STENCILPASS,      D3DSTENCILOP_REPLACE);

利用stencil buffer制作镜像时需要设置镜像物体的绕序:

Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);

可以利用blending打到disable后台缓存的效果:

Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);

Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

实现只写入一次stencil buffer的方法:

Device->SetRenderState(D3DRS_STENCILFUNC,      D3DCMP_EQUAL);

Device->SetRenderState(D3DRS_STENCILREF,       0x0);

Device->SetRenderState(D3DRS_STENCILPASS,      D3DSTENCILOP_INCR);

等于0则模板测试成功,成功后当前值增加,那么写一次测试的时候就不能够测试成功了。

用stencil buffer制作shadow时,先绘制地板,再禁用depth buffer,然后混合绘制阴影体。

D3D的绘制的更多相关文章

  1. [WorldWind学习]20.修改ShapeFileLayer类及托管D3D文字绘制方法

    PluginSDK\ShapeFileLayer.cs Line:1027char[] fieldDataChars = dbfReader.ReadChars(fieldHeaders[j].Fie ...

  2. 2017总结&2018展望

    2017已逝2018已来,是时候放下包袱来好好回顾下2017做了什么,有什么收获,遗憾之处的原因是什么.2018应该怎么做才能让自己满意,才能少一些遗憾. 2017 工作 工作中所参与的项目是一个直播 ...

  3. 【转载】OLE控件在Direct3D中的渲染方法

    原文:OLE控件在Direct3D中的渲染方法 Windows上的图形绘制是基于GDI的, 而Direct3D并不是, 所以, 要在3D窗口中显示一些Windows中的控件会有很多问题 那么, 有什么 ...

  4. ImGUI 1.87 绘制D3D外部菜单

    ImGUI 它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用,该框架通常会配合特定的D3Dx9等图形开发工具包一起使用,ImGUI常用来实现进 ...

  5. Direct3D11学习:(七)绘图基础——彩色立方体的绘制

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 在前面的几篇文章中,我们详细介绍了Direct3D渲染所需要的数学基础和渲染管道理论知识.从这篇文章开始,我们就 ...

  6. [ZZ] D3D中的模板缓存(3)

    http://www.cppblog.com/lovedday/archive/2008/03/25/45334.html http://www.cppblog.com/lovedday/ D3D中的 ...

  7. Direct基础学习系列3 绘制+实例

    3.1.1顶点缓存 索引缓存 放置在显存中能够加快绘制速度 创建顶点缓存 HRESULT CreateVertexBuffer( UINT Length, //为缓存分配的字节数 DWORD Usag ...

  8. D3D的内存类型

    一.对D3D中AGP显存.内存.显存三种内存的解释 三种内存AGP内存(非本地显存),显存(本地内存),系统内存,其中我们都知道系统内存就是咱那内存条,那这AGP内存是个啥玩意啊?其实是因为在以前显卡 ...

  9. DirectX 文本绘制

    在Direct中进行文本绘制,可以通过Win32程序框架实现,也可以通过DXUT进行绘制. 基于第一篇的Win32框架入门实现非常简单,只需要添加数行代码即可.主要说需要修改的地方. #pragma  ...

随机推荐

  1. XCode自动打ipa包脚本 命令

    XCode 新建文件 选择other Shell script  放入下面命令行. #工程绝对路径 #cd $ project_path=$(pwd) #build文件夹路径 build_path=$ ...

  2. 配置JDK时环境变量path和JAVA_HOME的作用

    1.PATH环境变量.作用是指定命令搜索路径,在i命令行下面执行命令如javac编译java程序时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序.需要把jdk安装目录下的bin目录增 ...

  3. C#中服务端接受前端JSON字符串转换成字典集合

    我们是否可以把从前端接受的JSON字符串转换成字典集合呢? 比如从前端接收:{'size':'10', 'weight':'10kg'} 在服务端转换成:[{size:"10"}, ...

  4. ios相关手册、图表等综合

    Objective-C初学者速查表(来源:http://www.cocoachina.com/applenews/devnews/2013/1115/7362.html) iOS UIKit类图 (来 ...

  5. 深入学习golang(5)—接口

    接口 概述 如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键.在Go语言的实际编程中,几乎所有的数据结构都围绕接口展开,接口是Go语言中所有数据结构 ...

  6. CentOS下httpd下php 连接mysql 本机可以,127.0.0.1不能访问

    你看到的这个文章来自于http://www.cnblogs.com/ayanmw php代码很简单: $server="127.0.0.1"; println("Begi ...

  7. 关于Domino数据库的软删除

    在Domino的数据库属性的 “高级” 附签(选择文件->数据库->属性),选中“允许软删除”,这样我们就启用了软删除功能,当一个文档没有删除的时候我们可以使用NotesDatabase的 ...

  8. [sicp]huffman编码的实现 @ Scheme

    #lang racket (define (length items) (if (null? items) (+ (length (cdr items))))) (define (element-of ...

  9. cocos2d-x.0创建工程

    $ python create-multi-platform-projects.py -p PompaDroid -k cn.philon.pompadroid -l cpp

  10. Codeforces Round #160 (Div. 1) 题解【ABCD】

    Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...