乐趣区

关于povray:天网

上一篇:第一颗卫星

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

这篇文章仍然无趣,因为有变量,有各种几何体,有宏,有数组,有循环,有 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.pov
Initial_Frame=1
Final_Frame=60
Cyclic_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.pov
Initial_Frame=1
Final_Frame=60
Cyclic_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

完。

退出移动版