Skip to content

Archive

Category: Tech article
前一阵子在把KlayGE的OpenGLES插件升级到OpenGL ES 3的过程中,原先还满怀希望地觉得GLES3总该全面支持浮点纹理的读写了,结果发现GLES3的标准支持float16和float32的读取,但不支持渲染到float16/float32的纹理上。只有支持GL_EXT_color_buffer_float或GL_EXT_color_buffer_half_float扩展的硬件,比如Tegra 4和Adreno 3xx才能很好地支持。所以,在其他设备上如果要渲染到浮点纹理,就得另想办法了。 编码和解码 单通道的float是32-bit,RGBA8也是,所以按说把float编码到RGBA8的纹理中应该没啥问题。很可惜的是,不支持浮点纹理的硬件往往也不支持整数指令和位运算操作。所以在这里需要有些限制。在网上搜了一下,最靠谱的应该是大牛Aras ...
前两年我曾经写过几篇关于AMD显卡上OpenGL驱动的陷阱,但原先我只在NV和AMD的卡上测试过KlayGE的例子,还从来没在Intel的集成显卡上测试过。前段时间曾经在Intel HD3000的笔记本上小测一下,结果惨不忍睹,所有的例子全部黑屏。最近在做KlayGE 4.3的最终测试和优化,就试图找一下失败的原因,以及修复的方法。这里把遇到的一些大坑总结一下,希望对遇到类似问题的朋友有所提示。 GLSL 所有例子都黑屏,最有可能的就是shader挂了。Debug下打开shader错误输出,果然,在NV和AMD驱动上都没事的GLSL遇到了编译失败。错误行是PS里的varying out vec4 v_gl_FragData。如果不用自定义的varying out,而用系统内建的gl_FragData就没事。所以判断应 ...
本系列的前三篇讲的都是关于Deferred Rendering的改进,本篇会专注于流水线后端的Post Process。 Post Process链 在KlayGE的渲染流水线里,不管用不用deferred,post process链是都会执行的。完整的post process链由一系列单独的post process组成,流程如下图所示。 前三个属于HDR的,经过tone mapping转成LDR之后,又经过三次post process,得到渲染结果。如果开了stereo,就会被stereoscopic的post process处理成立体的。 不管是用CUDA里的GPU kernel launch还是用图形API里的Draw Call来启动一个GPU任务,常见的改进规则都是,如果某次GPU任务不依赖于上次任务的其他单元,就应该和上次任务合并起来。这样可以省去GPU写入和读 ...
上一篇提到了在视口间共享shadow map的优化,以及对代码的重构。重构中的一个小发现造就了在不增加存储占用的情况下,就能支持透明物体的渲染。 透明物体和Deep G-Buffer 在透明的烦恼一文中,为了用纯Deferred的框架解决透明物体渲染的问题,KlayGE引入了Deep G-Buffer的方法。对不透明物体、透明物体的背面、透明物体的正面分为三个G-Buffer layer,分别有一条Deferred流水线,最终通过alpha把三层blend成最终结果。这种方法虽然能简单有效地解决问题,并避免繁琐的forward流水线,但需要三倍的存储和带宽。而且如果depth peeling的层数增加,开销还会进一步加大。最近出现的几种OIT方法,都不兼容于deferred。所以如果不用forward,就得 ...
上一篇讲到了把GI系统从Deferred Rendering框架中分离出来,以降低耦合度。本篇会涉及到一个共享shadow map、提高性能的改进。 多视口的改进 多视口的特性是KlayGE 4.2引入的。Deferred rendering layer支持通过多个视口生成多个渲染结果,可以用于分屏、反射、缩略图等情景。原先每个视口都是完全独立渲染的,互相不共享任何东西。实际上spot light和point light的shadow map是view independent的,不会因为视点不同而改变,就应该在视口间共享。 于是开发团队成员李渊完成了这个任务,把shadow map的生成提前到所有视口的G-Buffer之前。也就是说,原先的流水线是: for each view port: generate g-buffer. for each shado ...
从KlayGE 4.0确定了Deferred Rendering的框架以来,每个版本都有一些小改进。在正在开发的4.3里,多个改进经过这几个版本的融会贯通,产生了一些新的变化。这里做个系列总结一下。 GI和Deferred的分离 最早提到这个问题的是团队成员陈顺斌。他在去年就提出Deferred rendering layer太过复杂,应该把相对独立的GI拆出去。当时我的想法是,Deferred和MRSIL GI(Multiresolution splatting for indirect lighting)在逻辑上关联甚大,应该是一体的。后来实现了SSGI,也放在Deferred框架内,复杂度进一步增加。Deferred也成了个带有多种GI方法的怪物,各个组件之间的耦合度很高。 在分析了MRSIL、SSGI以及未来可能支持的SVO等多种GI方法之后 ...
上一篇提到了PSSM的方法,及其它的两个缺点。I3D2011上的Sample Distribution Shadow Maps可以用很低的代价同时解决掉那些缺点,在最大程度上优化shadow map上sample的分布。 SDSM PSSM的那两个缺点实际上都来自于同一个根源:光锥区域是根据视锥的大小,而不是可见pixel的范围来调整。这里所说的pixel范围涉及到两个方面。第一是pixel在view space的深度范围,这会影响区域的划分。另一个是pixel投影到light space的坐标范围,这影响到scale和bias的计算。很显然最佳情况是,shadow map的sample分布在所有可见pixel上,其他地方不浪费。而这两个方面都可以很简单地通过场景的depth texture得到。 原论文提到了多种sample distribution ...
大家一定很熟悉大场景的阴影渲染容易出现的锯齿问题,我这里就不废话了。这个问题常用的解决方式是Cascaded Shadow Map(CSM),用一系列同样大小的shadow map,每个管视锥的一个范围。现在大部分引擎也都支持CSM,各种资料也很齐全,所以我这里不详细阐述原理了。想了解细节的可以看原论文,或者GPU Gems 3的文章。 CSM还是PSSM 一个常见的疑问是为什么有的叫它CSM,有的叫他PSSM(Parallel-Split Shadow Map)。实际上原论文是把它叫做PSSM,工业界实现的时候选择了个更广泛的名字CSM。从名字本身来说,只要是一系列层级关系的shadow map,就能叫CSM,而只有平行切分视锥的才叫做PSSM。换句话说,CSM是个种类,PSSM是具体方法。 PSSM ...
去年4月,Forward+刚出来的时候,我写过一篇介绍的文章。很遗憾的是,原来的paper只比较了Forward+和传统Deferred,甚至是个没怎么好好优化的Deferred。对于Tiled Deferred(TD)的比较,一直都没见到详细的。今年GDC上,终于看到了一个对Forward+和Tiled Deferred的全面性能对比,包括不同光源数,不同render target(RT)个数和是否MSAA。 别的不说,直接看结论阶段。 算法分析 首先是对Forward+和Tiled Deferred的算法分析,列出可能影响性能的地方。     RT数量对比 G-Buffer包含了多少个render target,也就是用多少带宽,对性能应系那个很大。第一轮是关闭MSAA,三角形数量较多(1.25M个),Forward+和RT数 ...
经过前两次实验,大部分C++11里有的boost组件都被替换成了C++11中相应的。剩下的还有random库和bind/function/mem_fn/ref/smart_ptr这一组。看来,到了不得不改代码的时候了。 random 在第一次实验里提到过,random虽然在boost和C++11都有,但接口不相同,所以原先我用Boost.Random实现的代码,无法直接替换成C++11的。翻了一遍boost文档,发现现在的boost其实有实现了一套名字和C++11相同的组件,于是我重写了所有用到random的地方,用和C++11兼容的代码,就解决了这个问题。好在random用得不多,改几个地方就都好了。 bind/function/mem_fn/ref/smart_ptr 这几个组件相互依赖,要么全换,要么不换。再加上牵扯面非常广,修改起来几乎都 ...