上一篇:第一颗卫星

终于能够着手安排天网了。前几篇文章写得凌乱,而且也着实无趣。这是因为,它们充其量不过是我的一些学习笔记。

这篇文章仍然无趣,因为有变量,有各种几何体,有宏,有数组,有循环,有 union,没有 difference,有动画……最终我画进去的货色,无非是一个模仿地球自转的奇怪的几何体,只管我给它取了个巨大的名字叫世界。

从头开始

每一份 .pov 文件都应该以

#version 3.7; // 取决于所用的 POV Ray 版本#include "colors.inc"global_settings {  assumed_gamma 1.0}

作为开始,skynet.pov 也不例外。

为了失去的图形点线明显,最好是定义一组全局变量,

#declare PointSize = 0.03;#declare LineThickness = 0.5 * PointSize;#declare ArrowLength = 3 * PointSize;#declare PointColor = texture { pigment { color Gray50 } }#declare LineColor = texture { pigment { color Yellow } }#declare X_Color = texture { pigment { color Red } }#declare Y_Color = texture { pigment { color Green } }#declare Z_Color = texture { pigment { color Blue } }

一是能够防止代码中呈现过多的幻数,二是便于图形的批改。

坐标系

坐标系也叫规范正交基,然而对于天网而言,坐标系只是正交基,因为用于示意各维轴向的向量的长度可能不为 1,毕竟数学不等于事实。

MakeAxis 用于绘制各维轴向:

#macro MakeAxis(Begin, Direction, Texture)  #local Norm = vnormalize(Direction);  #local End = Begin + Direction;  #local ArrowEnd = End + ArrowLength * Norm;  object {    union {      cylinder {        Begin, End        LineThickness        texture { Texture }      }      cone {        End, 2 * LineThickness        ArrowEnd, 0        texture { Texture }      }    }  }#end

当然,MakeAxis 能够绘制给定了终点的任何一个方向,只是 MakeFrame 应用它绘制坐标系的各个轴向:

#macro MakeFrame(A, X_A, Y_A, Z_A)  object {    union {      sphere {        A, 2 * LineThickness        texture { PointColor }      }      MakeAxis(A, X_A, X_Color)      MakeAxis(A, Y_A, Y_Color)      MakeAxis(A, Z_A, Z_Color)    }  }#end

因为 MakeAxisMakeFrame 不仅仅在天网工程中有用,未来我可能会在其余工程中应用它们,因而把它们连同它们所用的全局变量从 skynet.pov 文件中抽取进去,寄存到 frame.inc 文件中,而后只需在 skynet.pov 文件中应用 #include 指令便可将其载入:

#include "frame.inc"

只有 frame.inc 与 skynet.pov 位于同一目录,povray 就总能通过 #include 指令找到 frame.inc。

:事实上,像 frame.inc 这样的文件能够放在任意一个目录内,要让 povray 找到它,只需在执行 povray 的命令时,通过 +L 选项通知它目录的地位。例如,假如 frame.inc 在 /foo/bar 目录,povray 命令可写成
$ povray +A +P +L/foo/bar skynet.pov 

卫星

天网是由卫星形成的。卫星,在本文中应用一些小坐标系代替。在 skynet.pov 中,宏 MakeSatellite 可基于天球上给定的经纬度计算并绘制小坐标系:

#macro UV_to_XYZ(U, V)  vrotate(vrotate(-z, V * x), -U * y)#end#macro MakeSatellite(U, V, S)  #local A = UV_to_XYZ(U, V);  #local Z_A = vnormalize(<0, 0, 0> - A);  #local X_A = vrotate(x, -U * y);  #local Y_A = vrotate(vrotate(y, V * x), -U * y);  #if (V = 0)    union {      MakeFrame(A, S * X_A, S * Y_A, S * Z_A)      MakeAxis(A, -S * X_A, X_Color)      MakeAxis(A, -S * Y_A, Y_Color)    }  #elseif (V < 0)    MakeFrame(A, -S * X_A, -S * Y_A, S * Z_A)  #else    MakeFrame(A, S * X_A, S * Y_A, S * Z_A)  #end#end

UV_to_XYZ 可将天球上任意一点的经纬度转换为三维坐标。

天网

通过了以上的筹备工作,上面能够着手安排天网。先对天网进行一番布局,用数组 UArray 存储一组经度,用数组 VArray 存储一组纬度。

#declare UArray = array[8] {0, 45, 90, 135, 180, -45, -90, -135}#declare VArray = array[5] {-60, -30, 0, 30, 60}

