浏览量:1,374

several color model

The eye is a detector of light whose sensitivity to the quality or wavelength of the light has developed into color perception. Color is the only one of several qualities that go to make up our field of vision. The

spacer
浏览量:1,961

高动态范围光

本篇文章谢绝转载,也禁止用于任何商业目的。文章中的源码实现的下载地址参见https://github.com/twinklingstar20/hdr_demo 1. 色阶重建 色阶重建(Tone Mapping)是什么样的一个技术呢,它与高动态光照渲染(High Dynamic Range, HDR)又有什么关系呢?,且听我娓娓道来。 假设你是一名摄影爱好者,一定听过HDR这个词,它的专业称法为高动态范围成像(High Dynamic Range Image, HDRI),是用来实现比普通图像(每个颜色通道占8位)表示的曝光范围更大的一种技术,高动态范围成像的目的就是要正确地表示真实世界中从太阳光直射到最暗的阴影这样大的范围亮度。举个例子来解释,大晴天出门去摄(zhuang)影(bi),拍摄了图1所示的一张图,一定会被人喷不专业,因为你这是想证明你对自然景色更感兴趣呢,还是对中国的文化遗产更感兴趣呢?照顾了天空的曝光,就使得暗部欠缺曝光。 图1. 想更准确的拍摄天空 你为了证明你是爱中国的文化遗产,你想重点关注建筑物,于是你拍摄了另外一张图,如图2所示,确实证明了你的爱,但是背景又是什么鬼,那是霾吗,大北京这么难能可贵的大晴天,却拍出了雾霾的效果。 分析下造成这个问题的原因,简单来说,照相机拍摄的亮度(Luminance)范围是有限的,如果想要亮部更加清晰,特别暗的区域就显得比较黑;相反,如果想要暗部更加清晰,特别亮的区域就会被截断(Clamp to white)成白色,显得特别的亮。我们想要的结果如图3所示,不仅能清楚的显现出建筑的模样,同时还有一个比较清晰的背景,这就是色阶重建技术达到的效果,它把一个高动态范围的亮度,变换为低动态范围(Low Dynamic Range)的亮度,使仅用低动态范围的亮度能清晰、有效地还原场景的效果,PERFECT!!! 图3. 高动态范围成像技术达到的效果图 再举个例子,如图4所示,我们可以用不同的曝光度,拍摄一组图片,由暗到亮,然后采用色阶重建技术把它变换为一组明暗协调的图片,如图5所示。色阶重建技术,又可以细分为全局色阶重建和局部色阶重建,想要了解各种色阶重建技术可以参见Reinhard etc。 图4. 不同曝光度的一组图像 图5. 全局和局部色阶重建后的图像 至此,介绍了高动态范围成像(HDRI)和色阶重建之间的关系,可以简单把色阶重建技术划分为全局色阶重建和局部色阶重建。接下来,又提出一个问题,在实时渲染中,特别在多光源的光照计算中,为什么存在无法渲染高动态范围的问题呢? 在计算机的颜色缓冲区中,存储的颜色范围是,当多光源的光照计算,由于亮度的叠加,容易导致亮度超过1.0,此时,硬件设备(GPU)会把它截断至亮度1.0,大部分情况下做这样一种截断处理是没有问题的。但是如果一个场景中绝大部分的片断(像素)经过多光源的光照叠加,它的亮度都超过1.0,简单的把颜色截断至范围内,那么整个场景有会显得曝光过度,物体的细节无法有效的得到呈现,如图6所示,整块区域就显得白花花的。可以模仿摄影中的色阶重建技术,同时渲染多张不同曝光度的高动态范围的图像,再通过色阶重建技术得到低动态范围的图像。那么问题来了,在实时渲染中,颜色缓冲区会把亮度超过1.0的图像自动截断至1.0,换句话说,就是GL_RGB类型的颜色缓冲区是无法存储高动态范围的帧,此时又如何存储渲染出来的高动态范围的帧呢? 图6. 曝光过度的渲染效果 这就有了新的图像存储格式的诞生,最早由Greg Ward在1985年提出了RGBE 32位的图像存储格式,RGB表示颜色值,E(Exponent)表示RBG颜色的指数系数,通过指定不同的E,就能有效的存储不同高动态范围的图像。后续又出现了多种不同的HDR格式的标准,例如Pixar Log Encoding(TIFF)、Radiance RGBE

