Q108:浅析PBRT-V3的代码结构

198 篇文章 12 订阅
195 篇文章 27 订阅


前续知识:

Q106:Linux系统下安装编译PBRT-V3
Q107:Linux系统下GDB对PBRT-V3进行debug


108.1 理论介绍

咱这篇文章要讲的内容不是如下这些基类,当然这些绝对时系统的核心结构。

这篇文章的主要内容是:从.pbrt场景描述文件到render()循环前的这个过程。


PBRT中的场景描述文件相当于《Ray Tracing from the Ground Up》中的world::build()


接下来,咱以Q106:Linux系统下安装编译PBRT-V3中用到的sharp.pbrt为例来进行说明。


场景描述文件,即配置文件。描述场景所包含的:shapes、material等等信息。

比如:场景中有两个球、球的材质时matte。


sharp.pbrt的功能相当于《Ray Tracing from the Ground Up》中的World::build(),即构建场景。

《Ray Tracing from the Ground Up》中的World::build()直接用C++写的,所以系统“认识”。

但是,sharp.pbrt是如下这个鬼样子,系统怎么认识呢?

#sharp.pbrt -- a simple pbrt input file that displays a cone, sphere
#              and refletive plane
#Richard P. Sharp - CIS782 Fall 2004

#first we set up the eye
LookAt 1 1 10   0 0 -1  0 1 0 #ex ey ez lx ly lz ux uy uz

#the camera
Camera "perspective" "float fov" [30]

#this is the filter used for antialiasing
PixelFilter "mitchell" "float xwidth" [2] "float ywidth" [2]

#name the file
Film "image" "string filename" ["sharp.exr"]
     "integer xresolution" [400] "integer yresolution" [400]

#begin describing scene
WorldBegin

#light source
AttributeBegin
  CoordSysTransform "camera"
  LightSource "distant" 
              "point from" [0 0 0] "point to"   [0 0 1]
              "color L"    [3 3 3]
AttributeEnd

#transform the world
AttributeBegin
  Translate 0 -1 0
  Rotate 35 0 1 0

  #define an orangish sphere
  AttributeBegin
    Translate -1 .75 -1.5
    Rotate -90 1 0 0
  
    Material "matte" "color Kd" [0.1 0.9 0.1]

    Shape "sphere" "float radius" [.75] 
  AttributeEnd


  #define a blue cone
  AttributeBegin
    Translate 0 0 2.5
    Rotate -90 1 0 0

    #this describes the material properties
    Material "matte" "color Kd" [0.9 0.1 0.1]
    
    #this is the shape
    Shape "cone" "float radius" [.75] "float height" [2]
  AttributeEnd


  #define a reflective ground plane
  AttributeBegin
    Scale 20 20 20

    Material "uber" "color Kd" [0.1 0.1 0.9] "color Kr" [0.9 0.9 0.9] "color Ks" [0.1 0.1 0.1] "float roughness" [0.9] "float index" [1.34]

    #this is a triangle mesh, the first set of points define four xyz 
    #coordinates, the second set defines the mesh by indexing into
    #those points
    Shape "trianglemesh" "point P" [ -1 0 -1  1 0 -1  1 0 1  -1 0 1 ]
   	  "integer indices" [ 0 1 2 2 3 0 ]
  AttributeEnd

AttributeEnd
WorldEnd

