POV-RAY基础教程 - 基本SDL(2)

时间:2024-05-19 16:46:24

本片介绍POV-RAY基本元素,同时编写基本的SDL文件并运行,由于POV-RAY是基于POV场景描述文进行图形渲染的,所以,首先需要了解和掌握POV文件的编写。

点击这里回到上一篇 POV-RAY教程系列 - 介绍(1)

第一副图像

了解POV-Ray的坐标系

首先,我们必须告诉POV-Ray我们的相机的位置以及它的方向。为此,我们使用3D坐标。POV-Ray的常用坐标系统是正y轴朝上,正x轴指向右边,正z轴指向屏幕,这种坐标系称为左手坐标系。

添加标准包含文件

可以使用我们个人喜欢的文本编辑器,我们创建一个名为demo.pov文件。某些版本的POV-Ray带有自己的内置文本编辑器,可能更容易使用。然后我们输入以下文字。输入区分大小写,大小写敏感。

#include“colors.inc”//包含文件包含
#include“stones.inc”//预定义的场景元素

第一个include语句读入各种有用颜色的定义。第二个包含语句读入石头纹理的集合。POV-Ray附带许多标准包含文件。其他感兴趣的是:

  #include“textures.inc”//预定义的场景元素
  #include“shapes.inc”
  #include“glass.inc”
  #include“metals.inc”
  #include“woods.inc”

他们读取预定义的纹理,形状,玻璃,金属和木材贴图。可以通过这些文件查看一下可用的形状和纹理。
我们应该只包括我们场景中需要的头文件。POV-Ray附带的一些包含文件非常大,如果我们不需要它们,我们应该考虑更好地节省解析时间和内存。在以下示例中,我们将仅使用colors.incstones.inc 包含文件。
我们可能在一个场景文件中包含众多数量的头文件。包含文件本身可能还包含其他的头文件,但最大嵌套包含层级不能超过十层
头文件搜索顺序,首先在当前目录中搜索include语句中指定的文件名。如果在当前目录中未找到您的.Inc文件,POV-Ray将搜索您指定的任何库路径。库路径是由+L 命令行开关或Library_Path选项设置的。有关库路径的更多信息,请参阅设置POV-Ray选项一章。
因为将包含文件保存在单独的目录中更方便使用,所以POV-Ray的标准安装会将这些文件放在c:\povray3\include目录中(c:\povray3将替换为您安装POV-Ray的实际目录)。

添加相机

camera声明定义相机位置以及它的方向。由x,y和z坐标定义摄像机的位置以及它的指向。我们使用向量描述坐标。通过在一对尖括号之间放置三个数值并用逗号分隔值来指定向量。我们将以下相机声明添加到场景中。

camera {
  location <0, 2, -3>
  look_at  <0, 1,  2>
}

简言之,location <0,2,-3>将摄像机放置在距离光线跟踪系统中心<0,0,0>的上面两个单位,远离屏幕三个单位处。默认情况下,+z进入屏幕,-z远离屏幕。同时look_at <0,1,2>旋转摄像机指向坐标<0,1,2>,这使得它在相机前面5个单元,比相机低1个单位。这look_at点应该是我们场景关注的焦点。

描述物体

现在摄像机已设置好记录场景,让我们在场景中放置一个黄色球体。我们将以下内容添加到场景文件中:

sphere {
  <0, 1, 2>, 2
  texture {
    pigment { color Yellow }
  }
}

第一个向量指定球体的中心。在此示例中,x坐标为零,因此它左右居中。y = 1在原点上一个单位。z坐标为2,即摄像机前面的五个单位。在中心向量之后是逗号,后跟半径,在这种情况下是半径。由于半径是球体宽度的一半,因此球体宽度为四个单位。

向物体添加纹理