spacer
浏览量:11,107

伽马校正

本篇文章谢绝转载,也禁止用于任何商业目的。 首先,解释下伽马(Gamma)是什么鬼。 以一个数字照相机为例,光子打到传感器上,显现出图像,如果有双倍的光子打到传感器,就会有双倍的电子信号,它是一个线性的关系。但是,人眼对光的感知并不是一个线性的关系,与照相机相比,人眼对暗色调会更加敏感些,使得人眼能感知的光照范围更加广(我也不知道为什么!!!)。如图1所示,图(1)人眼观测到的50%亮度的,实际上只有百分之二十多;图(2)是照相机捕获的50%亮度的颜色,明显比图(1)更亮。 图1. 人眼观测到的与照相机检测到的亮度对比 这与伽马又有什么关系呢?伽马建立起了一个照相机捕获的亮度与人眼观察到的亮度的对应关系,称之为伽马编码。设输入和输出的光照分别表示为,伽马系数为,得到关系等式(1),等式(1)的函数示意图如图2所示。的函数变化曲线如图中的红色曲线所示,的函数变化曲线如图中的蓝色曲线所示。 图2. 幂函数的示意图 因为人眼对暗色调(Dark Tone)更敏感,我们在存储图像文件的时候,对颜色进行伽马编码(Gamma Encoding),如图3所示,伽马编码产生的颜色带中暗色范围更宽。以相同的位数来表示颜色(例如8位),线性编码(Linear Encoding)可能需要更多的位数才能表现与伽马编码相同的效果。 图3. 以2.2伽马系数进行编码的颜色表对比图 伽马编码可以使得8位就能有效的描述绝大部分场景,但是它使得图像的存储和呈现过程变得更加复杂。(1)图像的存储过程,颜色通过系数为的幂函数进行处理;(2)图像的显示,存储的颜色,需要通过显示器采用系数的幂函数进行处理,即与图像存储相反的过程,它是显示设备内置的处理过程,我们可以把它理解为所有的显示设备都会行进伽马编码的逆处理。如图4所示,(1)图像伽马处理,把图像保存为JPEG或TIFF,(所有的JPEG格式的文件都会进行伽马编码)会采用系数为的幂函数进行预校正,使得指定的位数有效的表示图像;(2)显示伽马处理,是显示设备对颜色进行的校正,两个过程中和后能有效的呈现的颜色。绝大部分显示设备采用的伽马系数为2.2。 图4. 伽马编码和显示 如果图像伽马处理与显示伽马处理不能达到中和,就会使得呈现出来的图像过暗或者过亮。如图5所示,蓝色表示图像伽马处理曲线,红色表示显示伽马处理曲线,紫色表示两者叠加处理后的函数曲线图,不同的中和结果就会产生不同的效果。 图5. 设图像伽马系数为2.2,与不同的显示伽马系数中和作后呈现出来的效果对比图 至此,我们知道,伽马是什么,为什么需要伽马编码,不同的伽马处理对呈现出来的图像的影响。前面阐述的是伽马编码在摄像机(照相机)从现实生活中捕获图像数据,再呈现到显示设备上影响。而在实时渲染的过程中,图像数据的捕获过程就相当于GPU的渲染过程,它可能没有涉及伽马编码,但是显示设备仍然会偷偷滴地帮我们完成伽马编码的逆处理,那么它会引发什么样的问题呢?很多时候,我们渲染出一帧的图像,都会通过显示设备调整渲染出的效果至到它符合我们预期,其实这个过程也考虑到了显示设备隐藏的逆处理,虽然它调试的显示器上显示正常,可能在不同的伽马系数的显示器就会有不同的呈现效果,而且有些情况,我们需要在渲染上对输出到显示设备的帧数据进行校正,特别是有大量动态范围光照的渲染中。这里引入一个概念,伽马校正(Gamma Correction),它是对显示设备对最终输出颜色逆处理的逆处理过程,没有写错,是逆处理的逆处理。 举个例子来阐述下伽马校正的原理,设颜色,显示设备的伽马系数为经过显示设备的幂函数处理,实际上我们看到它呈现出来的颜色为。但是如果在输出到显示设备前,对它进行伽马校正,即,那么,我们在显示设备上实际看到的颜色为 ,这就是我们真正想表现的颜色。 Vries ,Gritz等,Akenine-Möller都有介绍伽马校正,首先我们要知道伽马的存在,然后在图形渲染,特别是光照计算中,就要留意它可能对呈现出的结果造成的影响。 理解伽马的原理的目的,就是为了使我们能采用合适的伽马校正,达到符合预期的渲染效果,这里再引入一个概念,颜色的线性(Linear)变换和非线性(Nonlinear)变换。设输入值,经过处理,得到输出值,对于线性变换,存在等式: 如果是非线性变换,则等式不成立。如果输入的纹理采用了伽马编码,即它经过幂函数的处理,那么这张纹理上的颜色变化是非线性的,当把它放入Shader处理时,又把它当作线性颜色来处理,则渲染的结果会是错误的,Gritz等阐述了这种错误的处理方式引发的问题。因为,解决伽马引发的问题,需要注意两点: (1)如果输入的纹理是伽马编码方式存储的,那么把它放入Shader计算前,采用伽马编码的逆处理,保证输入的纹理颜色是线性的; (2)对于即将输出到显示器的像素颜色,对它进行伽马校正处理。 最后,介绍OpenGL对伽马校正的支持,OpenGL规范提供了关于伽马的两个扩展,分别为GL_EXT_framebuffer_sRGB和GL_EXT_texture_sRGB。 GL_EXT_framebuffer_sRGB扩展是一种简单粗暴的做法,它把所有即将输入到颜色缓冲区的颜色做伽马系数(绝大部分的显示设备采用的伽马系数)的伽马校正,即幂指数为的函数处理,保证颜色缓冲区中的颜色数据一定是经过伽马校正的结果,调用方法就一行代码: glEnable(GL_FRAMEBUFFER_SRGB); 图6. 多缓冲区的渲染流程 这种做法存在一个问题,我们知道伽马校正后的颜色是非线性的,有些渲染算法需要多通道渲染,会采用多个颜色缓冲区,即输入到颜色缓冲区中的颜色并不是最终输出到显示设备的颜色,如图6所示。缓冲区1~n得到的颜色是非线性的,当各个缓冲区中的颜色再计算的时候,又把这些颜色当做线性的处理,就会引发错误。因此,另外一种做法,是在片断着色器中,对即将输出到显示设备的颜色做伽马校正,由自己来接管伽马校正: void main() { //

spacer
浏览量:885

C++11 note

list initialization Initializes an object from braced-init-list. int list_initialization = { 100 }; int list_initialization{ 100 }; int list_initialization(100); int list_initialization = 100; null pointers nullptr int * p = nullptr; constexpr and constant expressions A constant expression is an

spacer
浏览量:1,936

凹凸纹理

本篇文章谢绝转载,也禁止用于任何商业目的。 代码下载地址:https://github.com/twinklingstar20/BumpMapping 1. 凹凸纹理简介 凹凸纹理(Bump Mapping)是计算机图形学中,使物体表面仿真出褶皱效果的技术,该技术通过(1)扰动对象平面的法向量,(2)利用扰动的法向量进行光照计算,来实现。物体表面呈现出来的褶皱效果,不是由于物体几何结构的变换,而是光照计算的结果,凹凸纹理技术的基本思想最早由James Blinn在1978年提出的。凹凸纹理的效果如图1所示,左图是一个光滑的小球,中间图是一张扰动纹理贴图,通过它来扰动小球平面的法向量,再经过光照计算,就能产生右图所示的带有褶皱表面的小球。 图1. 凹凸纹理效果图 2. Blinn技术 2.1. 数学原理 任何一个三维几何面片,可以用三个带有两个变量的参数形式的表示: 其中,的取值在区间之间,几何面片的局部点的偏微分表示该点的两个方向向量: 单位向量表示与该局部点相切的两个方向的切线,那么该点的法向量可以通过这两个切线向量的叉积得到,如图2所示: 图2. 三维几何面片的法向量 实时渲染中的光照计算,特别是漫反射光和镜面反射光(Phong光照模型),依赖平面的法向量,Blinn技术的原理就是,使用一个扰动函数,对平面的法向量进行扰动,再将扰动后的法向量用于光照的计算。图3(a)~(d)描述了Blinn技术对法向量扰动的基本过程。 图3. 法向量的扰动过程 设扰动函数表示为,原始平面上的一个点 ,经过扰动后的位置为: 而扰动的法向量仍然可以由两个方向向量的偏微分得到: 计算新的位置点在方向上的偏微分,得到: (6)     为了简化问题,可以将上式简化为: (7)   把等式(7)代入等式(5),可以得到: (8)   其中,。 2.2. 算法描述 Blinn技术的算法描述如下所示: 在光照计算之前,对于物体表面上的每个顶点(像素):  查询表面上的每个点在高度贴图(Heightmap)上对应的点;

spacer
浏览量:4,275

Perlin噪声

本篇文章谢绝转载,也禁止用于任何商业目的 1. Perlin噪声 Ken Perlin在1983年提出了一种渐变噪声,Perlin在1985年的SIGGRAPH有该算法的描述,称之为经典Perlin噪声(Classical Perlin Noise)。为了简化计算,方便使用硬件实现,并解决经典Perlin噪声中存在的错误,到2001年,Ken Perlin再次对原始的噪声算法进行了改进,称之为Simplex噪声(Simplex Noise),这两种算法都可以称为Perlin噪声。但是,我们有时候也把分形噪声也称为Perlin噪声,甚至在严肃的学术论文中都有这种称法。为了避免歧义,本文指的Perlin噪声特指经典Perlin噪声和Simplex噪声。 Stefan Gustavson指出:Simplex噪声有更小的算法复杂度,要求更少的乘法,在维空间上,经典Perlin噪声的算法复杂度为,但是Simplex噪声的算法复杂度为等优点。虽然Stefan Gustavson提供了对Simplex算法的注解,但是我依然不能理解Simplex噪声背后的数学原理,对Simplex噪声不作进一步阐述。 2. 经典Perlin噪声 经典Perlin噪声是Ken Perlin在1983年提出的噪声,Ken Perlin提供了一维、二维、三维算法的C实现,我们无法仅从他提供的代码理解其数学原理,Matt Zucker从数学原理的角度,对经典Perlin噪声进行了解读。本节将详细介绍二维、三维的Pernlin噪声的数学原理,算法的C语言实现源码如下所示: /* coherent noise function over 1, 2 or 3 dimensions */ /* (copyright Ken Perlin) */ #include <stdlib.h> #include <stdio.h> #include <math.h> #define

spacer
浏览量:6,591

实时阴影技术

转载请注明原文章链接:http://www.twinklingstar.cn/2015/1717/tech-of-shadows/ 示例代码下载地址:https://github.com/twinklingstar20/twinklingstar_cn_tech_of_shadows/ 1. 阴影介绍 在现实生活中,阴影随处可见,如图1中所示的两个例子,一个温暖窝心,一个浪漫感动。光与物的结合,形成阴影,使得场景更加的真实。如果没有阴影的存在, 这两个场景将变得十分的不自然。 图1. 现实中的阴影 想起高中时学过的一首由马致远创作的小令《天净沙•秋思》 枯藤老树昏鸦 小桥流水人家 古道西风瘦马 夕阳西下 断肠人在天涯 顿时在脑海中闪现一个画面:在深秋村野上,出现了一位漂泊天涯的游子,在残阳夕照的荒凉古道上,牵着一匹瘦马,迎着凄苦的秋风,信步满游,背后拖着长长的身影。 在图形学领域,给出一个阴影的定义: Shadow the region of space for which at least one point of the light source is occluded. (由于光源上存在点被障碍物阻挡而产生的区域,就形成了阴影) 这个定义存在两个局限:(1)只考虑到直接来自于光源的光照,不考虑由平面反射出的光照;(2)默认障碍物是不透明。本篇文章讨论的阴影就基于这两个 “不符合”实际的假设来进行的。 首先,介绍几个与阴影相关的重要概念。阴影渲染中的三个关键元素是:(1)光源,(2)遮挡物(Occluders, Blockers, Shadows

spacer
浏览量:28,952

OpenGL原理介绍

转载请注明原文章链接:http://www.twinklingstar.cn/2015/1532/introduce-to-opengl/ 代码下载地址:https://github.com/twinklingstar20/twinklingstar_cn_demo_introduce_to_opengl 1. OpenGL简介 OpenGL是Open Graphics Library的缩写,是个定义了一个跨编程语言、跨平台的编程接口的标准,显卡通常有OpenGL的实现,不同显卡上的OpenGL实现也不一定相同,OpenGL标准不是平台相关的,所以同一个程序可能在不同的显卡上运行。OpenGL API只处理图形渲染,并不提供动画、定时器、文件IO、图像文件格式处理、GUI等功能,GLUT并不是OpenGL,也不是OpenGL的一部分,它仅是被一些用户用于创建OpenGL窗口。OpenGL不是开源代码,OpenGL指的是开放标准,在网上可以找到,任何人都可以免费下载,也有一个开源的GL实现,名叫 Mesa3D,已经实现了OpenGL 3.0和GLSL 1.30。 OpenGL被当作客户端-服务器系统来实现的,应用程序是客户端,图形硬件厂商提供的OpenGL实现是服务器。如图1所示,客户端程序需要调用OpenGL的接口实现3D渲染,那么OpenGL命令和数据会缓存在RAM中,在一定条件下,会将这些命令和数据通过CPU时钟发送到VRAM,在GPU的控制下,使用VRAM中的数据和命令,完成图形的渲染,并将结果存入帧缓冲区中,帧缓冲区中的帧最终会被发送到显示器上,显示出结果。在现代的图形硬件系统中,还支持不通过CPU时钟直接将数据由RAM发送至VRAM或直接将数据由帧缓冲区发送至RAM(例如OpenGL中的VBO,PBO)。 图1. 计算机图形硬件系统 在一些OpenGL实现中,比如那些与X windows system相关的实现,客户端和服务器在不同的机器上执行,两者通过网络连通起来。在这种情况下,客户端发送OpenGL命令,这些命令被转化成窗口系统相关的协议,再通过共享的网络发送给server。 如图2所示,OpenGL中的顶点、像素等数据需要通过不同阶段的处理,才能产生最后的可视图像,就像是工厂里的生产线,称为图形渲染管线。像素和顶点数据可以选择存储在显示列表中,我们可以把显示列表看成是存储数据的媒介,用于加速渲染速度。顶点数据经过求值器,产生法向量、纹理坐标、点的空间坐标等,通过顶点操作和图元装配,生成相应的像素信息,进行光栅化处理,光栅化是把几何和像素数据转化成片段,每个片段块对应帧缓冲区中的一个像素。其中,顶点操作和图元装配中又可以细分出一条渲染管线,这里称为顶点处理管线。在光栅化完成后,还可以根据命令,对每个像素进行处理,最后写入帧缓冲区内。 图2. OpenGL的图形渲染管线 2. 顶点处理管线 本节介绍如何将三维空间上的图元转化为二维屏幕上渲染出的图元,包括图元的顶点位置、大小等。 顶点的处理管线如图2所示,设我们在三维空间上的坐标处画一个小球,对小球移动至,再绕着坐标轴旋转90度,对小球位移和旋转的处理完成后,这是模型矩阵完成的功能。在空间中放置好模型后,需要架设摄像机,然后才能够观察到模型,架设摄像机,是视图矩阵实现的功能,把这两部分统一起来,就得到模型视图矩阵。接着,需要把小球投影到一个虚拟屏幕上,计算小球的虚拟投影点,这是投影矩阵完成的功能。如果场景中存在多个小球,相对于摄像机的视角,有一部分小球被前面的小球阻挡了,那么被阻挡的小球就不会被渲染出来,裁剪掉被阻挡的模型就是裁剪处理完成的功能。最后,根据屏幕的长宽,把虚拟屏幕映射到真实屏幕上。这就是OpenGL顶点处理的简化流程。接着,详细阐述技术细节。 图3. 顶点处理管线        首先引入齐次坐标的概念,齐次表示是什么?为什么要采用齐次表示呢?在 维空间上,把点和向量扩展一维,就是它们的齐次表示,点的齐次表示为,向量的齐次表示为。一个顶点可以表示为,一个向量则表示为。点表示空间上的一个位置,向量表示一个方向而没有具体的位置,因此点的位移是有意义的,但是向量的位移是没有意义的。采用齐次表示,三维空间上的图形变换包括旋转、位移、透视、正交等都可以用一个的矩阵来表示,矩阵的连乘就是各个矩阵代表的变换的叠加。因此,图3中的模型视图变换、投影变换都可以用一个的矩阵来表示。 2.1.   模型视图变换 我们又可以把模型视图矩阵细分为两个部分,如图4所示,对象坐标先经过模型变换,转化为世界坐标,再经过视图变换,转化为视点坐标。 图4. 模型视图变换 模型变换,只涉及仿射变换(互相平行的两条直线,经过变换后仍然能保持平行),这里介绍其中的3个变换:位移、旋转和缩放。三维空间上的,位移用矩阵表示,则,相当于把齐次坐标移动的偏移量。 (1) 在三维空间上,绕着轴、轴、轴的旋转的矩阵表示,有: (2) 其中,沿着轴相反的方向观察,表示逆时针旋转的角度。 在三维空间上,对模型的缩放变换的矩阵用表示,分别将坐标轴、轴、轴上的分量分别缩放至原先的倍。 (3)

spacer
浏览量:1,492

算法复杂度计算公式

主定理(Master Theorem) 设为常数,f(n)是函数,T(n)为非负整数,且,则有以下结果: (1)若,那么; (2)若,那么有; (3)若,且对于某个常数c和所有充分大的n,有,那么    

spacer
浏览量:2,039

坐标系统的变换

本文主要介绍图形学中坐标系统变换的理论基础。 图1. 坐标系统的变换 以二维为例,如图1所示。设坐标系统,原点在,两条坐标轴分别为,点在坐标系统上的坐标为;类似的,点在坐标系统上的坐标为。设坐标轴,原点经过一个矩阵变换,得到坐标系统的坐标轴和原点,即有: (1)   那么,坐标与之间的关系可以表示为(齐次表示,参见文章《齐次表示》): (2)   注意,等式(1)右侧分别为坐标系统的坐标表示和原点,但是等式(2)的右侧却是坐标系统的坐标信息,这里简单阐述下推导过程: 1. 由坐标系统的坐标表示有: (3)   2. 把(1)代入(3),可以得到:     3. 又,易知等式(2)成立。 进一步,我们可以拓展下坐标系统变换的问题,设有个连续的坐标系统变换,它们满足条件:     其中,。 由上述的推导,我们易知: (4)   再进一步,扩展为三维空间下坐标系统的变换,类似的等式也成立,不再赘述。 图2. 在世界坐标系中的照相机示意图 最后,介绍个图形学中坐标系统变换的实例(这里采用右手坐标系),将坐标由世界坐标系统变换至视点坐标系统,如图2所示,参见《OpenGL原理介绍》。在世界坐标系统下,照相机位于坐标,照相机向着方向观察场景,照相机垂直向上的方向为,因此照相机的配置信息能构造一个视点坐标系统,令,则该视点坐标系统的三条坐标轴分别对应,原点位于。设空间中有一个点,它在世界坐标系下的坐标表示为,它在视点坐标系统下的坐标表示为。结合等式(1)(2)易知,存在一个的齐次矩阵,使得: (5)   则有等式: (6)   由等式(5)且,可以推导出矩阵为: (7)   易知,为:

spacer