这个文件的具体内容,咱先不关心。咱现在要知道的是:每一行的第一个“单词”/“变量”可以理解为关键字(#开头的是注释)

比如:Shape、Material、WorldEnd等等。


为了“认识”sharp.pbrt文件中的内容,PBRT-V3借助外部工具flex和bison(后文称“解析工具”)来帮忙解析sharp.pbrt。

为了让解析工具能够解析sharp.pbrt,咱得做一些约定。这个约定就是前面提到的sharp.pbrt中“关键字”。

pbrtparse.y就是告诉解析工具怎么解析sharp.pbrt内容编写的。

pbrtparse.y中会告诉解析工具去解析sharp.pbrt中的每一个关键字。

解析完之后,解析工具还会根据partparse.y生成partparse.cpp。


比如:


为了sharp.pbrt中的如下内容:

   Shape "sphere" "float radius" [.75] 
咱需要在pbrtparse.y中编写:

| SHAPE STRING paramlist
{
    pbrt::ParamSet params;
    pbrt::InitParamSet(params, pbrt::SpectrumType::Reflectance);
    pbrt::pbrtShape($2, params);
    pbrt::FreeArgs();
}
然后,解析工具根据pbrtparse.y中的内容生成pbrtparse.cpp中对应的内容如下:

int
yyparse (void)
{
......

  case 57:
#line 573 "/home/lbzeng/pbrt-v3/src/core/pbrtparse.y" /* yacc.c:1646  */
    {
    pbrt::ParamSet params;
    pbrt::InitParamSet(params, pbrt::SpectrumType::Reflectance);
    pbrt::pbrtShape((yyvsp[-1].string), params);
    pbrt::FreeArgs();
}
}
pbrt::pbrtShape()是在~/pbrt-v3/src/core/api.cpp中实现的。

站在PBRT系统的开发者的角度来看:

因为PBRT系统时给大家用的,所以不能像《Ray Tracing from the Ground Up》那样通过在代码中编写World::build()来描述场景。

终端用户要使用咱们的PBRT系统的话,用什么方式来描述他们自己的场景呢?

从而,就有了.pbrt场景描述文件。

我们给终端用户规定一些关键字,让他们根据这些关键字来描述场景。

终端用户提供.pbrt场景描述文件后,系统怎么解析呢?

当然,咱们可以编写C++代码来进行解析。

但是,上面有成熟的解析工具(flex,bison)能够生成解析源代码(by the way,flex和bison被称为“生成解析器的解析工具”),咱直接使用。

为了使用解析工具,咱只需要告诉解析工具:关键字是什么?遇到关键字时应该干什么?(比如:遇到关键字Shape,调用pbrt::pbrtShape())

这些东西就写在pbrtparse.y文件中。

解析工具根据pbrtparse.y生成pbrtparse.cpp(即解析器)。

然后,系统就可直接调用解析器(pbrtparse.cpp)中的函数(yyparse())读取sharp.pbrt文件中的内容了。


图示说明如下:

Shape、Material等关键字的处理类似,最终通过api.cpp中的函数call到具体对应的shape、material。


解析阶段结束时,得到两样东西:Integrator对象、Scene对象



有个问题:场景初始化结束之后,怎么进入渲染循环呢?

这个是在关键字“WorldEnd”的处理函数pbrt::pbrtWorldEnd()中完成的。

该函数中有这么一条语句“integrator->Render(*scene);”。即在场景初始化结束时,开始渲染。


108.2 Callstack

接下来,咱用pbrt.debug来渲染sharp.pbrt。

(pbrt.debug参考:Q107:Linux系统下GDB对PBRT-V3进行debug


lbzeng@lbzeng-ubuntu:~$ gdb pbrt.debug

//进入debug环境

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from pbrt.debug...done.
(gdb) set args --nthreads=1 ~/pbrt/sharp.pbrt
//设置debug参数

(gdb) b /home/lbzeng/pbrt-v3/src/shapes/sphere.h:55
//设置断点(有多个断点需要设置,此处不一一贴出)

(gdb) r
//运行

Starting program: /usr/bin/pbrt.debug --nthreads=1 ~/pbrt/sharp.pbrt 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
pbrt version 3 (built May 20 2017 at 08:58:48) [Detected 4 cores]
*** DEBUG BUILD ***
Copyright (c)1998-2016 Matt Pharr, Greg Humphreys, and Wenzel Jakob.
The source code to pbrt (but *not* the book contents) is covered by the BSD License.
See the file LICENSE.txt for the conditions of the license.
然后,在“Shape”断点处停住

Breakpoint 5, pbrt::CreateSphereShape (o2w=0xb7b9f040, w2o=0xb7b9f0c0,
    reverseOrientation=false, params=...)
    at /home/lbzeng/pbrt-v3/src/shapes/sphere.cpp:321
321        Float radius = params.FindOneFloat("radius", 1.f);
(gdb) bt
//打印此处Callstack
#0  pbrt::CreateSphereShape (o2w=0xb7b9f040, w2o=0xb7b9f0c0,
    reverseOrientation=false, params=...)
    at /home/lbzeng/pbrt-v3/src/shapes/sphere.cpp:321
#1  0x082c1b7e in pbrt::MakeShapes (name="sphere", object2world=0xb7b9f040,
    world2object=0xb7b9f0c0, reverseOrientation=false, paramSet=...)
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:304
#2  0x082c8ae4 in pbrt::pbrtShape (name="sphere", params=...)
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:1171
#3  0x084127cc in yyparse () at /home/lbzeng/pbrt-v3/src/core/pbrtparse.y:576
#4  0x083283f9 in pbrt::ParseFile (filename="/home/lbzeng/pbrt/sharp.pbrt")
    at /home/lbzeng/pbrt-v3/src/core/parser.cpp:63