在我们定义了球体的位置和大小之后,我们需要描述表面的外观。该texture语句指定了这些参数。纹理块描述对象的颜色,凹凸和完成属性。在此示例中,我们仅指定颜色。这是我们必须做的最低限度。除颜色外的所有其他纹理选项将使用默认值。
我们定义的颜色是我们希望物体在完全照明时看起来的样子。如果我们正在绘制一个球体的图片,我们将使用深色调的颜色来指示阴影侧和明亮的阴影在照明侧。然而,光线追踪为您解决了这个问题。我们只需要选择物体中固有的基本颜色,POV-Ray会根据场景中的光线使其变亮或变暗。因为我们定义了对象实际具有的基本颜色而不是它看起来如何,调用参数pigment
许多类型的颜色图案可用于颜料声明。关键字color指定整个对象是一种纯色而不是某种颜色模式。我们可以使用之前在标准包含文件中定义的颜色标识符之一 colors.inc
如果我们的需求没有可用的标准颜色,我们可以使用color关键字后跟依次定义我们自己的颜色redgreenblue指定要混合的红色,绿色和蓝色值。例如,可以通过以下方式指定漂亮的粉红色:

color red 1.0 green 0.8 blue 0.8

注意:国际而非美国形式的“颜色”也是可以接受的,并且可以在任何可以使用“颜色”的地方使用。
每个关键字后面的值应该在0.0到1.0之间。未指定的三个组件中的任何一个都将默认为0.也可以使用快捷方式表示法。以下产生相同的粉红色:

color rgb <1.0, 0.8, 0.8>

在许多情况下,color关键字是多余的,因此指定粉红色的最短方式是:

rgb <1.0, 0.8, 0.8>

颜色在颜色部分中有更详细的解释。

定义光源

我们的场景还需要一个细节。我们需要一个光源。直到我们创造一个,在这个虚拟世界中没有光明。因此我们添加了这一行

light_source { <2, 4, -3> color White}

小结: 到场景文件获取我们的第一个完整的POV-Ray场景文件,其中包含:
头文件、相机、物体定义(包含贴图)、灯光
如下所示。

#include "colors.inc"
background { color Cyan }
camera {
  location <0, 2, -3>
  look_at  <0, 1,  2>
}
sphere {
  <0, 1, 2>, 2
  texture {
    pigment { color Yellow }
  }
}
light_source { <2, 4, -3> color White}

light_source声明中的矢量将光的位置指定为右侧的两个单位,原点上方的四个单位和距离原点的三个单位。光源是一个发光的不可见的微小点。它没有物理形状,因此不需要纹理。
运行上述代码,如果您指定了预览显示,它将显示在屏幕上。如果您指定了输出文件(默认为文件输出),则POV-Ray也会创建一个文件。
注意:如果您没有高色彩或真彩色显示硬件,则预览图像可能看起来很差,但无论显示类型如何,都会将完整的细节写入图像文件。
POV-RAY基础教程 - 基本SDL(2)

以上是只是一个基本的场景绘制过程,但我们必须从基础知识开始,然后我们才能获得更多有趣的功能和场景。

基本形状

到目前为止,我们刚刚使用了球体形状。POV-Ray可以渲染许多其他类型的形状。以下部分将介绍如何使用一些更简单的对象作为上面使用的球体的替代。

长方体

box是最常用的对象之一。我们尝试这个例子代替球体:

box {
  <-1, 0,   -1>,  // 左下角
  < 1, 0.5,  3>   // 右上角
  texture {
    T_Stone25     // Pre-defined from stones.inc
    scale 4       // Scale by the same amount in all
                 // directions
  }
  rotate y*20     // Equivalent to "rotate <0,20,0>"
}

在该示例中,我们可以看到通过指定其对角的3D坐标来定义框。第一矢量通常是最小的x,y和z坐标,第二矢量应该是最大的x,y和z值,但是可以使用任何两个相对的角。Box对象只能与世界坐标系的轴平行定义。我们以后可以将它们旋转到任何角度。

注意:我们可以对值和向量执行简单的数学运算。在rotate参数中,我们将向量标识符y乘以20.这与<0,1,0> * 20或<0,20,0>作用相同。

锥体

这是另一个示例,说明如何使用cone

cone {
  <0, 1, 0>, 0.3    // Center and radius of one end
  <1, 2, 3>, 1.0    // Center and radius of other end
  texture { T_Stone25 scale 4 }
}

锥形由每个末端的中心和半径限定。在这个例子中,一端位于<0,1,0>位置,半径为0.3,而另一端以<1,2,3>为中心,半径为1.如果我们想要锥体到达尖点我们必须使用radius = 0。实心端盖彼此平行并垂直于锥轴。如果我们想要一个没有端盖的开锥,我们必须在第二个半径之后添加open关键字,如下所示:

