物体、灯光和摄像机的位子都是使用的典型的3D坐标系统。之前,我们讲解过POV-Ray的坐标系统。这里我们在回顾一下,X轴的正方向指向右边,Y轴正方向指向上,Z轴指向屏幕里。
坐标系统的位置经常用三个元素来表示(x,y,z),这是很容易理解的。
向量也不总是来表示指示方向的。他们也涉及一些对物体移动、旋转和大小控制的操作。
大小,位置,方向和变形的坐标操作,与一个叫做transformations的标识符有关。接下里我们就阐述一下transformations和他们的使用。
支持变形的关键字有rotate,scale,translate。他们用来变形,处理大小或者移动物体和纹理。一个转化矩阵可以用来完成更复杂的变化操作。一组变形操作可以融合在一起,存储到一个transformation标识符里。transformations的语法如下所示
TRANSFORMATION:
rotate <Rotate_Amt> | scale <Scale_Amt> |
translate <Translate_Amt> | transform TRANSFORM_IDENTIFIER |
transform { TRANSFORMATION_BLOCK...} |
matrix <Val00, Val01, Val02,
Val10, Val11, Val12,
Val20, Val21, Val22,
Val30, Val31, Val32>
TRANSFORMATION_BLOCK:
TRANSFORM_IDENTIFIER | TRANSFORMATION | inverse
TRANSFORM_DECLARATION:
#declare IDENTIFIER = transform { TRANSFORMATION_BLOCK...} |
#local IDENTIFIER = transform { TRANSFORMATION_BLOCK...}
translate关键经常后面跟着一个向量,这个向量用来确定相对于目前位置,要移动的变化量。
sphere { <10, 10, 10>, 1
pigment { Green }
translate <-5, 2, 1>
}
上面的代码将会把球体,从<10,10,10>移动到<5,12,11>,而不是<-5,2,1>。另外translate后面的如果有的元素为0,那么就是没有变化。
你可以通过使用scale标识符来改变物体或者贴图模式的大小。同样的,关键字后面也是一个向量。
scale可以用来拉伸或者压扁元素。大于1拉伸,小于1压扁。
多个scale可以用使用。
sphere { <0,0,0>, 1
scale <2,1,0.5>
}
上面的代码会拉伸球体编程一个椭球体。X方向是原来的2倍,Y方向不变,Z方向是原来的1/2。
如果向量中三个元素都相同,那么可以用一个常数来代替。另外不能设置为0,系统将发出警告,同时将0变为1,视为没有进行scale操作。
你可以通过使用rotate标识符来改变物体或者纹理的方向。向量的中元素分别表示三个轴的旋转角度。
注意,旋转是按照X,Y,Z的顺序进行的,如果你对一个复杂的选择变量理解不了,不妨,想宣战单个方向。然后一步步来。
rotate <0, 30, 0> // 30 degrees around Y axis then,
rotate <-20, 0, 0> // -20 degrees around X axis then,
rotate <0, 0, 10> // 10 degrees around Z axis.
POV-Ray使用的是左手系旋转系统,当进行旋转时,不妨用一下左手试试。
matrix关键字可以用来指定具体的变换矩阵,从而应用到物体和纹理上。它的语法如下:
MATRIX:
matrix <Val00, Val01, Val02,
Val10, Val11, Val12,
Val20, Val21, Val22,
Val30, Val31, Val32>
Val00到Val32组成了一个4X4的矩阵,一般情况下,矩阵中的第四列会隐式设置成<0,0,0,1>。对于一个给定的点P=
qx = Val00 * px + Val10 * py + Val20 * pz + Val30
qy = Val01 * px + Val11 * py + Val21 * pz + Val31
qz = Val02 * px + Val12 * py + Val22 * pz + Val32
一般的,你是不会使用matrix关键字,因为它比变换命令更不好描述,而且不直观。然而matrix命令可以完成一些更复杂的变换,比如说裁剪操作
object {
MyObject
matrix < 1, 1, 0,
0, 1, 0,
0, 0, 1,
0, 0, 0 >
}
因为旋转操作与轴有关,大小操作与原位置有关,你可能希望在原位置,对物体先进性大小和旋转操作,然后在移动物体。
需要注意的是:在指定物体位置然后在进行旋转操作时,经常会发生错误。因为旋转操作是围绕着旋转轴进行的,这时物体的位置就可能变化太大,从而超出摄像机的视野。
同样的,移动操作之后在进行大小操作,也会把物体移动到想象不到的位置。如果你先移动然后在大小,会导致,移动倍数效果。比如说
translate <5, 6, 7>
scale 4
上面的代码,将会移动到<20,24,28>而不是<5,6,7>
transform { scale <20,24,28> translate y*3 inverse }
一个相反变换,效果就是正常变换的对立面。可以用来取消一些变换,这样就可以不适用一大推的正常变换操作了。
当然,正常变换也可以达到inverse的效果,只需要改变其对立属性即可。比如说:translate y*3的对立可以为:translate -y*3
整合多个变换操作到复杂的场景中是非常有用的。一个变换标识符就可以达到这样的目的。变换标识符被声明成下面形式:
TRANSFORM_DECLARATION:
#declare IDENTIFIER = transform{ TRANSFORMATION... } |
#local IDENTIFIER = transform{ TRANSFORMATION... }
IDENTIFIER是标识符的名字,TRANSFORMATION是任何有效的变换操作,修改。具体例子如下:
#declare MyTrans =
transform {
rotate THISWAY
scale SOMUCH
rotate -THISWAY
scale BIGGER
translate OVERTHERE
rotate WAYAROUND
}
下面是上面定义的标识符的具体使用,括号可以省略。
object {
MyObject // Get a copy of MyObject
transform MyTrans // Apply the transformation
translate -x*5 // Then move it 5 units left
}
object {
MyObject // Get another copy of MyObject
transform { MyTrans } // Apply the same transformation
translate x*5 // Then move this one 5 units right
}
如果在一个极端复杂的CSG物体上使用变换标识符,会比单独应用每一个变换指令快,这是因为,当再次使用标识符时,他已经是被编译过的了。当然是再次使用,速度会快,而不是初次使用。
当一个物体进行变换时,附着在物体上的纹理也会跟着变换。但是会有以下几种情况出现:如果现实变换操作(rotate、matrix、translate)在进行纹理设置,那么纹理是不会发生变换的。如果先进行纹理设置,在进行变换,那么纹理也会跟着变换。如果在纹理设置中进行变换操作,那么只会对纹理产生效果。
sphere { 0, 1
texture { Jade } // texture identifier from TEXTURES.INC
scale 3 // this scale affects both the
// shape and texture
}
sphere { 0, 1
scale 3 // this scale affects the shape only
texture { Jade }
}
sphere { 0, 1
texture {
Jade
scale 3 // this scale affects the texture only
}
}
另外,变换操作还可以单独的应用到pigment和surface normal中,这样应用操作的同时,可能会影响到其他的一些因素。下面是一个例子:
box { <0, 0, 0>, <1, 1, 1>
texture {
pigment {
checker Red, White
scale 0.25 // This affects only the color pattern
}
normal {
bumps 0.3 // This specifies apparent height of bumps
scale 0.2 // Scales diameter and space between bumps
// and also the height. Has no effect on
// color pattern.
}
rotate y*45 // This affects the entire texture but
} // not the object.
}