OptiX quick start 01

本文是optix自带的文档的翻译,本人初学者,英文水平很有限,仅作为自学与交流之用,如有大神能指正其中错误,本人将感激不尽。

optix的sdk提供了一个源码例子tutorial

这个例子演示了如何实现一些基本的光线跟踪效果。从简单的例子慢慢到一些相对复杂的例子。本例包含了十一个步骤,每一个例子都会在原来的基础上添加一些新的特效。在这一章节,我们会讨论每一个阶段和展示包括shading和intersection在内的程序。

本教程将会将注意力集中在CUDA  C的编程机制上,而不会花时间去讲解如何在主机端构架对象。完整的CUDA C代码以及主机应用编程接口部分都包含在SDK 中。本教程的目的只是让您可以快速入门optix。更加高级的内容,比如访问程序还有加速结构,都可以SDK 中找到。其他的更加高级的渲染技术和科学计算也将不会包含在本教程中。

在optix中最常见的程序就是closest hit。每当optix发现光线和物体的最近的交点,这个程式都会执行。通常这个程序的作用或者目的就是来决定光线与物体相交的点的颜色。用户可以创建很多个这样的程序并把他们绑定到场景中的物体上去。这样一来场景中的不同的物体也许就会呈现出不同的外观。这本教程中我们设置了一个closest hit函数并把他绑定到场景中的所有物体上。这个程序是一个normal shader----它将物体的法向量转换到世界空间,并调整比例,使得每一个组成部分都介于0和1之间。由此获得的结果(x,y,z)向量会被直接转换为颜色信息,并存储到跟光线相关的有效信息(payload理解为有用的信息,就是说某个信息载体如缓冲区,或者某个文件中所存储的有价值的数据:只是我个人理解,觉得这么翻译才有意义)中。

 

RT_PROGRAM void closest_hit_radiance0()

{

prd_radiance.result = normalize(rtTransformNormal(

RT_OBJECT_TO_WORLD,

shading_normal))

*0.5f+0.5f;

}

上面的程序提到一个变量名shading_normal。这个交叉程序会被盒子和地板(并没有在这里展示可以去SDK中查询具体代码)共同使用,所以一旦交叉点被发现,他们都会去计算这个变量的值。因为这个变量将会被多个程序共享,所以必须用下面的方式去指定它:

rtDeclareVariable(float3,

shading_normal,

attribute shading_normal, );

返回的结果颜色将会被写到另一个叫做prd_radiance的变量中。这是一个用户自定义的结构的实例,这里面包含了跟每一条光线相关的数据。在这个例子中,我们将会写一个float3类型的color到这个叫做result的结构体中。这个结构的另外两个元素的信息将会在后面展示。

struct PerRayData_radiance

{

float3 result;

float importance;

int depth;

};

rtDeclareVariable(PerRayData_radiance,

prd_radiance, rtPayload, );

我的注释: rtDeclareVariable(总的数据类型, 第一个成员变量, 第二个成员变量, 第三个成员变量);

 

 

 

shading_normal 和prd_radiance这两个变量并没有什么特别之处。rtDeclareVariable的第三个大量使用的声明叫做semantic name,它用来将这些变量绑定到系统中正确的地方。而这里我们使用rtPayload作为语意上的名字好让optix知道这个数据结构是与每一条光线都相关联的。光线的有效信息中的result这部分,将会被拷贝到raytracer的输出中,raytracer在下面的单独的程序中。

 

除了closest hit外,我们还需指定一个miss 程序。Miss程序会在光线不与任何物体相交时执行。在这种情况下,我们只将返回颜色值设置为一个用户自定义的值就行,这个变量叫做bg_color(实际可以理解为背景颜色——自己的理解)。

rtDeclareVariable(float3, bg_color, , );

RT_PROGRAM void miss()

{

prd_radiance.result = bg_color;//从这里就可以知道,最后返回的像素颜色是存储在//prd_radiance.result中的

}