cone {
  <0, 1, 0>, 0.3    // Center and radius of one end
  <1, 2, 3>, 1.0    // Center and radius of other end
  open
  texture { T_Stone25 scale 4 }
}
圆柱体

我们也可以这样定义cylinder

 cylinder {
    <0, 1, 0>,     // Center of one end
    <1, 2, 3>,     // Center of other end
    0.5            // Radius
    open           // Remove end caps
    texture { T_Stone25 scale 4 }
  }
平面

让我们试试一个计算机图形标准The Checkered Floor。我们将以下对象添加到demo.pov文件的第一个版本, 包括球体。

plane { 
  <0, 1, 0>, -1
  pigment {
    checker color Red, color Blue
  }
}

这里定义的对象是无限平面。矢量<0,1,0>是平面的表面法线(即如果我们站在表面上,则法线点直线向上)。之后的数字是平面从原点沿法线移动的距离 - 在这种情况下,地板放置在y = -1处,以便y = 1,半径= 2的球体停留在它上面。
注意:即使没有texture声明,这里也有隐含的纹理。我们可能会发现,连续输入嵌套的语句texture {pigment可能会变得令人厌烦,所以POV-Ray让我们 texture在很多情况下都会忽略声明。一般来说,我们只需要围绕纹理标识符的纹理块(如 T_Stone25上面的示例),或者创建分层纹理(稍后介绍)。
此颜料使用检查颜色图案并指定应使用红色和蓝色两种颜色。因为矢量<1,0,0>,<0,1,0>和<0,0,1>经常使用,POV射线具有三个内置向量标识符 x, y以及z分别可以用作速记。因此,可以定义为:

plane { y, -1
  pigment { ... }
}

注意:我们不使用矢量标识符周围的尖括号。
至此完整代码如下:

#include "colors.inc" 
background { color Cyan }  
camera {
  location <0, 2, -3>
  look_at  <0, 1,  2>
}  
sphere {
  <0, 1, 2>, 2
  texture {
    pigment { color Yellow }
  }
}  
plane { 
  <0, 1, 0>, -1
  pigment {
    checker color Red, color Blue
  }
}     
light_source { <2, 4, -3> color White}

运行的图如下:
POV-RAY基础教程 - 基本SDL(2)

看着地板,我们注意到球在地板上投下了阴影。光线跟踪器可以非常精确地计算阴影,从而产生精确,锐利的阴影。在现实世界中,经常会看到半影或柔和的阴影。稍后我们将学习如何使用扩展光源来柔化阴影。

Torus对象

一个torus可以被认为是甜甜圈或内胎。它是一种在多种CSG中非常有用的形状,因此POV-Ray采用这种四阶四次多项式作为原始形状。圆环的语法非常简单,一旦我们了解了两个浮点值的含义,就可以很容易地使用它。而不是关于这个主题的讲座,让我们创建一个并用它做一些实验。我们创建一个名为的文件tordemo.pov,并按如下方式编辑它:

#include "colors.inc"
camera {
  location <0, .1, -25>
  look_at 0
  angle 30
}
background { color Gray50 } // to make the torus easy to see
light_source { <300, 300, -1000> White }
torus {
  4, 1              // major and minor radius
  rotate -90*x      // so we can see it from the top
  pigment { Green }
}

我们追踪现场。好吧,这是一个甜甜圈好吧。让我们尝试更改主要和次要半径值,看看会发生什么。我们将它们更改如下:

torus {5,.25 //主要和次要半径

这看起来更像是呼啦圈!我们试试这个:

torus {3.5,2.5 //主要和次要半径

哇!一个有严重体重问题的甜甜圈!有了这么简单的语法,除了改变它的纹理之外,除了改变它的纹理之外我们还能做些什么呢?或者在那里?让我们来看看…Tori是CSG中非常有用的对象。我们来试试吧。我们改变了圆环和盒子:

difference {
  torus {
    4, 1
    rotate x*-90  // so we can see it from the top
  }
  box { <-5, -5, -1>, <5, 0, 1> }
  pigment { Green }
}

有意思…半个圆环。现在我们添加另一个翻转另一个方式。只是,让我们宣布原始的半圆环和必要的变换,以便我们可以再次使用它们:

#declare Half_Torus = difference {
   torus {
     4, 1
     rotate -90*x  // so we can see it from the top
   }
   box { <-5, -5, -1>, <5, 0, 1> }
   pigment { Green }
}
#declare Flip_It_Over = 180*x;
#declare Torus_Translate = 8;  // twice the major radius

现在我们创建一个包含两个Half_Torus对象的联合:

union {
  object { Half_Torus }
  object { Half_Torus
    rotate Flip_It_Over
    translate Torus_Translate*x
  }
}

现在代码如下:

#include "colors.inc"
camera {
  location <0, .1, -25>
  look_at 0
  angle 30
}
background { color Gray50 } // to make the torus easy to see
light_source { <300, 300, -1000> White }
  
#declare Half_Torus = difference {
   torus {
     4, 1
     rotate -90*x  // so we can see it from the top
   }
   box { <-5, -5, -1>, <5, 0, 1> }
   pigment { Green }
}
#declare Flip_It_Over = 180*x;
#declare Torus_Translate = 8;  // twice the major radius 

union {
  object { Half_Torus }
  object { Half_Torus
    rotate Flip_It_Over
    translate Torus_Translate*x
  }
}

显示图形是:
POV-RAY基础教程 - 基本SDL(2)

这是一个S形物体,但我们无法从现有的相机中看到整个物体。让我们添加一些链接,每个方向三个,沿+ z方向移动对象并围绕+ y轴旋转它,以便我们可以看到更多。我们还注意到,Tori会见的地方似乎有一个小的差距。这是因为我们正在直接在xz平面上查看此场景。我们将相机的y坐标从0更改为0.1以消除此问题。

union {
    object { Half_Torus }
    object { Half_Torus
      rotate Flip_It_Over
      translate x*Torus_Translate
    }
    object { Half_Torus
      translate x*Torus_Translate*2
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate x*Torus_Translate*3
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate -x*Torus_Translate
    }
    object { Half_Torus
      translate -x*Torus_Translate*2
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate -x*Torus_Translate*3
    }
    object { Half_Torus
      translate -x*Torus_Translate*4
    }
    rotate y*45
    translate z*20
}

POV-RAY基础教程 - 基本SDL(2)

渲染这个,我们看到一个凉爽,起伏,蛇状的东西或其他。但我们想要建模一些有用的东西,这些东西我们可能会在现实生活中看到。链条怎么样?
考虑一下,我们意识到链条的单个链接可以使用两个半圆柱和两个圆柱轻松建模。
我们创建一个新文件。我们可以使用相同的相机,背景,光源和声明的对象和转换,如我们所使用的 tordemo.pov:

 #include "colors.inc"
 camera {
   location <0, .1, -25>
   look_at 0
   angle 30
 }
 background { color Gray50 }
 light_source{ <300, 300, -1000> White }
 #declare Half_Torus = difference {
   torus {
     4,1
     sturm
     rotate x*-90  // so we can see it from the top
   }
   box { <-5, -5, -1>, <5, 0, 1> }
   pigment { Green }
 }
 #declare Flip_It_Over = x*180;
 #declare Torus_Translate = 8;

