一步一步实现基于GPU的pathtracer(一):基础

出于3D计算机图形学和图形渲染方面的个人兴趣,脑子里便萌生出了自己实现一个渲染器的想法,主要是借助pathtracing这种简单的算法,外加GPU加速来实现,同时也希望感兴趣的朋友们能够喜欢,也欢迎提出一些更好的看法~~。

(本人水平有限,若有错误也请指正~)

首先列个提纲......:

1)局部光照与全局光照简介

2)GPU并行运算在图形渲染的应用

—————————————————————————————————————————————————

1)pathtracing算法简介:

  在利用计算机表达现实生活景物的思想逐渐成型时,人们最初是利用所谓的局部光照模型来进行物体表面着色的,这种光照模型只能算得上是预览品质,在当时计算能力不高的硬件水平上已经能够达到一个比较满意的效果,这里我们要记住两个人,一个是Phong,一个是Lambert,前者推导出了理想漫反射表面对入射光所遵从的物理模型,后者提出了一个渲染物体表面高光质感的视觉近似模型。这里我们要提前做一些符号约定:规定所有的单位向量均由物体表面内部指向外部,由光线击中处O向光源引出的单位向量记为L,O向视线引出的单位向量为E,O向镜面反射方向的方向引出单位向量,记为R,由O出发指向外侧垂直于O所在表面的单位向量为N,即法线。

  Phong的模型:Phong给出了漫反射表面遵从的物理模型公式,即设漫反射光线强度为I(介于0与1之间),则I正比于E与L之间所成角的余弦值,由于均为单位向量,则

  实际中对比例系数再次进行定义以便更好描述物体表面属性,增加Kd与Id,这里的d为diffuse的缩写,Kd即为漫反射表面自身对光线的反射程度,1表示所有的光不吸收,全部进行漫反射,0则吸收所有入射光,对外呈现纯黑色,Id则为入射光强度,也是介于0~1之间,则

  Lambert模型:Lambert解决了物体表面的高光反射的问题,给出了视觉近似公式,随物体表面粗糙程度的不同,入射光线的所有可能的出射方向由理想镜面反射方向到理想漫反射方向之间过渡,Lambert近似给出在过渡过程中的视觉变化,其公式为

  位于指数次幂的n代表了物体的光滑程度,n越大,则物体表面越光滑,相当于视向量E对于镜面反射向量R越敏感。

  为了更好的描述物体表面,将这两项相加即可,I=Id+Is,所表现的物体表面既有高光反射质感,不进行高光反射的地方可以利用漫反射公式对其进行着色。

  以上所述的两种着色方式是局部光照模型的典型代表,这里的“局部”含义即为:物体表面的亮与暗仅与着色处的一些参量有关,而与场景中其它物体的反射,遮挡等等其它因素均无关,当对下图所示情况进行着色时,局部光照模型无法给出图示处的阴影现象。

  光在场景中的传输过程的本质是很简单的,折射(透射),反射,吸收。其中的反射又可分为漫反射,高光反射与镜面反射,这三种反射是由于物体表面光滑程度的不同而来的。但是,由于现实生活中场景的复杂程度变化多样,这就造成了一些常见的现象:溢色与焦散现象,溢色即如下左图所示(图片来源于网络):红色的物体反射的光线射向墙面使得白色的墙面染上了红色,如同颜色“溢出”到其它物体一样。焦散现象如下右图(图片来源于网络),本质是透射物体对光线的汇聚与分散作用。

  而上述现象对于传统的局部光照模型来讲是无法实现的,全局光照模型则是为了解决上述问题和出于真实感渲染的目的应运而生的,全局光照模型考虑的是光线在场景中如何传输并与场景中的物体进行物理拟真交互的问题,从而得到一张真实度很高的渲染成品,常见的一些全局光照的手段有:基于光子贴图(Photon Mapping)的方法,基于路径跟踪(Path Tracing)的方法,这两种方法,前者从光源处发射光子,并记录光子在场景中传输所产生的记录,后者则是从视线出发对场景进行采样,可以说这两种方法的思路是相反的,但对于表现真实感的场景,都是很好的算法,而且已经应用了很长时间。

2)GPU并行运算在图形渲染的应用:

  GPU的概念最初是由NVIDIA提出的,也就是我们所说的“显卡”,现在的显卡已经由一个传统的游戏设备,逐渐往通用计算领域发展。对于传统游戏设备,现代的GPU能够通过像OpenGL和Direct3D这种即时图形API在屏幕上呈现出即时影像,CPU通过这些API,经由底层驱动给GPU发送绘图数据和绘图指令等等。而对于通用计算领域,CPU则可以通过像CUDA,OpenCL这类API给GPU发送计算指令,计算得到的数据传回CPU进行后续处理。CUDA是NV的,而OpenCL则是一个开放的标准,AMD,Intel,Apple都支持这个标准,目的是利用上任何一个能够参与计算的设备,通用性比CUDA强,但是其效率没有CUDA高。上述的两种全局光照算法均可以在GPU上得以实现,且实现的效率能够超过GPU约两个数量级,这归功于GPU的并行设计理念。而且随着GPU硬件的不断发展,GPU的一些硬件优势也得以体现,如今的GPU的双精度浮点运算能力都要比CPU快很多倍,单精度则更快,同时GPU的显存是没有分页机制的,内部带宽也很高,因此访存延迟要比CPU少很多。这就是在某些场合下,为什么GPU的速度能够远超CPU的原因。