bg_color的值是host端设置的,而且可以在不同的raytracer的调用间修改。这是optix和主机端最常见的交流机制。Optix还提供变量间的继承机制。但是这些细节将不会在此探讨。

为了创建这些光线,我们将会使用针孔相机模型。这里的ray generation program就是用来创建一条光线的,就是发射一条光线到场景中,然后将结果颜色复制到一个output buffer(输出缓冲区)。输出缓冲区接下来将会交由host端做进一步的分析处理,或者交给opengl进行绘制(渲染)。Optix可以将数据写到任意数目的输出缓冲区中,而且这些缓冲区的类型可以是任意的。本例中的单输出缓冲区是一个二维的,RGBA8格式的映像(理解为像素数据的二维数组就行),这样设计是为了可以更高效的将数据转换为opengl纹理。辅助函数make_color(这里并没有展示

)将会准确的把浮点类型的RGB颜色转换为RGB8 int类型的值(optix中RGB分量的值是浮点类型的,而opengl中我们处理的时候,RBG值是int类型就行)。scaling and clamping as necessary。(后置定语不翻译了)

RT_PROGRAM void pinhole_camera()

{

size_t2 screen = output_buffer.size();

float2 d = make_float2(launch_index) /

make_float2(screen) * 2.f - 1.f;

float3 ray_origin = eye;

float3 ray_direction = normalize(d.x*U + d.y*V + W);

optix::Ray ray(ray_origin, ray_direction,

radiance_ray_type, scene_epsilon );

PerRayData_radiance prd;

prd.importance = 1.f;

prd.depth = 0;

rtTrace(top_object, ray, prd);

output_buffer[launch_index] = make_color( prd.result );

}

这个程序里面最重要的部分就是调用rtTrace.在这个函数中有三个声明:

第一个是,在一个对象层次中(场景树?),根节点代表了整个场景。这个对象层次是在执行光线跟踪之前在host端创建的。

第二个是,一束光线,也就是上面计算出来的向量,模拟了针孔相机的视口锥截体(viewing frustum该区域的实际形状依所模拟的摄像机镜头而定,但顾名思义,其常见的形状是方平截头体。将四棱锥截为平截头体的两个平面称作近平面 和远平面。如果某个物体到摄像机的距离比近平面近或比远平面远,那么这个物体不会被显示。)。

第三个是,

 

 

 

 

 

假如光线与一个物体相交,closest hit 程序就会将result成员设置成法线颜色(或者翻译成正常颜色?不太理解),如果光线不和任何物体相交,miss函数就会将result设置为背景色。一旦光线跟踪执行完毕,控制权就会交还给相机程序,这样我们将得到的颜色数据存储到输出缓冲区。

 

最后需要指出,由于optix在遍历和着色(或者阴影计算)是支持递归的,一个本地的栈,是用来维持状态的。如果一个栈不够大,那么他就会溢出。一旦出现这样的情况,所有当前光线产生进程都会终止,一个exception program 也就是异常处理程序就会执行。在本例中,我们只是将输出缓冲区设置为一个特殊的颜色(当然也是在host端设置的)来提示用户,异常发生了。

 

 

rtDeclareVariable(float3, bad_color, , );

RT_PROGRAM void exception()

{

output_buffer[launch_index] = make_color( bad_color );

}

 

将所有的程序正确就位,我们就可运行教程的程序了,并产生上面图示的效果。每一个程序都会被optix每秒执行很多次来产生实时的画面。现在吗我们将会在此基础上绘制更加真实和复杂的图像。

一点二

接下来的步骤我们要在场景中的物体上添加简单的明暗效果。为实现这个目标我们要重写closest hit程序,实现每一个交点的关照计算。

 

RT_PROGRAM void closest_hit_radiance1()