现在,我们制作了两个半圆环的完整圆环:

  union {
    object { Half_Torus }
    object { Half_Torus rotate Flip_It_Over }
  }

图片如下:
POV-RAY基础教程 - 基本SDL(2)

这似乎是制作一个完整圆环的浪费方式,但我们真的要将每一半移动以为圆柱体腾出空间。首先,我们在联合之前添加声明的柱面:

#declare Chain_Segment = cylinder {
<0, 4, 0>, <0, -4, 0>, 1
pigment { Green }
}

然后我们将两个Chain_Segments加到联合并转换它们,使它们与每一侧的圆环的小半径对齐:

union {
    object { Half_Torus }
    object { Half_Torus rotate Flip_It_Over }
    object { Chain_Segment translate  x*Torus_Translate/2 }
    object { Chain_Segment translate -x*Torus_Translate/2 }
  }

图片如下:
POV-RAY基础教程 - 基本SDL(2)

现在我们将两个圆周+ y和-y平移,以便修剪的末端与圆柱的末端相交。该距离等于先前声明的一半Torus_Translate

union {
    object {
      Half_Torus
      translate y*Torus_Translate/2
    }
    object {
      Half_Torus
      rotate Flip_It_Over
      translate -y*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate x*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate -x*Torus_Translate/2
    }
  }

