引擎设计跟踪(九.14.3.1) deferred shading: Depthstencil as GBuffer depth
问题汇总
1.Light support for Editor
编辑器加入了灯光工具, 可以添加和修改灯光.
问题1. light object的用户互交.
point light可以把对应的volume (wireframe sphere/cone)画出来用于用户选中, 但是光源太多的时候, 球就有点凌乱了. 所以使用了HUD, 只要选中HUD就会选中灯光, 只有灯光被选中的时候才显示volume. 另外, 编辑器里面的很多"不可见"的逻辑对象都有这种需求, 虽然现在还没有. 另外, 可以直接拿deferred shading中的geometry复用, 来显示bounding volume helper, 对于方向光, 需要额外加一个箭头作为helper.
问题2: HUD的picking. 之前的物体picking, 是用3D方法, 拿screen sapce的x,y, 取任意的z(不同的z都投影到x,y), unproject到world space, 再拿world sapce的相机坐标, 构建一个ray (这个ray上的所有点投影到屏幕上都是x,y), 然后用3D空间算法拾取bounding box.
而HUD比较特殊, 如果复用之前的3D方法, 反而很麻烦. 需要根据screen rect反算bounding box, 而且world bounding并不能完全紧凑包围screen rect, 需要使用view space的bounding, 用view sapce ray计算.
考虑之后选择直接在screen space做picking, 这样做的结果是多加了一两个接口, 但是实现起来变得很轻松. 需要注意的是, screen space的z也需要保留, 用来排序出最靠前的对象.
问题3: HUD的icon, 直接使用的是编辑器的资源(64x64 png), 并没有离线压缩, 而是实时压缩为BC3 (DXT5). 另外这个icon需要背景, 用美术资源重复合成的话冗余太多, 同时又不想把贴图个数写死(必须是2?), 所以加了一个新的senmatic来获取texture的个数, 这样在shader里面就可以迭代采样了.
void BladeFSMain(
in float4 pos : POSITION,
in float2 uv : TEXCOORD0,
uniform float4 texutreCount : SAMPLER_COUNT,
uniform sampler2D hudDiffuse[MAX_DYNAMIC_TEXTURE_COUNT], out float4 outColor : COLOR0
)
{
outColor = float4(,,,);
for(int i = ; i < texutreCount.x; ++i)
{
float4 color = tex2D(hudDiffuse[i],uv.xy);
outColor = lerp(outColor, color, color.a);
}
}
2: View Distance v.s. View Depth
(view distance v.s. view space Z)
View space Z 就是camera distance吗? 两者很多时候可以几乎视为等价, 但并不相同.
首先两者都是线性的, 不同的是, distance相同的点构成了一个球面, 而Z相同的点构成了一个与view dir垂直的plane.
由于view space Z由于是z值, 所以可以用于Z buffering(depth write/test), 即可以写入depth stencil; 而view distance不能用于depth test.
| Normalized Linear Depth | Can Be Used As ZBuffer(Depth Testing) | Geometry Points of The Same Value |
| view Distance | NO | sphere |
| view space Z | YES | plane |
而之前的计划为了节省GBuffer, 是准备用INTZ写入深度, 并作为GBufer的depth来采样, 所以Blade使用的View space Z.
然而, deferred shading 里面:
pos = eye_pos + dir * "depth", 实际上这里的depth是viewDist, 即
pos = eye_pos + dir * viewDistance.
对于直接读取depthstencil来说, 拿到的是view Z而不是view Dist. 这个问题之前没有发现, 因为只实现了方向光, 没有用到position.

