Direct3D 12——模板——平面镜效果

这篇具有很好参考价值的文章主要介绍了Direct3D 12——模板——平面镜效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.将实物照常渲染到后台缓冲区内(不包括镜子)。注意,此步骤不修改模 板缓冲区。

2.清理模板缓冲区,将其整体置零。
Direct3D 12——模板——平面镜效果
将实物都绘制到后台缓冲区中,并将模板缓冲区清理为0 (用浅灰色来表示)。
绘制在模板缓冲区中的黑色轮廊线条反映的是:后台缓冲区与模板缓冲区中像素之间的对照关系,而并非模板缓冲区中所绘的实际数据。

3.仅将镜面渲染到模板缓冲区中。若要禁止其他颜色数据写入到后台缓冲区,可用下列设置所创 建的混合状态:
D3D12_RENDER_TARGET_BLEND_DESC::RenderTargetWriteMask = 0;
再通过以下配置来禁止向深度缓冲区的写操作:
D3D12_DEPTH_STENCIL_DESC::DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;

在向模板缓冲区渲染镜面的时候,我将模板测试设置为每次都成功(D3D12_COMPARISON_ALWAYS), 并且在通过测试时用1 ( StencilRef模板参考值)来替换(通过D3D12_STENCIL_OP_REPLACE来 设置)模板缓冲区元素。如果深度测试失败,则应当采用枚举项D3D12_STENCIL_OP_KEEP,使模板缓冲区中的对应像素保持不变。由于仅向模板缓冲区绘制了镜面,因此在模板缓冲区内,除了镜面可见部分的对应像素为1,其他像素皆为0。图下所示的即为更新后的模板缓冲区。换言之,我们其实就是在模板缓冲区中标记了镜面的可见像素而已。
Direct3D 12——模板——平面镜效果
图把镜面渲染到模板缓冲区中,其实就是在模板缓冲区中标记出镜面可视部分的对应像素。
模板缓冲区中实心黑色区域的模板元素取值为1。但请注意,由于被立方体挡住部分的深度测试会失败,所以在模板缓冲区中的这一范围内,元素的取值并不为1
(立方体与黑色镜面重合的部分,也就是立方体位于镜面前方的这一部分)

保证先绘制实物,后将镜面渲染至模板缓冲区的顺序是很重要的。这样一来,深度 测试的失败会令镜面的像素被实物的像素所遮挡,因而也就不必再对模板缓冲区进 行二次修改了。我们并不希望把模板缓冲区中镜面被遮挡部分的值设为1,那样将导致在实物位于镜面前方的范围内也能显示出镜面内容。

4.现在我们来将实物的镜像渲染至后台缓冲区及模板缓冲区中。前面曾提到,只有通过模板测 试的像素才能渲染至后台缓冲区。对此,我们便将其设置为:仅当模板缓冲区中的值为1时, 才能通过模板测试。这可以通过令StencilRef为1,且模板运算符为D3D12_COMPARISON_ FUNC_EQUAL来实现。如此一来,只有模板缓冲区中元素数值为1的实物镜像部分才能得以 渲染。由于只有镜面可见部分所对应的模板缓冲区中元素数值为1,所以仅有这一范围内的实物镜像才能被渲染出来。

5.最后,我们像往常那样将镜面渲染到后台缓冲区中。但是,为了能“透过”镜面观察实物的 镜像(它实际位于镜子的背面。虽说展现的是镜面内的镜像,但实际上是镜面背后的反射实物 与镜面透明混合所得到的效果),我们就需要运用透明混合技术来渲染镜面。若非如此,则由于 实物镜像的深度值小于镜面的深度值,理所当然地会致使实物镜像被镜子挡住。为此,我 们只需为镜面定义一个新的材质配置实例:将其漫反射alpha通道分量设为0.3,使镜子的不透 明度达到30%,

	auto icemirror = std::make_unique<Material>();
	icemirror->Name = "icemirror";
	icemirror->MatCBIndex = 2;
	icemirror->DiffuseSrvHeapIndex = 2;
	icemirror->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.3f);
	icemirror->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
	icemirror->Roughness = 0.5f;