我们渲染这个,瞧!链的单个链接。但我们还没有完成!谁听说过绿链?我们宁愿使用漂亮的金属色。首先,我们去除所声明的圆环和圆柱体中的任何颜料块。然后我们在创建链接的联合之前添加一个黄金纹理的声明。最后,我们将纹理添加到union中并将其声明为单个链接:

  #declare Half_Torus = difference {
    torus {
      4,1
      sturm
      rotate x*-90  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
  }
    
  #declare Chain_Segment = cylinder {
    <0, 4, 0>, <0, -4, 0>, 1
  }

  #declare Chain_Gold = texture {
    pigment { BrightGold }
    finish {
      ambient .1
      diffuse .4
      reflection .25
      specular 1
      metallic
    }
  }

  #declare Link = union {
    object {
      Half_Torus
      translate y*Torus_Translate/2
    }
    object {
      Half_Torus
      rotate Flip_It_Over
      translate -y*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate x*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate -x*Torus_Translate/2
    }    
    texture { Chain_Gold }
  }  

现在我们建立两个链接的联合。第二个必须翻译+ y,使其内壁恰好与另一个链接的内壁相遇,就像链条的链接一样。该距离变为先前声明的Torus_Translate减2(小半径的两倍)的两倍。这可以通过以下表达式来描述:
Torus_Translate * 2-2 * Y
我们将此表达式声明如下:
#declare Link_Translate = Torus_Translate * 2-2 * y;
在对象块中,我们将使用此声明的值,以便我们可以将其相乘以创建其他链接。现在,我们旋转第二个链接 90*y,使其垂直于第一个链接,就像链的链接一样。最后,我们将联合缩放1/4,以便我们可以看到整个事物:

  union {
    object { Link }
    object { Link translate y*Link_Translate rotate y*90 }
    scale .25
  }

我们渲染这个,我们将看到一对非常现实的链接。如果我们想要创建一个完整的链,我们必须声明上面的联合,然后创建这个声明的对象的另一个联合。我们必须确保从声明的对象中删除缩放:

#declare Link_Pair =
  union {
    object { Link }
    object { Link translate y*Link_Translate rotate y*90 }
  }

至此代码为:

  #include "colors.inc"
  camera {
    location <0, .1, -25>
    look_at 0
    angle 30
  }
  background { color Gray50 }
  light_source{ <300, 300, -1000> White }  
  
  #declare Flip_It_Over = x*180;
  #declare Torus_Translate = 8;    
   #declare Half_Torus = difference {
    torus {
      4,1
      sturm
      rotate x*-90  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
  }
    
  #declare Chain_Segment = cylinder {
    <0, 4, 0>, <0, -4, 0>, 1
  }

  #declare Chain_Gold = texture {
    pigment { BrightGold }
    finish {
      ambient .1
      diffuse .4
      reflection .25
      specular 1
      metallic
    }
  }

  #declare Link = union {
    object {
      Half_Torus
      translate y*Torus_Translate/2
    }
    object {
      Half_Torus
      rotate Flip_It_Over
      translate -y*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate x*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate -x*Torus_Translate/2
    }    
    texture { Chain_Gold }
  }   
  
  #declare Link_Translate = Torus_Translate * 2-2 * y;
  union {
    object { Link }
    object { Link translate y*Link_Translate rotate y*45 }
    scale .20
  }

图片为:
POV-RAY基础教程 - 基本SDL(2)
现在我们宣布我们的链:

#declare Chain = union {
  object { Link_Pair}
  object { Link_Pair translate  y*Link_Translate*2 }
  object { Link_Pair translate  y*Link_Translate*4 }
  object { Link_Pair translate  y*Link_Translate*6 }
  object { Link_Pair translate -y*Link_Translate*2 }
  object { Link_Pair translate -y*Link_Translate*4 }
  object { Link_Pair translate -y*Link_Translate*6 }
}

最后,我们通过几个转换创建我们的链,以便更容易看到。这些包括将其缩小1/10,然后旋转它以便我们可以清楚地看到每个链接:

object {Chain scale .1 rotate &lt;0,45,-45&gt;}

我们渲染这个,我们应该看到一个非常逼真的金链在屏幕上对角拉伸。
POV-RAY基础教程 - 基本SDL(2)
圆环对象可用于创建链。

继续读下一篇 POV-RAY基础教程 - CSG(3)