Skip to content

Archive

Category: Tech article
Singleton是一个非常常用的设计模式。几乎所有稍大的程序都会用到它。所以构建一个线程安全,并且高效的singleton很重要。既然要讨论这个主题,我们就先来定义一下我们的需求: Lazy initialization。只有在第一次使用的时候才需要初始化出一个singleton对象。这使得程序不需要考虑过多顺序耦合的情况。同时也避免了启动时初始化太多不知道什么时候才会用到的东西。 线程安全。多个线程有可能同时调用singleton。如果只需要单线程,那实在没什么需要讨论的。 高效。因为singleton会被反复调用,如果效率低的话浪费太大了。 通用。适合现有的各种平台,以及未来可能出现的平台。 有了这些需求,我们就可以开始讨论如何构造这么一 ...
上一篇提到了BC7的结构,以及压缩的巨大计算量。本篇将阐述FasTC算法,一种可以快速压缩BC7的方法。 慢的根源 之前讲过,传统BC7压缩之所以慢,是因为需要穷举所有的可能性,从中挑出最好的一种。在这种情况下,最快的实现靠的是GPU的巨大并行度,虽然能解决问题,但效率仍然很低,并依赖于D3D11的CS。 审视BC7的压缩步骤,可以看出首先有64个partition,8个mode,有的mode有2种颜色编码和3种旋转。很显然,占决定性作用的是64个partition。如果能有个算法不需要穷举就能决定一个partition,就能迅速把计算量减少几十倍。 Partition的确定 那么有没有可能直接确定出partition呢?09年刚完成BC6H/BC7 DirectCompute Encoder Tool的时候 ...
DXT到了D3D10之后,就改名为BC(Block Compression)。到了D3D11/OpenGL 4.2时代,又增加了BC6和BC7两种高效的压缩法,分别针对HDR和LDR。但是,由于BC6/7的压缩复杂度远超过以往的BC1-5,D3DX的压缩函数又不是特别给力,限制了它的应用。本系列将专注于介绍一个BC7的快速压缩算法。 和其他BC的比较 BC1的只能用于RGB565,或者RGBA5551。压缩质量不高但速度很快。BC2和BC3的RGB部分和BC1完全一样,都是RGB565。BC2的A是4bit采样,BC3的A是8bit插值。如果要用他们来压缩非颜色信息,比如normal,结果基本都不怎么样。因为最好的BC3也只能提供一个8bit通道和一个6bit通道。 BC4和BC5只有1通道和2通道。BC5在用于normal压缩的时候能提供2个 ...
在KlayGE走上OSX的实验中,我提到了目前OSX的版本还有两个主要问题,一是没法打开post processing,而是shader编译用的是Cg,以至于不能支持GL3+的功能。钱康来这几天又做了一些实验,在很大程度上解决了这些问题。 Post processing 原先一打开HDR、FXAA、Gamma校正等流水线末端的post processing之后,只能看到黑屏或一片混乱。在xcode的调试中看到的是,back buffer中有正确的结果,但swap到front buffer就只有错误的画面。这就排出了是depth或stencil没用清空造成的错误,只能是swap的地方有什么蹊跷。 经过一番尝试和查阅资料,发现了OSX和其他平台在swap上有所不同。Windows上的SwapBuffers,以及Linux上的glXSwapBuffers,都可以 ...
面光源一直是实时渲染的一大难点。原先所有实时渲染中都只敢用点光源(spot光源也是从一个点发射出来的,在这里也算做点光源)。直到这两年,软硬件水平逐步提高了之后,面光源的实时近似才慢慢变得实用起来。 面光源的难处 从ray tracing的角度来说,在计算一个点的光照时,需要根据BRDF沿着反射方向发出多根光线,每一根都需要与光源求交。如果是点光源,那么只要计算一个点和射线求交。如果是个有体积的物体,求交就比较麻烦了,并且需要发射出更多的光线才能逼近真实效果。 在实时渲染中,光照的计算可以分为两部分。第一是来自光源的贡献。点光源可以用常见的光照模型进行计算,最近流行的基于物理的渲染,前提之一就是光源为点光 ...
上一篇完成了specular的环境光渲染。当然,在实际效果中,diffuse也是不可缺少的。在这套基于物理的环境光渲染中,也必须要有diffuse才完整。 Irradiance map GPU Gems 2第10章详细描述了如何通过卷积cube map,得到irradiance map,并用于diffuse的环境光渲染。其基本原理就是,可以把cube map当作一个拥有无数方向光源的物体。场景中的任何一个点,都会受到cube map里所有方向光源的照射,累积起来得到最终结果。 从最基本的光照原理可以得出,对于一个点,只有normal方向的那个半球面会对这个点有影响。而且影响程度按照n dot l的大小来分布。各向同性的纯diffuse情况下,shading和视点方向无关。所以,这里可以用Spherical Harmonic(SH ...
上一篇把BRDF换成了更为常见的blinn-phong,推出了在上面进行importance sampling的公式,以及如何把结果存到一张查找表LUT上。更进一步的做法是把这张LUT拟合成一个曲面,这样就可以在shader中直接计算,省去一次纹理采样。Black Ops II也做了拟合,但它的方法是把F=0和F=1的曲线用F=0.04来表达,最终用一个很粗糙的插值来得到整个曲面。这里我打算用暴力的方法直接拟合整个曲面。 曲线拟合 LUT有两个通道,x表达scale,y表达bias。对于这两个通道,可以表达为f(n_dot_v, roughness)这样的一个函数。原始的LUT大小为128x128,实验中发现LUT本身很平滑,即使缩小到16x16,也不容易从最终渲染结果上看区别。所以这里我们选择16x16的大小作为拟 ...
上一篇重现了UE4的环境BRDF渲染框架。本篇会把GGX换成更常见的Blinn-Phong BRDF。在这个过程中,整个框架仍然保持不变,从importance sampling得到的ground truth开始,逐步推出用prefiltered环境光和预计算的LUT完成基于物理的环境光渲染。只是把BRDF换掉。 采样的细节 上一篇我只是简略地说了ground truth来自于采样1024次,但并没有给出如何计算采样点。这里会有具体的做法。 生成2D空间的随机点$\xi_{\theta}$和$\xi_{\phi}$ 根据BRDF的概率密度函数pdf,从$\xi_{\theta}$和$\xi_{\phi}$计算importance sampling需要的球面坐标系$s_{\theta}$和$s_{\phi}$ 把球面坐标系的$s_{\theta}$和$s_{\phi}$转换成直角坐标系的halfway -re ...
本系列源自于对Real Shading in Unreal Engine 4和Getting More Physical in Call of Duty: Black Ops II的理解。打算按照以前游戏中基于物理的渲染的思路,介绍一下如何在游戏这样的实时应用中使用基于物理的环境光。 回顾 在游戏中基于物理的渲染中列出了渲染方程的简化版,这是整个基于物理的体系的源头。 $L_0(\mathbf{v})=\int_{\Omega} \rho(\mathbf{l},\mathbf{v}) \otimes {L}_{i}(\mathbf{l}) (\mathbf{n} \cdot \mathbf{l}) d \omega_{i}$ 其中,根据microfacet理论,BRDF可以表达成: $\rho(\mathbf{l}, \mathbf{v})=\frac{F(\mathbf{l},\mathbf{h})G(\mathbf{l},\mathbf{v},\mathbf{h})D(\mathbf{h})}{4(\mathbf{n} \cdot \mathb ...
在2010年字体生成工具经历了一次提速,通过只填充边缘、SSE2、Danielsson distance transform后,速度已经较快,而且很难再提升了。前不久一个朋友周赫发现了一篇paper Anti-aliased Euclidean distance transform[1]。该文提供了一个新的生成距离场的算法,只需要较小的灰度图,就能估算出叫高精度的距离场,该算法已经用于freetype-gl。这给KlayGE的字体生成工具提供了一个再次大幅度提速的机会,所以在KlayGE 4.5中,我尝试实现了这个算法。 原算法回顾 原算法的完整描述可以在这里找到。总的来说,可以把距离场的生成概括成这几个步骤。 通过freetype生成光栅化的4096x4096的灰度图,转成二值位图。 轮廓提取,得到4096x4096的轮 ...