#5  0x082c0592 in main (argc=3, argv=0xbffff104)
    at /home/lbzeng/pbrt-v3/src/main/pbrt.cpp:157
(gdb) c
//继续运行
Continuing.
然后,在“材料”断点处停住

Breakpoint 4, pbrt::CreateMatteMaterial (mp=...)
    at /home/lbzeng/pbrt-v3/src/materials/matte.cpp:66
66            mp.GetSpectrumTexture("Kd", Spectrum(0.5f));
(gdb) bt

//打印此处Callstack

#0  pbrt::CreateMatteMaterial (mp=...)
    at /home/lbzeng/pbrt-v3/src/materials/matte.cpp:66
#1  0x082c2f31 in pbrt::MakeMaterial (name="matte", mp=...)
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:415
#2  0x082c9782 in pbrt::GraphicsState::CreateMaterial (
    this=0x8a300a0 <pbrt::graphicsState>, params=...)
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:1256
#3  0x082c8b21 in pbrt::pbrtShape (name="sphere", params=...)
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:1173
#4  0x084127cc in yyparse () at /home/lbzeng/pbrt-v3/src/core/pbrtparse.y:576
#5  0x083283f9 in pbrt::ParseFile (filename="/home/lbzeng/pbrt/sharp.pbrt")
    at /home/lbzeng/pbrt-v3/src/core/parser.cpp:63
#6  0x082c0592 in main (argc=3, argv=0xbffff104)
    at /home/lbzeng/pbrt-v3/src/main/pbrt.cpp:157

(gdb) c

//继续运行

Continuing.
然后在“Integrator”断点处停住

Breakpoint 8, pbrt::SamplerIntegrator::Render (this=0x8a4f480, scene=...)
    at /home/lbzeng/pbrt-v3/src/core/integrator.cpp:233
233        Bounds2i sampleBounds = camera->film->GetSampleBounds();
(gdb) bt
//打印此处Callstack
#0  pbrt::SamplerIntegrator::Render (this=0x8a4f480, scene=...)
    at /home/lbzeng/pbrt-v3/src/core/integrator.cpp:233
#1  0x082ca8ad in pbrt::pbrtWorldEnd ()
    at /home/lbzeng/pbrt-v3/src/core/api.cpp:1386
#2  0x08412b98 in yyparse () at /home/lbzeng/pbrt-v3/src/core/pbrtparse.y:643
#3  0x083283f9 in pbrt::ParseFile (filename="/home/lbzeng/pbrt/sharp.pbrt")
    at /home/lbzeng/pbrt-v3/src/core/parser.cpp:63
#4  0x082c0592 in main (argc=3, argv=0xbffff104)
    at /home/lbzeng/pbrt-v3/src/main/pbrt.cpp:157


简单来说,sharp.pbrt中的关键字和api.cpp中的函数相对应


参考:

《Physically Based Rendering_From Theory To Implementation. 3rd. 2016》中“Appendix B: Scene Description Interface”章节。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值