简单分析可以得出|viewDistance| = |ViewZ| / cos(θ) = |viewZ| / dot(viewDir, dir).
Construct position In View space:
right handed: viewDir = (0,0,-1)
viewZ = tex2D(depthINTZ, uv).r; //normalized linear depth
viewPos = viewDir * (viewZ * farClipDist) / -viewDir.z ;
Construct position In World space:
viewZ = tex2D(depthINTZ, uv).r;
worldPos = worldEyePos + worldDir * (viewZ*farClipDist) / dot( worldLookatDir, worldDir);
这样就可以使用depthstencil作为Gbuffer的depth了. 既可以做depth test, 又能用来构建顶点位置坐标. 这样就不用把normal和depth压缩后挤在同一个buffer,
甚至在使用24位normal时, 还空出一个通道. 目前这个通道用来保存specular的power.
目前Blade的GBuffer如下:
| Component | Format | Attachment | Usage |
| Color | A8R8G8B8 | MRT color 0 | Diffuse:rgb, SpecularLevel:a |
| Normal | A8R8G8B8 | MRT color 1 | WorldNormal:rgb, Specular exponent:a |
| Depth | INTZ | depthstencil | normalized View space Z ZBuffer depth, converted to view space |
Blade 一开始在pixel shader里将normalized view space z输出, 后来因为效率不高, 所以改成了vertex shader里输出常规的z, 然后在deffered shading里根据zbuffer解算view sapce z:
viewZ = convertDepthToViewSpace( tex2D(depthINTZ, uv).r );
worldPos = worldEyePos + worldDir * viewZ* / dot( worldLookatDir, worldDir);
关于convertDepthToViewSpace的计算:
前面已经记录了一个链接, 这里简单记录一下思路. 根据projection matrix
projectedZ = f(viewZ) (linear conversion to [0, zfar] )
projectedW = -viewZ (right handed)
在perspective divide (z/w) 以后:
NDCz = -f(viewZ)/viewZ ranges [-1,1] (OGL) or [0,1] (D3D)
即NDCz = g(z) = a/z + b (non-linear)
其中b = prjoectionMatrix33 = projectionMatrix[2][2], a = projectMatrix34 = projectionMatrix[3][2]
如果忽略viewport 的depth range, 可以认为最终depth buffer里面存储的是NDC space的z,
现在带入projection matrix的参数, 反向计算viewZ = g-1(zbuffer) = a / (zbuffer + b)
只要在CPU端计算好a,b, 在shader里面计算出view space Z,就可以了. 也可以使用invertedProjectionMatrix来直接求出viewSpaceZ.
目前只是尝试阶段, 还没有发现问题, 比如可能的精度不够等等的可能情况(之前使用linear depth就是为了精度问题), 后面再继续完善.
如果精度不够用的话, 可能就需要将view distance直接渲染到MRT里, 不采样depthstencil了.
需要注意的是, 并不是所有SM3.0都支持INTZ, 只有G80以上才支持. 为了简化管线, 在不支持INTZ的显卡上, 直接使用forward shading.
目前Blade支持的shader model有2_0, 2_x, 3_0. 在shader model为3.0的时候, 检测INTZ的支持, 如果不支持,则设置为2_x, 这个细节备忘下, 后面再完善.
其他问题
Light Volume: Calculate Screen UV in Vertex Shader:
只有方向光的quad比较特殊, 可以这么做, shpere和cone是不行的.尝试过了不对. 详细见这里: http://gamedev.stackexchange.com/questions/63870/computing-pixels-screen-position-in-a-vertex-shader-right-or-wrong
UV scale
由于默认backbuffer是desktop的大小, 所以depthstencil创建时也是这么大. 然而使用时是实际窗口的大小, 需要根据viewport的pixel size(或window size)和depthstencil的size, 计算UV的scale, 只采样部分区域, 同时apply half pixel offset, 这个UV的scale和offset在CPU计算并传入pxiel shader.
后面准备完善spot light, 并加上stencil mask.
引擎设计跟踪(九.14.3.1) deferred shading: Depthstencil as GBuffer depth的更多相关文章
- 引擎设计跟踪(九.14.3.2) Deferred shading的后续实现和优化
最近完成了deferred shading和spot light的支持, 并作了一部分优化. 之前forward shading也只支持方向光, 现在也支持了点光源和探照光. 对于forward sh ...
- 引擎设计跟踪(九.14.3.3) Deferred shading的一些小细节
1.ambient light 之前的shader里面, 方向光会加上ambient 的计算. 但是如果没有方向光, 就没有ambient. 这是把全局方向光改为点光源之后发现的, 因为透明物体的fo ...
- 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复
由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...
- 引擎设计跟踪(九.14.3) deferred shading 准备
目前做的一些准备工作 1.depth prepass for forward shading. 做depth prepass的原因是为了完善渲染流程, 虽然架构上支持多个pass, 但实际上从来没有测 ...
- 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现
因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...
- 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善
最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVert ...
- 引擎设计跟踪(九.14.2g) 将GNUMake集成到Visual Studio
最近在做纹理压缩工具, 以及数据包的生成. shader编译已经在vs工程里面了, 使用custom build tool, build命令是调用BladeShaderComplier, 并且每个文件 ...
- 引擎设计跟踪(九.14.2f) 最近更新: OpenGL ES & tools
之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...
- 引擎设计跟踪(九.14.2d) [翻译] shader的跨平台方案之2014
Origin: http://aras-p.info/blog/2014/03/28/cross-platform-shaders-in-2014/ 简译 translation: 作者在2012年写 ...
随机推荐
- 增强for、iterator迭代器
因为初学java,对部分语法还模棱两可, 在做练习的时候,用增强for遍历字符串编译报错 所以来复习下增强for原理和适用范围 一.增强for概念 增强for(也成为for each循环)是JDK 1 ...
- ansj分词
本文转载至:https://blog.csdn.net/bitcarmanlee/article/details/53607776 最近的项目需要使用到分词技术.本着不重复造轮子的原则,使用了ansj ...
- java——类、对象、方法
一.类 1.Java语言把一组对象中相同属性和方法抽象到一个Java源文件就形成了类. 一个java文件可以有多个类,但是每一个类都会生成一个class字节码文件. 如果class 前加public ...
- C++ Coroutine简明教程
在C++里,一个函数如果其函数体实现中包含co_await.co_yield.co_return中任何一个关键字,那么这个函数就是一个coroutine.其中: co_await:挂起当前的corou ...
- linux下anaconda和keras配置过程
连接服务器,使用ssh协议. 下载anaconda bash Anaconda3-5.1.0-Linux-x86_64.sh(安装过程需要输入yes来添加环境变量,需要输入一次安装路径.) 因为环境变 ...
- Number and String in JS
Number 整数 小数(浮点数) 小数参与运算 NaN 其他数据类型转换成数字 String 其他数据类型转换成字符串 Number.Boolean.String的相同点 Number 虽然 ...
- 五、stdout,stdoin和stderr
stdout,stdin和stderr分别是标准输出流.标准输入流和标准错误流,当一个用户进程被创建的时候,系统会自动为该进程创建这三个数据流,默认情况下这三个流是在终端上表现出来的.可以使用fpri ...
- 泊爷带你学go -- 经典的继承与接口 简直吊炸天 !
package main import ( "fmt" ) type TeamBase struct { m_TeamId uint64 m_Rid uint32 m_RoomRu ...
- callback回调函数的理解
callback采用的设计模式是:模板模式,他的设计理念是基于面向对象中的多态的. 我们的程序中走到某个地方他会出现不一样的动作的时候,我们在这儿就使用回调函数.我们利用的就是 多态的原理,我们传递不 ...
- SMS PDU编码数据串格式分析
PDU协议数据单元详细介绍 PDU 相当于一个数据包,它由构成消息(SMS)的信息组成.作为一种数据单元,它必须包含源/目的地址.保护(有效)时间.数据格式.协议类型和正文,正文长度可达140字节,它 ...