D3D depth buffer的预览
在使用D3D开发游戏的过程中,很多情况下都会用到depth buffer来完成特定的效果,比如DOF,Shadows,SSAO等等。在这些情况下我们就可能需要预览depth buffer来确定它是正确的,以免导致后续运算渲染出错。此时有一个问题就出现了,因为原始的depth buffer中保存的depth不是线性的。我们知道,世界坐标系下的顶点在经过视图变换后会被转换到视图空间,此时摄像机在原点,并且我们为摄像机定义了一个近平面和一个远平面:
在经过视图变换后,接着执行的就是投影变换,D3D的透视投影变换矩阵如下,其中,zn就是为摄像机定义的近平面,而zf 就是远平面:
这里,我们因为在讨论depth,所以我们只关心z的变换。z在经过透视投影矩阵的洗礼后,得到的是:
(公式中的z是顶点坐标变换到视图坐标系后的z)
此时的g(z)还不是真正保存到depth buffer中的值,还需要经过perspective divide,也就是我们常说的投影变换后需要进行的步骤:(x, y, z) / w。
最后,我们得到的才是真正保存到depth buffer中的值,他看起来是这样的:
公式1
根据这个公式,我们来看下图,图中我绘制了两条曲线图,其中一条我们定义近平面zn的值为1,远平面zf 的值为100。而另一条我们定义近平面zn的值为10,远平面zf 的值为100:
此时我们就可以发现,随着z的变化,g(z)并不是线性变化的,靠近近平面的很少一部分z值在变换后却占据了绝大部分的g(z)范围,而很大一部分z值在变换后却需要去争抢剩余的很小一部分g(z)范围(题外话:这也就是导致depth buffer精度问题的原因,以及为什么我们常说把近平面和远平面设置的更加靠近可以减少depth buffer的精度问题)。所以当我们在预览depth buffer时,看到的很大情况下都是白茫茫一片,因为绝大部分z值在变换后都位于g(z)的那一小部分范围内(也就是接近1.0的范围)。
那么我们该如何正确的预览depth buffer呢,没错,就是把depth转换回线性的!
那么该如何转换回线性depth值呢,因为顶点从世界坐标系变换到视图坐标系后,此时的z值仍是线性的,所以我们要做的就是将depth值倒推回它在视图空间的z值。根据公式1,我们来计算视图空间的z值:
现在,我们就得到了视图空间的z值,这个值是线性的。但是,我们还不能用这个值来预览depth,我们还必须把它归一化到区间[0, 1],然后才可以存到render target中用于预览。那么如何把视图空间的z值归一化到[0, 1]呢?因为在视图空间中,摄像机位于原点,并且顶点在可见时它的z值会落在区间[zn, zf],所以我们要做的就是把区间[zn, zf]转换到[0, 1],也就是执行操作:(z - zn) / (zf - zn):
好了,至此,我们已经得到了线性的depth,并且它的值是位于区间[0, 1]的。最后,我们只需要把这个值写入render target进行预览就可以了。
下面展示我写的一个预览depth buffer的Demo,部分核心shader代码如下:
//--------------------------------------------------------------------------------------
// Constant buffers
//-------------------------------------------------------------------------------------
cbuffer ViewDepthPerFramePS : register( b0 )
{
float2 f2ClipPlane; // f2ClipPlane.x stores the near plane and f2ClipPlane.y stores the far plane
} //--------------------------------------------------------------------------------------
// Textures and sampler states
//--------------------------------------------------------------------------------------
Texture2D DebugTexture : register( t0 );
SamplerState PointSampler : register( s0 ); float4 DebugOutputViewDepthPS( VS_OUTPUT pInput ) : SV_TARGET
{
float nonLinearizeDepth = DebugTexture.Sample( PointSampler, pInput.texCoords );
float linearizeDepth = (f2ClipPlane.x * nonLinearizeDepth) / (f2ClipPlane.y - nonLinearizeDepth*(f2ClipPlane.y - f2ClipPlane.x)); return float4( linearizeDepth, linearizeDepth, linearizeDepth, 1.0f );
}
最终效果如图:
D3D depth buffer的预览的更多相关文章
- WebRTC 源码分析(二):安卓预览
有过一定相机开发经验的朋友可能会疑惑,预览还有什么好分析的,不是直接 camera.setPreviewDisplay 或者 camera.setPreviewTexture 就能在 SurfaceV ...
- JSP实现word文档的上传,在线预览,下载
前两天帮同学实现在线预览word文档中的内容,而且需要提供可以下载的链接!在网上找了好久,都没有什么可行的方法,只得用最笨的方法来实现了.希望得到各位大神的指教.下面我就具体谈谈自己的实现过程,总结一 ...
- Java实现office文档与pdf文档的在线预览功能
最近项目有个需求要java实现office文档与pdf文档的在线预览功能,刚刚接到的时候就觉得有点难,以自己的水平难以在三四天做完.压力略大.后面查找百度资料.以及在同事与网友的帮助下,四天多把它做完 ...
- .net 实现Office文件预览 Word PPT Excel 2015-01-23 08:47 63人阅读 评论(0) 收藏
先打个广告: .Net交流群:252713569 本人QQ :524808775 欢迎技术探讨, 近期公司要求上传的PPT和Word都需要可以在线预览.. 小弟我是从来没有接触过这一块的东西 感觉很棘 ...
- FlexPaper+SWFTool+操作类=在线预览PDF
引言 由于客户有在线预览PDF格式的需求,在网上找了一下解决方案,觉得FlexPaper用起来还是挺方便的,flexpaper是将pdf转换为swf格式的文件预览的,所以flexpaper一般和swf ...
- fileupload图片预览功能
FileUpload上传图片前首先预览一下 看看效果: 在专案中,创建aspx页面,拉上FileUpload控件一个Image,将用来预览上传时的图片. <%@ Page Language=&q ...
- ReportViewer 不预览,直接导出 PDF文件
作为笔记记着,以免以后再到处找资料 1. 在不预览的情况下导出文件 先看一个方法说明,想知道ReportViewer支持导出哪些文件类型,在Render方法说明中就有描述 // // Summary: ...
- Java+FlexPaper+swfTools仿百度文库文档在线预览系统设计与实现
笔者最近在给客户开发文档管理系统时,客户要求上传到管理系统的文档(包括ppt,word,excel,txt)只能预览不允许下载.笔者想到了百度文库和豆丁网,百度文库和豆丁网的在线预览都是利用flash ...
- springmvc 文件下传、上载、预览。以二进制形式存放到数据库(转载)
springmvc 文件上传.下载.预览.以二进制形式存放到数据库.数据库中的关于传入附件的字段我写了2个:一个存放内容accessory,一个存放文件的后缀filetype 上传:首先需要2个必须的 ...
随机推荐
- [css filter]filter在界面实现滤镜效果
最近逛当当,发现当当尾品会的首页推荐最底端的商品链接是灰色的图片,然后鼠标hover之后就会变成正常的彩色 肯定不是通过img来改变的,然后直接看了一下源码,其实是用的filter属性 _(:з」∠) ...
- Java jdk环境变量配置
首先安装jdk,现在已经是jdk 8了,也不知道能不能好好用了...
- View和监听器
View的基本概念 View就是Activity当中显示出来的控件,用对象来表示,如文本框的TextView类,按钮的Button类等等 每一种控件都对应一个类,都属于View的子类 在Activit ...
- C++ 的全局构造与析构函数
我们知道一般的C/C++ 的程序是从main函数开始的,然后在main函数结束后程序结束.但是不然,在main函数开始执行前,已经有其他的指令被执行了. 为了程序的顺利执行,首先要初始化执行环境,比如 ...
- hdu 1237 简单计算器
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1237 简单计算器 Description 读入一个只包含 +, -, *, / 的非负整数计算表达式, ...
- Android中如何获取应用版本号
- IBM MQ扩大队列最大消息长度
要设置MQ的最大消息长度,需要考虑同时设置队列管理,队列以及通道的最大消息长度. 具体操作如下: runmqsc 队列管理器名称 alter qmgr maxmsgl(10000000) 1 : al ...
- AppDelegate中的方法解析
// 当应用程序启动完毕的时候就会调用(系统自动调用) -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOp ...
- Could not resolve placeholder
使用spring的<context:property-placeholder location="/WEB-INF/redis.properties"/>读取prope ...
- Windows Phone 8 实现列表触底加载
[背景] 很多时候在做WP开发的过程中会遇到数据需要分页获取,根据微软官方的推荐方式,建议实现为Market中类似的体验,即滑动到列表的底部的时候加载更多的数据. 这一需求在早起WP7.1时代实现起来 ...