时间: 2024-07-29 22:13:34

一步一步实现基于GPU的pathtracer(一):基础的相关文章

一步一步实现基于Task的Promise库(四)无参数的WorkItem

接着上一篇我直接给出代码,现在支持了new Task(), then(), all(), any() 这些不传参的调用方式. 1 (function(){ 2 var isFunction = function (target) { 3 return target instanceof Function; 4 }; 5 var isArray = function (target) { 6 return target instanceof Array; 7 }; 8 9 //自定义事件管理(代码

一步一步实现基于Task的Promise库(三)waitFor方法的设计

在上一篇中我们已经完成了Task.js里面的all和any方法,已经可以完美的解决大部分需求,我们再来看一个需求: 我们要先读取aa.txt的内容,然后去后台解析,同时由用户指定一个文件,也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了.. 这里的用户是指真正浏览网页的用户,可能是说让用户上传一个文件去读取解析,但是aa.txt是程序定好了的,我们也不希望用户上传文件之后再去读取解析aa.txt,怎么办?如果有一个waitFor方法可以等待另

一步一步实现基于Task的Promise库(一)Promise的基本实现

如果我们现在有一个需求,大概是先读取一个文件的内容,再把得到的内容传给后台去解析,最后把解析后的结果再保存到那个文件,按照最原始的做法代码就是下面这个样子的: 1 //读取文件的原始内容 2 var readFile = function(fileName, callback){ 3 window.setTimeout(function(){ 4 console.log("read '" + fileName + "' complete."); 5 var rawC

一步一步实现基于Task的Promise库(二)all和any方法的设计和实现

在上一篇中我们已经初步完成了Task类,如果仅仅是这些,那么没有多大意义,因为网上这类js库有很多,现在我们来些更复杂的使用场景. 如果我们现在有这样一个需求:我们要先读取aa.txt的内容,然后去后台解析,同时bb.txt也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了..需求很变态,但是我还是想问有没有好的办法呢?按照最原始的嵌套回调的写法好像不是那么容易了,因为你没法知道aa.txt和bb.txt两个文件的读取解析谁先完成,所以你除了要

一步一步教你搭建基于docker的MongoDB复制集群环境

一步一步教你搭建基于docker的MongoDB复制集群环境 1.安装docker 2.创建MongoDB的Image 3.搭建MongoDB的集群 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中. 1.ubuntu14.04安装docker 参考文档 http://docs.docker.com/installation/ubuntulinux/ 参考文档 http://docs.docker.com/mac/started/ pc@pc-Th

2维FFT算法实现——基于GPU的基2快速二维傅里叶变换

上篇讲述了一维FFT的GPU实现(FFT算法实现——基于GPU的基2快速傅里叶变换),后来我又由于需要做了一下二维FFT,大概思路如下. 首先看的肯定是公式: 如上面公式所描述的,2维FFT只需要拆分成行FFT,和列FFT就行了,其中我在下面的实现是假设原点在F(0,0),由于我的代码需要原点在中心,所以在最后我将原点移动到了中心. 下面是原点F(0,0)的2维FFT的伪代码: //C2DFFT //被执行2DFFT的是一个N*N的矩阵,在source_2d中按行顺序储存 //水平方向FFT f

一步一步学习Vue(十一)

本篇继续学习vuex,还是以实例为主:我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码: todolist.js ; (function () { var list = []; var Todo = (function () { var id = 1; return function (title, desc) { this.title = title; this.desc = desc; this.id = id++; } })(); /** *

.NET跨平台:在Mac上跟着错误信息一步一步手写ASP.NET 5程序

今天坐高铁时尝试了一种学习ASP.NET 5的笨方法,从空文件夹开始,根据运行dnx . kestrel命令的错误信息,一步一步写代码,直至将一个最简单的ASP.NET程序运行起来. 尝试的具体步骤如下. 新建一个空文件夹HelloCnblogs: mkdir HelloCnblogs && cd $_ 在这个空HelloCnblogs文件夹中运行 dnx . kestrel 命令(基于CoreCLR的dnx),运行结果是如下的出错信息: System.InvalidOperationEx

一步一步跟我学习lucene(9)---lucene搜索之拼写检查和相似度查询提示(spellcheck)

suggest应用场景 用户的输入行为是不确定的,而我们在写程序的时候总是想让用户按照指定的内容或指定格式的内容进行搜索,这里就要进行人工干预用户输入的搜索条件了:我们在用百度谷歌等搜索引擎的时候经常会看到按键放下的时候直接会提示用户是否想搜索某些相关的内容,恰好lucene在开发的时候想到了这一点,lucene提供的suggest包正是用来解决上述问题的. suggest包联想词相关介绍 suggest包提供了lucene的自动补全或者拼写检查的支持: 拼写检查相关的类在org.apache.