D3D的绘制
一、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的绘制的更多相关文章
- [WorldWind学习]20.修改ShapeFileLayer类及托管D3D文字绘制方法
PluginSDK\ShapeFileLayer.cs Line:1027char[] fieldDataChars = dbfReader.ReadChars(fieldHeaders[j].Fie ...
- 2017总结&2018展望
2017已逝2018已来,是时候放下包袱来好好回顾下2017做了什么,有什么收获,遗憾之处的原因是什么.2018应该怎么做才能让自己满意,才能少一些遗憾. 2017 工作 工作中所参与的项目是一个直播 ...
- 【转载】OLE控件在Direct3D中的渲染方法
原文:OLE控件在Direct3D中的渲染方法 Windows上的图形绘制是基于GDI的, 而Direct3D并不是, 所以, 要在3D窗口中显示一些Windows中的控件会有很多问题 那么, 有什么 ...
- ImGUI 1.87 绘制D3D外部菜单
ImGUI 它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用,该框架通常会配合特定的D3Dx9等图形开发工具包一起使用,ImGUI常用来实现进 ...
- Direct3D11学习:(七)绘图基础——彩色立方体的绘制
转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 在前面的几篇文章中,我们详细介绍了Direct3D渲染所需要的数学基础和渲染管道理论知识.从这篇文章开始,我们就 ...
- [ZZ] D3D中的模板缓存(3)
http://www.cppblog.com/lovedday/archive/2008/03/25/45334.html http://www.cppblog.com/lovedday/ D3D中的 ...
- Direct基础学习系列3 绘制+实例
3.1.1顶点缓存 索引缓存 放置在显存中能够加快绘制速度 创建顶点缓存 HRESULT CreateVertexBuffer( UINT Length, //为缓存分配的字节数 DWORD Usag ...
- D3D的内存类型
一.对D3D中AGP显存.内存.显存三种内存的解释 三种内存AGP内存(非本地显存),显存(本地内存),系统内存,其中我们都知道系统内存就是咱那内存条,那这AGP内存是个啥玩意啊?其实是因为在以前显卡 ...
- DirectX 文本绘制
在Direct中进行文本绘制,可以通过Win32程序框架实现,也可以通过DXUT进行绘制. 基于第一篇的Win32框架入门实现非常简单,只需要添加数行代码即可.主要说需要修改的地方. #pragma ...
随机推荐
- JAVA学习Swing章节流布局管理器简单学习
package com.swing; import java.awt.Container; import java.awt.FlowLayout; import javax.swing.JButton ...
- Null Object模式
去除代码中的if(obj==null),或者try/catch语句.维持Code的一致性. Null对象,代表"什么也不做"的一个对象. 使Null对象称为一个匿名内部类确保了该类 ...
- 不能返回函数内部new分配的内存的引用
以前在开发电子秤接口动态库时,曾尝试在用于获取重量的函数外面定义一个字符串指针,然后作为参数传入函数内部,然后在函数内部new,用来输出函数执行过程中发生的错误.但是总是出错,没有找到原因,后来无意中 ...
- 还有人在用SQL Server 2000或2005吗? 2014来了!
你的项目,还在用SQL Server 2000或2005吗? 很多人甚至还没有来得及用过SQL Server 2008,SQL Server 2012,现在SQL Server 2014已经出来了! ...
- GO語言基礎教程:序章
首先自我介紹一下我自己,我是一個coder,目前主要從事B/S程序開發工作,懂點PHP;ASP;JSP;JS;VB;C;DELPHI;JAVA,另外知道幾個數據庫,除此之外別無所長,那麼我為何會選擇學 ...
- 如何将 DVD 转成 ISO
Windows 电脑 + 光驱(Mac 下没找到类似 UltraISO 这么好用的软件,知道的朋友推荐一下哈) 安装 UltraISO 软件(试用版即可),http://baoku.360.cn/so ...
- java string转为xml
一.使用最原始的javax.xml.parsers,标准的jdk api // 字符串转XML String xmlStr = \"......\"; StringReader s ...
- 奇怪吸引子---Russler
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- mac os 中安装memcahed
1.先安装macport sudo port selfupdate #更新当前Marport (如果port 不可以时可以考虑此操作) sudo prot -d selfupdate #替换更 ...
- 记录一下,如何配置nodejs nginx的反向代理
本文是在mac下配置nodejs 在nginx下的反向代理 1.安装nodejs,之前就安装了. 2.安装nginx ,我采用的直接源码安装 3.进入 /usr/local/nginx/conf 目录 ...