【寒江雪】模板技术实现镜面特效
来源:互联网 发布:excel怎么对比数据 编辑:程序博客网 时间:2024/06/05 02:58
在Direct3D中使用模板缓存,可以实现很多特效。比如镜面特效,阴影等.
关于模板缓存的概念,我在Direct3D9的学习笔记中有记录。这里直接切入正题,讲讲如何在Direct3D11中创建并使用模板缓存
创建模板缓存
模板缓存的创建是跟随者深度缓存一并创建的。也就是说,创建深度缓存的时候顺便创建模板缓存。
创建深度缓存,首先需要描述它,描述深度缓存的同时,顺便描述一下模板缓存。描述深度缓存使用D3D11_TEXTURE2D_DESC结构体。然后使用设备指针调用CreateTexture2D方法即可完成深度,模板缓存的创建。
创建深度模板视图
深度模板缓存创建好之后保存在ID3D11Texture2D指向的内存区。要创建深度模板视图,需要调用设备接口的CreateDepthStencilView方法,将创建好的视图存在内存中,通过接口ID3D11DepthStencilView操作。
设置深度模板视图
深度模板视图创建好之后,我们在设置目标渲染视图的同时,顺便设置深度模板视图,设置视图是通过调用立即执行上下文接口的OMSetRenderTargets方法完成的。
创建深度模板视图的具体步骤
- 描述深度模板缓存
描述深度模板缓存使用D3D11_TEXTURE2D_DESC结构体完成。该结构体的组成如下:
typedef struct D3D11_TEXTURE2D_DESC { UINT Width; UINT Height; UINT MipLevels; UINT ArraySize; DXGI_FORMAT Format; DXGI_SAMPLE_DESC SampleDesc; D3D11_USAGE Usage; UINT BindFlags; UINT CPUAccessFlags; UINT MiscFlags;} D3D11_TEXTURE2D_DESC;
- UINT Width:指纹理宽度,不过这里指窗口宽度
- UINT Height:指纹理高度,这里指窗口高度
- UINT MipLevels:纹理映射级数,多重采样则填1。要生成子纹理的全集,填0。这里设置为1即可
- UINT ArraySize:纹理数组中纹理的数目,至少为1
- DXGI_FORMAT Format:设置数据格式,在这里可以选择的数据格式包括:DXGI_FORMAT_D32_FLOAT_S8X24_UINT和 DXGI_FORMAT_D24_UNORM_S8_UINT。
- DXGI_FORMAT_D32_FLOAT_S8X24_UINT:该格式中,每个像素为8字节(64位),其中深度值占32位,为float型。模板值为8位,为位于[0,255]中的整型,后面24位无任何用途,纯对齐用;
- DXGI_FORMAT_D24_UNORM_S8_UINT:该格式中,每个像素为4字节(32位),其中深度值占24位,并映射到[0,1]之间。模板值为8位,为位于[0,255]中的整型;
- DXGI_SAMPLE_DESC SampleDesc:对纹理多重采样的描述。这里不使用多重纹理。
- D3D11_USAGE Usage:定义纹理读写方式,填D3D11_USAGE_DEFAULT即可
- UINT BindFlags:该标识符定义如何将纹理绑定到渲染管线中。这里填D3D11_BIND_DEPTH_STENCIL。表示将纹理绑定为深度模板的输出目标
- UINT CPUAccessFlags:定义如何访问CPU,用不到则置零
- UINT MiscFlags:定义附加选项的标识,没有则置零
下面是一个使用示例:
D3D11_TEXTURE2D_DESC dsDesc; dsDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; //这里表示24位用于深度缓存,8位用于模板缓存 dsDesc.Width = 800; //深度模板缓存的宽度 dsDesc.Height = 600; //深度模板缓存的高度 dsDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; //绑定标识符 dsDesc.MipLevels = 1; dsDesc.ArraySize = 1; dsDesc.CPUAccessFlags = 0; //CPU访问标识符,0为默认值 dsDesc.SampleDesc.Count = 1; //多重采样的属性,本例中不采用多重采样即, dsDesc.SampleDesc.Quality = 0; //所以Count=1,Quality=0 dsDesc.MiscFlags = 0; dsDesc.Usage = D3D11_USAGE_DEFAULT;
- 创建缓存
描述完成后,通过设备接口指针调用CreateTexture2D方法创建缓存。该方法的原型如下:
HRESULT CreateTexture2D( [in] const D3D11_TEXTURE2D_DESC *pDesc, [in, optional] const D3D11_SUBRESOURCE_DATA *pInitialData, [out, optional] ID3D11Texture2D **ppTexture2D);
- const D3D11_TEXTURE2D_DESC *pDesc:很明显就是刚才我们填的结构体的指针.
- const D3D11_SUBRESOURCE_DATA *pInitialData:该指针指向一个D3D11_SUBRESOURCE_DATA的数组。关于D3D11_SUBRESOURCE_DATA的描述,可以参考MSDN。这里设为NULL即可。
- ID3D11Texture2D **ppTexture2D:最终输出的缓存。
调用示例:
ID3D11Texture2D depthStencilBuffer;hr = (*device)->CreateTexture2D(&dsDesc, 0, depthStencilBuffer);
- 创建深度模板视图
创建深度模板视图需要调用设备接口中的CreateDepthStencilView方法。该方法的原型如下:
HRESULT CreateDepthStencilView( [in] ID3D11Resource *pResource, [in, optional] const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc, [out, optional] ID3D11DepthStencilView **ppDepthStencilView);
- ID3D11Resource *pResource:该指针指向将要被保存为深度模板视图的资源,就是刚才我们创建的ID3D11Texture2D接口
- const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc:该指针是一个指向D3D11_DEPTH_STENCIL_VIEW_DESC结构体的指针,该结构体描述了深度缓存视图中可访问的纹理子资源。在这里不需要,设为NULL
- ID3D11DepthStencilView **ppDepthStencilView:指向深度模板缓存视图接口的指针,我们调用这个方法就是为了初始化这个参数。
下面是一个调用示例:
ID3D11DepthStencilView** depthStencilView;hr = (*device)->CreateDepthStencilView(*depthStencilBuffer, 0, depthStencilView);
- 设置视图
设置视图就是调用立即执行上下文接口的OMSetRenderTargets方法就可以了。下面是调用示例:
(*immediateContext)->OMSetRenderTargets(1, //绑定的目标视图的个数 renderTargetView, //渲染目标视图,InitD3D函数传递的实参 *depthStencilView); //绑定模板
创建渲染状态
在使用模板绘图的时候,可能需要修改一些混合状态。绘制完成后又把状态恢复。所以状态的描述应该提前保存起来。
创建混合状态之前,都需要对其进行描述,描述混合状态使用D3D11_BLEND_DESC结构体来完成。该结构体在混合技术笔记中有提到.
除了混合状态之外,还有深度模板状态。该状态定义比较函数,写掩码等等参数。使用D3D11_DEPTH_STENCIL_DESC描述.
禁止颜色写入
有时候,在渲染的过程中,我们只希望修改深度模板缓冲区部分,而且希望保持后缓冲区中的颜色值,这时候,我们就需要禁止颜色写入。
有两种方法可以禁止颜色的写入。
其中一种是把源混合因子设为D3D11_BLEND_ZERO,把目标因子设为D3D11_BLEND_ONE,这样混合方程中源部分相乘结果为0,目标部分相乘后结果仍为原样。
另外一种方法是直接把描述中的RenderTargetWriteMask设为0,即任何一位都无法写入
下面是一个示例:
//禁止写颜色 D3D11_BLEND_DESC noColorWriteBlendDesc; //混合状态的描述 noColorWriteBlendDesc.AlphaToCoverageEnable = false; //关闭AlphaToCoverage多重采样技术 noColorWriteBlendDesc.IndependentBlendEnable = false; //不针对多个RenderTarget使用不同的混合状态 noColorWriteBlendDesc.RenderTarget[0].BlendEnable = false; //不开启融合 noColorWriteBlendDesc.RenderTarget[0].RenderTargetWriteMask = 0; //写掩码为0,即禁止写入颜色
描述完成后调用设备接口的CreateBlendState方法完成创建.
D3D11_DEPTH_STENCIL_DESC结构体
该结构体定义如下:
typedef struct D3D11_DEPTH_STENCIL_DESC { BOOL DepthEnable; D3D11_DEPTH_WRITE_MASK DepthWriteMask; D3D11_COMPARISON_FUNC DepthFunc; BOOL StencilEnable; UINT8 StencilReadMask; UINT8 StencilWriteMask; D3D11_DEPTH_STENCILOP_DESC FrontFace; D3D11_DEPTH_STENCILOP_DESC BackFace;} D3D11_DEPTH_STENCIL_DESC;
- BOOL DepthEnable:该参数表示是否开启深度测试。需要开启则设为TRUE
- D3D11_DEPTH_WRITE_MASK DepthWriteMask:深度缓存的写掩码,表示哪些位可以写入深度缓存中,该枚举类型只有D3D11_DEPTH_WRITE_MASK_ZERO和D3D11_DEPTH_WRITE_ALL两个,即要么不写,要写就全写的选择。
- D3D11_COMPARISON_FUNC DepthFunc:深度值比较函数,该参数定义了深度测试的操作符。具体可以参考MSDN中对该枚举体的描述。
- BOOL StencilEnable:表示是否开启模板测试
- UINT8 StencilReadMask:模板的读掩码。这里使用默认的读掩码即可——D3D11_DEFAULT_STENCIL_READ_MASK
- UINT8 StencilWriteMask:模板的写掩码。这里使用默认的写掩码即可——D3D11_DEFAULT_STENCIL_WRITE_MASK
- D3D11_DEPTH_STENCILOP_DESC FrontFace:该结构体描述正面模板测试的相关信息。该结构体的内容如下
- D3D11_DEPTH_STENCILOP_DESC
typedef struct D3D11_DEPTH_STENCILOP_DESC {
D3D11_STENCIL_OP StencilFailOp;
D3D11_STENCIL_OP StencilDepthFailOp;
D3D11_STENCIL_OP StencilPassOp;
D3D11_COMPARISON_FUNC StencilFunc;
} D3D11_DEPTH_STENCILOP_DESC; - D3D11_STENCIL_OP StencilFailOp:模板测试失败后的操作
- D3D11_STENCIL_OP StencilDepthFailOp:模板测试成功后,深度测试失败时的操作
- D3D11_STENCIL_OP StencilPassOp:模板测试成功且深度测试也成功后的操作
- D3D11_COMPARISON_FUNC StencilFunc:比较函数
- D3D11_DEPTH_STENCILOP_DESC
- D3D11_DEPTH_STENCILOP_DESC BackFace:该结构体描述背面模板测试的相关信息。与正面模板测试相关信息相似。
下面是一个调用示例:
///填充镜子区域 D3D11_DEPTH_STENCIL_DESC markMirrorDSSDesc; //深度模板描述 markMirrorDSSDesc.DepthEnable = true; //开启深度测试 markMirrorDSSDesc.DepthFunc = D3D11_COMPARISON_LESS; //深度测试比较为“小于” markMirrorDSSDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; //禁止将深度值写入深度模板缓存 markMirrorDSSDesc.StencilEnable = true; //开启模板测试 markMirrorDSSDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; //设置默认读掩码 markMirrorDSSDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;//设置默认写掩码 markMirrorDSSDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; //通过模板测试的条件为“总是” markMirrorDSSDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; //通过测试进行替换操作 markMirrorDSSDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;//模板通过,深度失败则保持不变 markMirrorDSSDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //模板测试失败则保持不变 markMirrorDSSDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; //通过模板测试的条件为“总是” markMirrorDSSDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; //通过测试进行替换操作 markMirrorDSSDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; //测试通过,深度失败则保持不变 markMirrorDSSDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //模板测试失败则保持不变
这些渲染状态通过调用设备接口的CreateDepthStencilState方法来完成。
更多的渲染状态描述这里就不阐述了。
绘制镜子中的箱子
下面通过实例讲解如何绘制镜子中的箱子.
创建深度模板视图就不写出来了。把主要的步骤写出来即可.
创建 半透明效果 的渲染状态
//半透明效果 D3D11_BLEND_DESC blendDesc; ZeroMemory(&blendDesc, sizeof(blendDesc)); //清零操作 blendDesc.AlphaToCoverageEnable = false; //关闭AlphaToCoverage多重采样技术 blendDesc.IndependentBlendEnable = false; //不针对多个RenderTarget使用不同的混合状态 //只针对RenderTarget[0]设置绘制混合状态,忽略1-7 blendDesc.RenderTarget[0].BlendEnable = true; //开启混合 blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; //设置源因子 blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;//设置目标因子 blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; //混合操作 blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; //源混合百分比因子 blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; //目标混合百分比因子 blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; //混合百分比的操作 blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; //写掩码 //创建ID3D11BlendState接口 device->CreateBlendState(&blendDesc, &blendStateAlpha);
创建 关闭背面消隐 的渲染状态
//关闭背面消隐 D3D11_RASTERIZER_DESC ncDesc; //光栅器描述 ZeroMemory(&ncDesc,sizeof(ncDesc)); //清零操作 ncDesc.CullMode = D3D11_CULL_NONE; //剔除特定朝向的三角形,这里不剔除,即全部绘制 ncDesc.FillMode = D3D11_FILL_SOLID; //填充模式,这里为利用三角形填充 ncDesc.FrontCounterClockwise = false;//是否设置逆时针绕续的三角形为正面 ncDesc.DepthClipEnable = true; //开启深度裁剪 //创建一个关闭背面消隐的状态,在需要用的时候才设置给设备上下文 if(FAILED(device->CreateRasterizerState(&ncDesc,&NoCullRS))) { MessageBox(NULL,L"Create 'NoCull' rasterizer state failed!",L"Error",MB_OK); return false; }
创建 描述逆时针为正面 的渲染状态
//设置逆时针为正面 D3D11_RASTERIZER_DESC ccfDesc; //光栅器描述 ZeroMemory(&ccfDesc,sizeof(ccfDesc)); //清零操作 ccfDesc.CullMode = D3D11_CULL_BACK; //不绘制背面 ccfDesc.FillMode = D3D11_FILL_SOLID; //填充模式,这里为利用三角形填充 ccfDesc.FrontCounterClockwise = true; //设置逆时针绕续的三角形为正面 ccfDesc.DepthClipEnable = true; //开启深度裁剪 if(FAILED(device->CreateRasterizerState(&ccfDesc,&counterClockFrontRS))) { MessageBox(NULL,L"Create 'NoCull' rasterizer state failed!",L"Error",MB_OK); return false; }
创建 禁止颜色 的渲染状态
//禁止写颜色 D3D11_BLEND_DESC noColorWriteBlendDesc; //混合状态的描述 noColorWriteBlendDesc.AlphaToCoverageEnable = false; //关闭AlphaToCoverage多重采样技术 noColorWriteBlendDesc.IndependentBlendEnable = false; //不针对多个RenderTarget使用不同的混合状态 noColorWriteBlendDesc.RenderTarget[0].BlendEnable = false; //不开启融合 noColorWriteBlendDesc.RenderTarget[0].RenderTargetWriteMask = 0; //写掩码为0,即禁止写入颜色 if(FAILED(device->CreateBlendState(&noColorWriteBlendDesc,&noColorWriteBS))) { MessageBox(NULL,L"Create 'No Color Write' blend state failed!",L"Error",MB_OK); return false; }
创建 镜子区域绘深度模板测试 的渲染状态
//填充镜子区域 D3D11_DEPTH_STENCIL_DESC markMirrorDSSDesc; //深度模板描述 markMirrorDSSDesc.DepthEnable = true; //开启深度测试 markMirrorDSSDesc.DepthFunc = D3D11_COMPARISON_LESS; //深度测试比较为“小于” markMirrorDSSDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; //禁止将深度值写入深度模板缓存 markMirrorDSSDesc.StencilEnable = true; //开启模板测试 markMirrorDSSDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; //设置默认读掩码 markMirrorDSSDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;//设置默认写掩码 markMirrorDSSDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; //通过模板测试的条件为“总是” markMirrorDSSDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; //通过测试进行替换操作 markMirrorDSSDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;//模板通过,深度失败则保持不变 markMirrorDSSDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //模板测试失败则保持不变 markMirrorDSSDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; //通过模板测试的条件为“总是” markMirrorDSSDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; //通过测试进行替换操作 markMirrorDSSDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; //测试通过,深度失败则保持不变 markMirrorDSSDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //模板测试失败则保持不变 if(FAILED(device->CreateDepthStencilState(&markMirrorDSSDesc,&markMirrorDSS))) { MessageBox(NULL,L"Create 'MarkMirror' depth stencil state failed!",L"Error",MB_OK); return false; }
创建 绘制镜子中的物体时深度模板测试 的渲染状态
//绘制镜子中物体 D3D11_DEPTH_STENCIL_DESC drawRefDesc; drawRefDesc.DepthEnable = true;//开启深度测试 drawRefDesc.DepthFunc = D3D11_COMPARISON_LESS;//深度测试比较为“小于” drawRefDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;//允许将深度值写入深度模板缓存 drawRefDesc.StencilEnable = true;//开启模板测试 drawRefDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;//设置默认读掩码 drawRefDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;//设置默认写掩码 drawRefDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;//通过模板测试的条件为“等于” drawRefDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;//通过测试进行保持操作 drawRefDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;//模板通过,深度失败则保持不变 drawRefDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;//模板测试失败则保持不变 drawRefDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;//通过模板测试的条件为“总是” drawRefDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;//通过测试进行替换操作 drawRefDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;//测试通过,深度失败则保持不变 drawRefDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;//模板测试失败则保持不变 if(FAILED(device->CreateDepthStencilState(&drawRefDesc,&drawReflectionDSS))) { MessageBox(NULL,L"Create 'DrawReflection' depth stencil state failed!",L"Error",MB_OK); return false; }
完整示例代码
https://coding.net/u/HJXCoding/p/MirrorEffect/git
Copyright© by 寒江雪
Date:2017.1.11
- 【寒江雪】模板技术实现镜面特效
- 模板测试与镜面特效专场
- 模板测试与镜面特效专场
- Direct3D---模板测试之镜面特效
- Direct3D学习手记八:模板技术【镜面效果】
- 【Visual C++】游戏开发笔记四十六 浅墨DirectX教程十四 模板测试与镜面特效专场
- 【Visual C++】游戏开发笔记四十六 浅墨DirectX教程十四 模板测试与镜面特效专场
- Android-实现图片的简单特效(平移、缩放、旋转、镜面、倒影)
- 【寒江雪】模板技术
- 网页模板、网页特效
- DirectX学习笔记(九):模板缓存与镜面效果实现
- QT特效技术导读
- JS特效模板精彩案例!
- Jquery特效+前端模板站点
- 模板技术
- 技术面
- 委托、信号和消息反馈的模板实现技术
- 用模板技术实现PHP代码和HMTL代码分离
- Cassandra 3.x官方文档_数据库内部
- 运行新项目的时候 出现 The type javax.servlet.http.HttpServletRequest cannot be resolved.
- leetcode 19. Remove Nth Node From End of List
- 女程序员发展之路
- android studio设置自动导入
- 【寒江雪】模板技术实现镜面特效
- ObjectAnimator设置动画
- android仿ios圆形头像
- javaWeb 08 tomcat服务器
- Android Retrofit 2.0 使用-补充篇
- web.xml is missing and <failOnMissingWebXml> is set to true
- android之FragmentTabHost使用
- Hierarchy Viewer
- python 安装第三方库