假设已经将实物镜像的像素置于后台缓冲区内,那么,此时我们所看到的镜像颜色30%来自镜子 (源像素),70%出自实物镜像(目标像素)。

定义镜像的深度/模板状态

为了实现上述算法,我们要用到两个PSO对象。第一个用于在绘制镜面时标记模板缓冲区内镜面部 分的像素,第二个则用于绘制镜面可见部分(即不被前侧实物所遮挡部分)内的实物镜像。

	//
	//
	// PSO for marking stencil mirrors.禁止对渲染目标的写操作
	//

	CD3DX12_BLEND_DESC mirrorBlendState(D3D12_DEFAULT);
	mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0; //禁止对渲染目标的写操作

	D3D12_DEPTH_STENCIL_DESC mirrorDSS;
	mirrorDSS.DepthEnable = true;
	mirrorDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;//禁止对渲染目标的写操作
	mirrorDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
	mirrorDSS.StencilEnable = true;
	mirrorDSS.StencilReadMask = 0xff;
	mirrorDSS.StencilWriteMask = 0xff;
	
	mirrorDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
	mirrorDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
	mirrorDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
	mirrorDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
	

	//我们不渲染背面朝向的多边形,因而对这些参数血置并不关心
	// We are not rendering backfacing polygons, so these settings do not matter.]

	mirrorDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
	mirrorDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
	mirrorDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
	mirrorDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;

	D3D12_GRAPHICS_PIPELINE_STATE_DESC markMirrorsPsoDesc = opaquePsoDesc;
	markMirrorsPsoDesc.BlendState = mirrorBlendState;
	markMirrorsPsoDesc.DepthStencilState = mirrorDSS;
	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&markMirrorsPsoDesc, IID_PPV_ARGS(&mPSOs["markStencilMirrors"])));

	//
	// PSO for stencil reflections.用于渲染模板缓冲区中反射镜像的PSO
	//

	D3D12_DEPTH_STENCIL_DESC reflectionsDSS;
	reflectionsDSS.DepthEnable = true;
	reflectionsDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
	reflectionsDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
	reflectionsDSS.StencilEnable = true;
	reflectionsDSS.StencilReadMask = 0xff;
	reflectionsDSS.StencilWriteMask = 0xff;

	reflectionsDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;

	// We are not rendering backfacing polygons, so these settings do not matter.
	reflectionsDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
	reflectionsDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;

	D3D12_GRAPHICS_PIPELINE_STATE_DESC drawReflectionsPsoDesc = opaquePsoDesc;
	drawReflectionsPsoDesc.DepthStencilState = reflectionsDSS;
	drawReflectionsPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
	drawReflectionsPsoDesc.RasterizerState.FrontCounterClockwise = true;
	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&drawReflectionsPsoDesc, IID_PPV_ARGS(&mPSOs["drawStencilReflections"])));

绘制场景

	//绘制不透明的物体
	// Draw opaque items--floors, walls, skull.
	auto passCB = mCurrFrameResource->PassCB->Resource();
	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
    DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
	
	//将模板缓冲区中可见的镜面像素标记为1
	 Mark the visible mirror pixels in the stencil buffer with the value 1
	mCommandList->OMSetStencilRef(1);
	mCommandList->SetPipelineState(mPSOs["markStencilMirrors"].Get());
	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Mirrors]);

	//只绘制镜子范围内的镜像(即仅绘制模板缓冲区中标记为1的像素)
   //注意,我们必须使用两个单独的渲染过程常量缓冲区(per-pass constant buffer)来完成此工作,
   //一个存储物体镜像,另一个保存光照镜像
	// Draw the reflection into the mirror only (only for pixels where the stencil buffer is 1).
	// Note that we must supply a different per-pass constant buffer--one with the lights reflected.
	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress() + 1 * passCBByteSize);
	mCommandList->SetPipelineState(mPSOs["drawStencilReflections"].Get());
	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Reflected]);

	//恢复主渲染过程常量数据以及模板参考值 
	// Restore main pass constants and stencil ref.
	mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
	mCommandList->OMSetStencilRef(0);

	//绘制透明的镜面,使镜像可以与之混合
	// Draw mirror with transparency so reflection blends through.
	mCommandList->SetPipelineState(mPSOs["transparent"].Get());
	DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);