这两个数组的组合,可结构 40 个天球上的点。这些点就是卫星的装置地位。

天网的用意是监督天球内的所有。然而当初要想看到天网,就必须把天网自身也作为世界的一部分。我用一个半透明的蓝色球体代表天网要监督的所有:

#declare World = sphere {    <0, 0, 0>, 1    texture { pigment { color rgbt <0, 0, 1, 0.5> } }}

而后用 World 去合并天网:

#declare World = object {  union {    object { World }    #for (i, 0, 7, 1)      #local U = UArray[i];      #for (j, 0, 4, 1)        #local V = VArray[j];        MakeSatellite(U, V, 0.2)      #end    #end  }}

最初将整个世界出现进去:

object {  World  rotate -360 * clock * y  rotate -15 * z}

这个世界是向右歪斜,并不停地旋转。

天外

要看到天网,光源须要设在天外,我也须要站在天外,向下鸟瞰:

light_source {  <5, 5, -5>  color White  shadowless // 无影灯}camera  {  orthographic  location <3, 3, -3>  look_at <0, 0, 0>}

后果能够看到:

动画

若想看到世界的旋转,不得不建设 skynet.ini 文件,其内容为:

Input_File_Name=skynet.povInitial_Frame=1Final_Frame=60Cyclic_Animation=On

而后应用命令

$ povray +A skynet.ini

产生一系列图片文件 skynet01.png,skynet02.png,……,skynet60.png。应用 ImageMagick 提供的 convert 工具将这个图片序列合成为本文开始的动图:

$ convert -delay 10 -loop 0 skynet*.png skynet.gif

附录

skynet.ini 文件:

Input_File_Name=skynet.povInitial_Frame=1Final_Frame=60Cyclic_Animation=On

skynet.pov 文件:

#version 3.7;#include "colors.inc"#include "frame.inc"global_settings {  assumed_gamma 1.0}#macro UV_to_XYZ(U, V)  vrotate(vrotate(-z, V * x), -U * y)#end#macro MakeSatellite(U, V, S)  #local A = UV_to_XYZ(U, V);  #local Z_A = vnormalize(<0, 0, 0> - A);  #local X_A = vrotate(x, -U * y);  #local Y_A = vrotate(vrotate(y, V * x), -U * y);  #if (V = 0)    union {      MakeFrame(A, S * X_A, S * Y_A, S * Z_A)      MakeAxis(A, -S * X_A, X_Color)      MakeAxis(A, -S * Y_A, Y_Color)    }  #elseif (V < 0)    MakeFrame(A, -S * X_A, -S * Y_A, S * Z_A)  #else    MakeFrame(A, S * X_A, S * Y_A, S * Z_A)  #end#end#declare UArray = array[8] {0, 45, 90, 135, 180, -45, -90, -135}#declare VArray = array[5] {-60, -30, 0, 30, 60}#declare World = sphere {    <0, 0, 0>, 1    texture { pigment { color rgbt <0, 0, 1, 0.5> } }}#declare World = object {  union {    object { World }    #for (i, 0, 7, 1)      #local U = UArray[i];      #for (j, 0, 4, 1)        #local V = VArray[j];        MakeSatellite(U, V, 0.2)      #end    #end  }}object {  World  rotate -360 * clock * y  rotate -15 * z}light_source {  <5, 5, -5>  color White  shadowless // 无影灯}camera  {  orthographic  location <3, 3, -3>  look_at <0, 0, 0>}

frame.inc 文件:

#declare PointSize = 0.03;#declare LineThickness = 0.5 * PointSize;#declare ArrowLength = 3 * PointSize;#declare PointColor = texture { pigment { color Gray50 } }#declare LineColor = texture { pigment { color Yellow } }#declare X_Color = texture { pigment { color Red } }#declare Y_Color = texture { pigment { color Green } }#declare Z_Color = texture { pigment { color Blue } }#macro MakeAxis(Begin, Direction, Texture)  #local Norm = vnormalize(Direction);  #local End = Begin + Direction;  #local ArrowEnd = End + ArrowLength * Norm;  object {    union {      cylinder {        Begin, End        LineThickness        texture { Texture }      }      cone {        End, 2 * LineThickness        ArrowEnd, 0        texture { Texture }      }    }  }#end#macro MakeFrame(A, X_A, Y_A, Z_A)  object {    union {      sphere {        A, 2 * LineThickness        texture { PointColor }      }      MakeAxis(A, X_A, X_Color)      MakeAxis(A, Y_A, Y_Color)      MakeAxis(A, Z_A, Z_Color)    }  }#end

完。