{

float3 world_geo_normal = normalize(rtTransformNormal(

RT_OBJECT_TO_WORLD,

geometric_normal));

float3 world_shade_normal = normalize(rtTransformNormal(

RT_OBJECT_TO_WORLD,

shading_normal));

float3 ffnormal = faceforward(world_shade_normal,

-ray.direction,

world_geo_normal);

float3 color = Ka * ambient_light_color;

float3 hit_point = ray.origin + t_hit * ray.direction;

for(int i = 0; i < lights.size(); ++i) {

BasicLight light = lights[i];

float3 L = normalize(light.pos - hit_point);

float nDl = dot( ffnormal, L);

if( nDl > 0 )

color += Kd * nDl * light.color;

}

prd_radiance.result = color;

}

 

这个程序包含三个基本的步骤:

第一步,这个程式会精确地计算世界空间的法线。为实现这个计算,需要获取阴影法线和几何体法线,并将他们转换到世界空间,然后使用faceforward函数确保计算出的法线是以光源为导向的(这边不知道怎么翻合适)。大多数的渲染系统,是区分阴影法线和几何体法线的,例如,定点法向量插值计算或者说表面凹凸映射。尽管本教程并不包含这样的特效,但是这个着色程序使得这个程序本身可以直接被更加复杂的场景再次使用。

第二步,本程序会为物体表面计算一个环境光。环境光是将场景中所有投射到这个物体的光照,进行计算获得所有这些光线的近似平均值。本程序中,我们利用两个变量来从host端获取这些参数。第一个参数ka,反映了几何体的一个属性,这个属性要么是与一个材质对象绑定的要么是与一个几何对象绑定的,而绑定的工作是由本教程的host代码完成的。另一个ambient_light_color象参数是一个绑定到optix的context上的全局属性。需要指出的是,optix的层次结构机制很给力,尤其是在变量的指定上;通过在host端的场景树中将他们附加到不同的点上,他们就可以影响到子集中的被渲染的对象(自己也没有读懂具体的意思,求教)。关于变量的继承,本教程中不会详细讲解,您可以通过阅读OptiX Programming Guide来获取更多细节。

第三步,我们将会循环遍历场景中所有的光源并计算光的贡献值。在这个例子中,每一个光源都被描述在一个用户定义的结构体中,这个结构体叫做BasicLight, 而且这一些光线被存储在一个一维的输入缓冲区中,这个缓冲就是lights。Host代码会在执行光线跟踪之前分配和填充这个lights缓冲区。下面是device端对应的结构体:

 

struct BasicLight

{

float3 pos;

float3 color;

int casts_shadow;

int padding; // make the structure more efficient

};

rtBuffer<BasicLight> lights;

 

在照明回路中,我们使用一个简单的基于物体表面的法向量与入射光线夹角的cos值的Lambertian shading model。物体表面颜色是被另一个在host端被初始化的变量kd指定的。接下来的例子将会利用程序计算颜色,来实现更加复杂的视觉效果。

 

 

 

一点三

对于博朗光照模型的简单修改,就是加入phong高光。明快的高光可以在真实世界中的一些塑料或者是金属物体上看到。我们使用Jim Blinn的方法来计算halfway vector(中间向量?),这个向量位于L和入射方向之间(不知道是个什么概念,L是什么?)。中间向量H 和法向量夹角的cos值会增加一个用户定义变量phong_exp的权值。这个值决定了高光部分的锐度。这个例子中我们使用了内置函数pow(x,y)这个函数计算x的y次方。这个函数对GPU上的特殊硬件有影响,它会使得计算更加高效。

下面的代码展示了对于之前的例子中的漫反射着色器必须进行的小规模修改。

...

if( nDl > 0 ){

float3 Lc = light.color;

color += Kd * nDl * Lc;

float3 H = normalize(L - ray.direction);

float nDh = dot( ffnormal, H );

if(nDh > 0)

color += Ks * Lc * pow(nDh, phong_exp);

}

...

 

 

 未完待续。。。。

posted @ 2015-11-07 09:59  轻遣流年  阅读(1242)  评论(0)    收藏  举报