关于以上代码还有一点需要注意,即在绘制RenderLayer: :Reflected层的时候如何来修改其渲染过程常量缓冲区。这是因为在绘制物体镜像的同时,还涉及场景中光照的镜像(即,物体的镜像也 要有与之对应的光照)。光源本存于渲染过程常量缓冲区中,因此我们可以再额外创建一个渲染过程常量 缓冲区,用以存储场景中光照的镜像。该常量缓冲区的设置方法如下:

  PassConstants mMainPassCB;
  PassConstants mReflectedPassCB;
void StencilApp::UpdateReflectedPassCB(const GameTimer& gt)
{
	mReflectedPassCB = mMainPassCB;

	XMVECTOR mirrorPlane = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
	XMMATRIX R = XMMatrixReflect(mirrorPlane);

	// 光照镜像
	for(int i = 0; i < 3; ++i)
	{
		XMVECTOR lightDir = XMLoadFloat3(&mMainPassCB.Lights[i].Direction);
		XMVECTOR reflectedLightDir = XMVector3TransformNormal(lightDir, R);
		XMStoreFloat3(&mReflectedPassCB.Lights[i].Direction, reflectedLightDir);
	}

	// 将光照镜像的渲染过程常量数据存于渲染过程常量缓冲区中索引1的位置
	auto currPassCB = mCurrFrameResource->PassCB.get();
	currPassCB->CopyData(1, mReflectedPassCB);
}

绕序与镜像

当一个三角形被反射到某个平面上时(也就是此三角形在这一平面上的镜像),其绕序(winding order ) 并不会发生改变,正因如此,其平面法线的方向同样保持不变。所以,实际物体的外向法线在镜像中则变为 了内向法线。此时,为了纠正这一点,我们会告知Direct3D将逆时针绕序的三角形看作是正面 朝向,而将顺时针绕序的三角形看作背面朝向。这实际上 是对法线的方向也进行了 “反射”,以此使镜像成为外向朝向。我们可以通过设置下列PSO光栅化属性来改 变绕序的约定:

drawReflectionsPsoDesc.RasterizerState.FrontCounterClockwise = true;

Direct3D 12——模板——平面镜效果文章来源地址https://www.toymoban.com/news/detail-420766.html

多边形的法线不会随着反射操作而调转过来,这使得镜像的法线都变为内向朝向

