上一篇:第一颗卫星
终于能够着手安排天网了。前几篇文章写得凌乱,而且也着实无趣。这是因为,它们充其量不过是我的一些学习笔记。
这篇文章仍然无趣,因为有变量,有各种几何体,有宏,有数组,有循环,有 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
因为 MakeAxis
和 MakeFrame
不仅仅在天网工程中有用,未来我可能会在其余工程中应用它们,因而把它们连同它们所用的全局变量从 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
完。