到了这里,关于Direct3D 12——模板——平面镜效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • DirectX12_Windows_GameDevelop_3:Direct3D的初始化

    查看龙书时发现, 第四章介绍预备知识的代码不太利于学习 。因为它不像是LearnOpenGL那样从头开始一步一步教你敲代码,导致你没有一种整体感。 如果你把它当作某一块的代码进行学习,你跟着敲会发现,总有几个变量是没有定义的。这是因为书上的代码都是把框架里的某

    2024年02月08日
    浏览(44)
  • Direct3D光照

    光照的组成 环境光:这种类型的光经其他表面反射到达物体表面,并照亮整个场景,要想以较低代价粗略模拟这类反射光,环境光是一个很好的选择 漫射光:这种类型光沿着特定的方向传播。当它到达某一表面时,将沿着各个方向均匀反射,无论从哪个方位观察,表面亮度

    2024年02月09日
    浏览(37)
  • Direct3D融合技术

    该技术能使我们将当前要进行光栅化的像素的颜色与先前已已光栅化并处于同一位置的像素的颜色进行合成,即将正在处理的图元颜色值与存储在后台缓存中的像素颜色值进行合成(混合),利用该技术我们可得到各种各样的效果,尤其是透明效果。 在融合运算时需要遵循:首

    2024年02月07日
    浏览(47)
  • Direct3D绘制旋转立方体例程

    初始化文件见Direct3D的初始化_direct3dcreate9_寂寂寂寂寂蝶丶的博客-CSDN博客 D3DPractice.cpp 运行结果

    2024年02月09日
    浏览(44)
  • Character Animation With Direct3D 读书笔记

    2D动画:循环播放多张图片 3D动画: 骨骼动画、变形动画 Win32 应用程序 Application类:处理主程序循环,图形设备的初始化 Init:加载资源并创建图形设备 Update:更新游戏世界,移动对象,更新物理引擎 Render:渲染所有对象,并将结果呈现给屏幕 Quit Cleanup DirectX 渲染循环:

    2024年02月12日
    浏览(41)
  • 三维引擎基础概述(Direct3D、OpenGL、UE、U3D、threejs等)

    一般而言,三维引擎是在三维底层图形技术的基础上,封装硬件操作与三维图形算法,形成普遍意义上的三维交互引擎,提供给开发者一个简单易用、功能丰富的三维图形环境,在此基础上进行虚拟现实、三维交互、可视化管理平台二次开发等,极大提高开发效率。 【底层图

    2024年02月11日
    浏览(47)
  • web3D三维引擎(Direct3D、OpenGL、UE、U3D、threejs)基础扫盲

    三维引擎是指用于创建和渲染三维图形的软件框架。它们通常提供了图形处理、物理模拟、光照、碰撞检测等功能,帮助开发者构建逼真的三维场景和交互体验。在这里,我将为您详细介绍一些常见的三维引擎,包括Direct3D、OpenGL、Unreal Engine、Unity3D和Three.js。 Direct3D是由微软

    2024年02月11日
    浏览(59)
  • 【C/C++】使用C++和Direct3D (d3d)获取屏幕截图并根据传入分辨率进行缩放图片大小

    目录 一,函数清单 1.Direct3DCreate9 函数 2.IDirect3D9::CreateDevice 方法 3.IDirect3DDevice9::GetDisplayMode 方法 4.IDirect3DDevice9::CreateOffscreenPlainSurface 方法 5.IDirect3DDevice9::GetFrontBufferData 方法 6.IDirect3DDevice9::D3DXLoadSurfaceFromSurface 方法 7. D3DXSaveSurfaceToFile 函数 二,关键代码实现 三,最终实现

    2024年01月18日
    浏览(48)
  • 在direct3D中,透明度处理和D2D1_ALPHA_MODE_PREMULTIPLIED含义?

    D2D1_ALPHA_MODE_PREMULTIPLIED 是 Direct2D 中定义的一种 Alpha 模式,用于描述像素颜色值和其 Alpha 通道(透明度)之间的关系。 在非预乘 Alpha (Straight or Unpremultiplied Alpha) 图像中,每个颜色分量(红、绿、蓝)是独立于 Alpha 值的。而在预乘 Alpha 图像中,每个颜色分量已经被其对应的

    2024年01月25日
    浏览(45)
  • direct3d-msaa-抗锯齿算法-教程-涉及概念解析

    交换链(Swap Chain)在计算机图形学和窗口系统中是一个核心概念,它主要用于管理一组缓冲区(通常是帧缓冲区),这些缓冲区用于存储渲染的图像,并且有序地与屏幕显示进行交替更新。 窗口系统中的交换链: 在Windows、Linux等操作系统上的窗口环境中,交换链与图形API(

    2024年01月24日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包