python ray定时_当 Python 邂逅 POV-Ray
引言
POV-Ray 是一種專業(yè)的三維場(chǎng)景描述語(yǔ)言,它描述的三維場(chǎng)景可交由 POV-Ray 的解析器(或編譯器)采用光線跟蹤技術(shù)進(jìn)行渲染,渲染結(jié)果為位圖。
POV-Ray 語(yǔ)言是圖靈完備的,亦即其他編程語(yǔ)言能寫出來(lái)的程序,使用 POV-Ray 語(yǔ)言總能等價(jià)地寫出來(lái)。不過(guò),這個(gè)世界上不會(huì)有人打算使用 POV-Ray 語(yǔ)言來(lái)編寫網(wǎng)絡(luò)服務(wù)程序、GUI 程序以及那些運(yùn)行在手機(jī)上的 APP,更何況也寫不出來(lái)。兩個(gè)程序等價(jià),是數(shù)學(xué)意義上的,而不是物理意義上的。許多時(shí)候,我們是在編寫一些非圖形渲染類的程序時(shí),需要繪制一些三維圖形,這時(shí)就可以考慮如何用自己最熟悉的編程語(yǔ)言去驅(qū)動(dòng) POV-Ray 這支畫筆,即為 POV-Ray 編寫代碼生成器。
本文介紹了使用 Python 3 為 POV-Ray 編寫代碼生成器的基本思路。所實(shí)現(xiàn)的代碼生成器重視 POV-Ray 的建模功能,而忽視其光線追蹤渲染功能。凡涉及渲染之處,僅僅使用 POV-Ray 的一些非常簡(jiǎn)單的渲染語(yǔ)句,這種處理頗類似于繪畫藝術(shù)中的白描。因?yàn)槲抑杂袆?dòng)力寫這份文檔,是因?yàn)槲乙褂?POV-Ray 來(lái)繪制我的一些論文與演示文檔里的插圖。這些插圖以表意為主,基本不需要考慮如何讓觀閱它們的人信以為真。之所以選擇 Python 語(yǔ)言來(lái)驅(qū)動(dòng) POV-Ray,是因?yàn)樗阌谖以趯懳臋n的過(guò)程中可以忽略許多數(shù)據(jù)結(jié)構(gòu)與內(nèi)存管理上的細(xì)節(jié)。實(shí)際上,在寫這份文檔之前,我一直在用 C 語(yǔ)言生成 POV-Ray 代碼。
我不會(huì)對(duì) POV-Ray 與 Python 語(yǔ)言本身作太多介紹,因?yàn)槲覍?duì)它們也僅僅是略知一二。我在附錄中給出了我曾經(jīng)粗略翻過(guò)的 POV-Ray 與 Python 的一些文檔的鏈接。
模型、視圖與控制器
在計(jì)算機(jī)中繪制圖形,無(wú)論是二維還是三維,無(wú)論是古代還是現(xiàn)代,一直存在著一個(gè)基本范式,即:模型-視圖-控制器。在使用 Python 驅(qū)動(dòng) POV-Ray 的過(guò)程中,這個(gè)范式依然有效。
直接使用 POV-Ray 語(yǔ)言,可以像下面這樣描述這個(gè)范式:
@ model.inc # [POV-Ray]
... 定義一些模型 ...
@
@ view.inc # [POV-Ray]
... 設(shè)置光源與相機(jī) ...
#include "model.inc" // 加載模型
... 繪制模型 ...
@
@ controller.ini # [POV-Ray]
... 設(shè)置動(dòng)畫參數(shù) ...
@
注:上述諸如 @ model.inc # [POV-Ray] 之類的語(yǔ)句,可理解為注釋。位于符號(hào) @ 與 # 之間的文本是文件名,位于 # 符號(hào)之后的 [...] 中的文本表示其后面的代碼段所用的語(yǔ)言。每個(gè)代碼段的尾部都有一個(gè) @ 符號(hào),表示代碼段至此終止。這種注解形式來(lái)自我寫的一個(gè)文式編程工具所支持的標(biāo)記,詳見(jiàn) https://github.com/liyanrui/orez。
POV-Ray 語(yǔ)言并沒(méi)有刻意強(qiáng)調(diào)模型-視圖-控制器范式,但其語(yǔ)法能夠很自然地描述這種范式。模型注重的是幾何形體,視圖注重的是如何觀察幾何形體,而控制器用于控制視角的變化。POV-Ray 雖然只能給出位圖形式的渲染結(jié)果,但由于它提供了定時(shí)器功能,利用這一功能可生成一組視角有序變化的渲染結(jié)果,然后將它們組合為 GIF 格式的動(dòng)圖,我將這種方式稱為 POV-Ray 視圖的控制器。
其實(shí),這種范式無(wú)處不在。與其說(shuō)是哪個(gè)人發(fā)明了它,不如說(shuō)這是人類處理復(fù)雜任務(wù)時(shí)的本能反應(yīng)。簡(jiǎn)單舉個(gè)餐飲業(yè)的例子,農(nóng)民為餐飲業(yè)提供了模型,廚師為餐飲業(yè)創(chuàng)造了視圖,食客為餐飲業(yè)創(chuàng)造了控制器。用經(jīng)濟(jì)學(xué)的術(shù)語(yǔ)來(lái)說(shuō),就是「生產(chǎn)的社會(huì)化」,強(qiáng)調(diào)的是有規(guī)模的分工與合作。
模型
下面從最簡(jiǎn)單的任務(wù)開(kāi)始,以點(diǎn)與點(diǎn)集的繪制為例,講述如何用 Python 實(shí)現(xiàn) POV-Ray 模型。
POV-Ray 語(yǔ)言沒(méi)有提供點(diǎn)對(duì)象的繪制語(yǔ)法,但是可以使用直徑很小的球體來(lái)表示點(diǎn)對(duì)象:
sphere {
, r
}
為球心,r 為半徑。
基于這一發(fā)現(xiàn),就可以構(gòu)造點(diǎn)集模型:
#declare points = union {
sphere {, r}
sphere {, r}
... ... ...
}
#declare 是 POV-Ray 提供的用于定義局部變量的指令。points 是變量的名字。union 是 POV-Ray 的三維實(shí)體模型的布爾運(yùn)算符,它可將一組三維實(shí)體合并為一個(gè)對(duì)象。上述代碼中,所有小球的半徑相同。
現(xiàn)在開(kāi)始考慮,如何使用 Python 語(yǔ)言自動(dòng)生成上述的點(diǎn)集模型的 POV-Ray 描述。假設(shè)有一份名為 points.asc 的文本文件,其中的每一行文本存儲(chǔ)一個(gè)三維點(diǎn)的坐標(biāo)值,例如:
2.3 4.5 1.1
3.0 8.7 11.3
... ... ...
若使用 Python 語(yǔ)言寫一個(gè)程序,讓它來(lái)解析 points.asc 文件,然后再基于解析到的點(diǎn)集數(shù)據(jù)生成 POV-Ray 模型文件,這樣就可以避免手動(dòng)去寫一大堆 sphere 語(yǔ)句。更重要的是,多數(shù)情況下,像 points.asc 這樣的文件是現(xiàn)有的,例如一些程序輸出的數(shù)據(jù)與三維掃描設(shè)備從實(shí)物表面上采集到的數(shù)據(jù)等等。
下面是一份從 points.asc 這樣的文件解析三維點(diǎn)集數(shù)據(jù)的 Python 代碼:
@ points-to-pov.py # [Python]
def points_parser(src_file_name, right_handed = True, dim = 3):
points = []
with open(src_file_name, 'r') as src:
for line in src:
coords = line.split()
if len(coords) != dim:
continue
x = []
for t in coords:
x.append(float(t))
if right_handed:
x[dim - 1] = -x[dim - 1] # 將 x 的坐標(biāo)從右手坐標(biāo)系變換到左手坐標(biāo)系
points.append(x)
src.close()
return points
@
注:POV-Ray 的坐標(biāo)系是左手系。若待解析的三維點(diǎn)集數(shù)據(jù)位于右手系,那么在解析過(guò)程中需要對(duì)每個(gè)點(diǎn)的最后一個(gè)維度的坐標(biāo)取相反數(shù)。
像這樣的功能,用 C/C++ 之類的語(yǔ)言來(lái)寫,會(huì)比較繁瑣;用 POV-Ray 語(yǔ)言也能寫得出來(lái),依然會(huì)比較繁瑣。
繼續(xù)用 Python 語(yǔ)言將解析所得點(diǎn)集轉(zhuǎn)化為 POV-Ray 模型,并以文件的形式保存:
@ points-to-pov.py # +
def output_points_model(points, model_name, dim = 3):
model = open(model_name + '.inc', 'w')
model.write('#declare ' + model_name + ' = union {\n')
for x in points:
model.write(' sphere {
for i in range(0, dim):
if i < dim - 1:
model.write('%f, ' % (x[i]))
else:
model.write('%f' % (x[i]))
model.write('>, point_size_of_' + model_name + '}\n')
model.write('} // ' + model_name + ' end\n')
model.close()
@
注:上述代碼片段首部的 @ points-to-pov.py # + 的 + 符號(hào)表示在已存在的 points-to-pov.py 代碼片段之后追加一段代碼。
現(xiàn)在,只需將 points_parser 與 output_points_model 組合起來(lái)便可將一份點(diǎn)集數(shù)據(jù)文件轉(zhuǎn)化為 POV-Ray 點(diǎn)集模型文件。例如將 foo.asc 轉(zhuǎn)化為 foo.inc 文件,并且二者位于同一目錄:
points = points_parser('foo.asc')
output_points_model(points, 'foo')
若結(jié)合 Python 的命令行參數(shù)方式,便可寫出一個(gè)可將任意一份三維點(diǎn)集數(shù)據(jù)轉(zhuǎn)化為 POV-Ray 模型文件的小工具:
@ test.py # [Python]
# points-to-pov.py @
import os
import sys
if __name__=="__main__":
path = sys.argv[1]
(parent, file_name) = os.path.split(path)
(model_name, ext_name) = os.path.splitext(file_name)
points = points_parser(path)
output_points_model(points, model_name)
@
注:上述代碼片段中的 # points_model.py @ 表示將所有名為 points_model.py 的代碼片段匯集于該語(yǔ)句出現(xiàn)之處。
為了照顧一下至此尚未看懂上述代碼片段首部與尾部的那些 @ 代碼片段 # [語(yǔ)言標(biāo)記](méi) + 或 ^+ 運(yùn)算 之類符號(hào)的人,下面給出 test.py 的完整代碼:
def points_parser(src_file_name, right_handed = True, dim = 3):
points = []
with open(src_file_name, 'r') as src:
for line in src:
coords = line.split()
if len(coords) != dim:
continue
x = []
for t in coords:
x.append(float(t))
if right_handed:
x[dim - 1] = -x[dim - 1] # 將 x 的坐標(biāo)從右手坐標(biāo)系變換到左手坐標(biāo)系
points.append(x)
src.close()
return points
def output_points_model(points, model_name, dim = 3):
model = open(model_name + '.inc', 'w')
model.write('#declare ' + model_name + ' = union {\n')
for x in points:
model.write(' sphere {
for i in range(0, dim):
if i < dim - 1:
model.write('%f, ' % (x[i]))
else:
model.write('%f' % (x[i]))
model.write('>, point_size_of_' + model_name + '}\n')
model.write('} // ' + model_name + ' end\n')
model.close()
import sys
if __name__=="__main__":
path = sys.argv[1]
(parent, file_name) = os.path.split(path)
(model_name, ext_name) = os.path.splitext(file_name)
points = points_parser(path)
output_points_model(points, model_name)
實(shí)際上在我這里,上述代碼是通過(guò)我寫的一個(gè)名字叫 orez 的工具直接從這份文檔中提取得到:
$ orez -t -e test.py python-meeting-povray.md
其中,python-meeting-povray.md 便是這份文檔的名字。
試著讓 Python 解釋器執(zhí)行
$ python3 test.py foo.asc
結(jié)果會(huì)在 src.asc 所在的目錄中產(chǎn)生 foo.inc 文件,其內(nèi)容類似:
#declare foo = union {
sphere { <3.554705, 199.173300, 8.394049>, point_size_of_foo}
sphere { <3.667395, 198.429900, 10.576820>, point_size_of_foo}
... ... ...
} // foo end
其中,foo_size 是小球的半徑值,但是現(xiàn)在它只是一個(gè)尚未定義的變量,它的值需要在在視圖中進(jìn)行確定。
在視圖看來(lái),模型是什么?
前面說(shuō)過(guò),模型-視圖-控制器這個(gè)范式,各個(gè)部分是分工合作的關(guān)系,而不是只分工不合作的關(guān)系。在上述的點(diǎn)集模型構(gòu)造過(guò)程中,用于表示點(diǎn)的小球的半徑是一個(gè)未定義的變量,它需要在視圖中進(jìn)行定義。因此,對(duì)于點(diǎn)集的繪制這一任務(wù)而言,視圖與模型之間最基本的合作是視圖需要為點(diǎn)集模型確定小球的半徑。
下面是針對(duì)點(diǎn)集的視圖與模型之間一種非常簡(jiǎn)單又粗暴的合作方式:
#declare foo_size = 0.1;
#include "foo.inc"
object {
foo
pigment {
color rgb <0.5, 0.5, 0.5>
}
}
這樣,在視圖文件中載入 foo.inc 時(shí),foo_size 的值就是 0.1。
這種簡(jiǎn)單粗暴的合作方式帶來(lái)的問(wèn)題是,foo_size 的取值有時(shí)會(huì)不合適,太小了,會(huì)導(dǎo)致點(diǎn)集不可見(jiàn),太大了,看到的又往往是一堆相交的球體,以致看不清點(diǎn)集的形貌。
現(xiàn)在,姑且容忍這種簡(jiǎn)單又粗暴的方式,繼續(xù)考慮為點(diǎn)集模型與視圖之間是否還存在其他方面的聯(lián)系,這需要從 POV-Ray 視圖的基本結(jié)構(gòu)開(kāi)始考慮。
在 POV-Ray 視圖結(jié)構(gòu)中,首先要考慮相機(jī)的擺放,例如:
camera {
location
look_at
}
location 參數(shù)定義了相機(jī)的位置,look_at 參數(shù)定義的是相機(jī)待拍攝的三維場(chǎng)景的中心,即相機(jī)鏡頭光心要對(duì)準(zhǔn)的位置。
對(duì)于拍攝點(diǎn)集模型而言,通常會(huì)希望點(diǎn)集能夠完整且最大化的出現(xiàn)在所拍攝照片中,因此相機(jī)參數(shù)的設(shè)定依賴點(diǎn)集模型的位置與尺寸。
除了相機(jī)之外,POV-Ray 視圖還需要光源。沒(méi)有光,就沒(méi)有圖像。在 POV-Ray 視圖里像上帝那樣創(chuàng)造一個(gè)太陽(yáng),并不困難:
light_source {
color White
}
表示光源的位置。color White 表示光源的顏色是白光。光源的位置也依賴于點(diǎn)集模型的位置與尺寸,只是不像相機(jī)那樣敏感。通常情況下,只要光源的位置足夠高遠(yuǎn),它總是能夠照到待渲染的模型上的,例如:
light_source {
<0, 5000, -5000>
color White
}
這樣的光源就類似于在一個(gè)位于 (0, 0, 0) 的物體的正前上方高掛著一個(gè)太陽(yáng)。只要沒(méi)有物體比這樣的光源更高遠(yuǎn),就無(wú)需考慮物體的位置與尺寸。
現(xiàn)在,待繪制的點(diǎn)集模型、相機(jī)與光源均已出現(xiàn),它們構(gòu)成了一幅完整的 POV-Ray 視圖:
camera {
location
look_at
}
light_source {
color White
}
#declare foo_size = 0.1;
#include "foo.inc"
object {
foo
pigment {
color rgb <0.5, 0.5, 0.5>
}
}
相機(jī)、光源以及點(diǎn)的尺寸等參數(shù)的確定皆與繪制的點(diǎn)集模型的位置與尺寸相關(guān)。那么,點(diǎn)集模型的位置與尺寸該如何給出?一個(gè)簡(jiǎn)單又有效的方法是計(jì)算點(diǎn)集模型的軸向最小包圍盒,以包圍盒的中心作為點(diǎn)集的中心。相機(jī)與光源若都位于包圍盒的外接球空間之外,并且相機(jī)的光心對(duì)準(zhǔn)包圍盒的中心,那么就可以保證點(diǎn)集模型可見(jiàn)并且總是位于相機(jī)的拍攝范圍之內(nèi)。至于點(diǎn)的尺寸,可將其視為包圍盒外接球空間的最小長(zhǎng)度單位,并使之與包圍盒外接球半徑成固定比例。
點(diǎn)集的包圍球
下面的代碼可計(jì)算基于點(diǎn)集的軸向最小包圍盒的外接球的中心與半徑:
@ points-to-pov.py # +
import math
def space_of_points(points, dim = 3):
llc = []
urc = []
for i in range(0, dim):
llc.append(sys.float_info.max)
urc.append(-sys.float_info.max)
for x in points:
for i in range(0, dim):
if llc[i] > x[i]:
llc[i] = x[i]
if urc[i] < x[i]:
urc[i] = x[i]
center = []
squared_d = 0.0
for i in range(0, dim):
center.append(0.5 * (urc[i] + llc[i]))
t = urc[i] - llc[i]
squared_d += t * t
r = 0.5 * math.sqrt(squared_d)
return (center, r)
@
生成 POV-Ray 視圖文件
如上文所述,一旦獲得了點(diǎn)集的包圍球的中心與半徑,便可進(jìn)行相機(jī)、光源以及點(diǎn)的尺寸等參數(shù)的設(shè)定,從而生成 POV-Ray 視圖文件。有了視圖文件,便可由 POV-Ray 解析器生成渲染結(jié)果。不過(guò),事情沒(méi)那么簡(jiǎn)單。當(dāng)然也沒(méi)那么復(fù)雜。POV-Ray 解析器(至少 3.7 版本)對(duì)一些 POV-Ray 代碼有一些硬性要求,即一些代碼必須提供,否則就會(huì)給出警告信息。這部分代碼與繪制點(diǎn)集模型基本上沒(méi)有太大關(guān)系,因此下面將其隔離對(duì)待。此外,為了能讓基本的渲染功能正常進(jìn)行,也需要載入 POV-Ray 的一些預(yù)定義文件,例如顏色的預(yù)定義文件。可將這些代碼看作是視圖文件的「導(dǎo)言」:
@ points-to-pov.py # +
def view_prelude(view):
prelude = [
'#version 3.7;\n',
'#include "colors.inc"\n',
'background {color White}\n',
'global_settings {assumed_gamma 1.0}\n\n'
]
view.writelines(prelude)
@
下面開(kāi)始考慮如何構(gòu)造視圖的基本要素。
首先給出點(diǎn)集包圍球的中心與半徑,并將包圍球的中心作為視圖的初始中心:
@ points-to-pov.py # +
def space_of_scene(view, x, r):
view.write('#declare model_center = ;\n' % ((x[0], x[1], x[2])))
view.write('#declare model_radius = %f;\n' % (r))
view.write('#declare view_center = model_center;\n\n')
@
然后擺放相機(jī):
@ points-to-pov.py # +
def place_camera(view):
view.write('camera {\n')
view.write(' location <0, 0, -model_radius> + model_center * z\n')
view.write(' look_at <0, 0, 0>\n')
view.write(' translate view_center\n')
view.write('}\n\n')
@
上述代碼可將相機(jī)擺放點(diǎn)集模型的正前方,光心對(duì)準(zhǔn)點(diǎn)集包圍球的中心,并且相機(jī)的光心到點(diǎn)集包圍球中心的距離與包圍球半徑相同。
注:POV-Ray 的坐標(biāo)系是左手系,z 軸的正方向指向屏幕內(nèi)部。因此,相機(jī)相對(duì)于點(diǎn)集的位移為負(fù)值,意味著沿 z 軸負(fù)方向移動(dòng)。
再來(lái)看光源的設(shè)定:
@ points-to-pov.py # +
def place_light_source(view, color = [1.0, 1.0, 1.0]):
view.write('light_source {\n')
view.write(' model_center + <0, 0, -10 * model_radius>\n')
view.write(' color rgb \n' % (color[0], color[1], color[2]))
view.write(' shadowless // 無(wú)影光源\n')
view.write('}\n\n')
@
光源的位置被設(shè)定在相機(jī)的正上方,與相機(jī)的距離為 10 * model_radius。
最后將點(diǎn)集模型放到三維場(chǎng)景中:
@ points-to-pov.py # +
def place_model(view, model_name, s, color = [0.5, 0.5, 0.5]):
view.write('#declare point_size_of_' + model_name + ' = %f;\n' % (r * s))
view.write('#include "' + model_name + '.inc"\n')
view.write('object {\n')
view.write(' ' + model_name + '\n')
view.write(' pigment {\n')
view.write(' color rgb \n' % (color[0], color[1], color[2]))
view.write(' }\n')
view.write('}\n')
@
將上述函數(shù)組合起來(lái),便可得到視圖文件生成器:
@ test-2.py # [Python]
# points-to-pov.py @
import os
import sys
if __name__=="__main__":
point_size = float(sys.argv[1])
path = sys.argv[2]
(parent, file_name) = os.path.split(path)
(model_name, ext_name) = os.path.splitext(file_name)
# 生成模型文件
points = points_parser(path)
output_points_model(points, model_name)
# 生成視圖文件
(center, r) = space_of_points(points)
with open(model_name + '.pov', 'w') as view:
view_prelude(view)
space_of_scene(view, center, r)
place_camera(view)
place_light_source(view)
place_model(view, model_name, point_size)
view.close()
@
測(cè)試:
$ python3 test-2.py 0.003 foo.asc
$ povray +P foo.pov
0.003 是點(diǎn)的尺寸系數(shù),它與點(diǎn)集的包圍半徑的積便是點(diǎn)的實(shí)際尺寸。
折騰到這里,終于能看到一張圖了。上述命令最終得到的渲染結(jié)果為 foo.png:
產(chǎn)生上述渲染結(jié)果的視圖文件如下:
#version 3.7;
#include "colors.inc"
background {color White}
global_settings {assumed_gamma 1.0}
#declare model_center = <2.413898, 15.227750, 1.339995>;
#declare model_radius = 3.807916;
#declare view_center = model_center;
camera {
location <0, 0, -model_radius> + model_center * z
look_at <0, 0, 0>
translate view_center
}
light_source {
model_center + <0, 0, -10 * model_radius>
color rgb <1.000000, 1.000000, 1.000000>
shadowless
}
#declare point_size_of_points = 0.011424;
#include "points.inc"
object {
points
pigment {
color rgb <0.500000, 0.500000, 0.500000>
}
}
控制器
一番辛苦,看到的只是一幅簡(jiǎn)單的點(diǎn)集圖像,的確很丟 POV-Ray 的臉,然而這就是所謂的「白描」。若想得到美侖美奐的渲染結(jié)果,不僅需要對(duì) POV-Ray 足夠熟悉,也需要具備一定的美術(shù)功底。不過(guò),所有的修飾都集中在視圖部分。模型是不變的。事實(shí)上能得到這種白描的結(jié)果,已經(jīng)是邁出了一大步。
現(xiàn)在來(lái)考慮控制器的構(gòu)建。與模型、視圖的代碼生成器相比,POV-Ray 的控制器更簡(jiǎn)單一些,因?yàn)楦静恍枰獮樗帉懘a生成器。就像要得到精美的渲染結(jié)果只需要修改視圖部分,控制器也是如此,一切只需要?jiǎng)邮秩バ薷囊晥D文件。值得一提的是,POV-Ray 提供了制作動(dòng)畫的功能。利用這一功能,可以讓上面的白描渲染結(jié)果動(dòng)起來(lái)。老話說(shuō),一動(dòng)不如一靜,然而現(xiàn)代人看書(shū)的人少啊,看片的人多。
我要讓上面所繪制的模型向左偏移 15 度角,然后再向右偏移 15 度角,即讓它搖晃一個(gè)角度,輕輕搖晃,一點(diǎn)一點(diǎn)搖晃。要實(shí)現(xiàn)這一想法,只需將上述的視圖文件 foo.pov 的 object 部分作以下修改:
#declare joggle = 30;
object {
foo
translate -model_center
rotate #if (clock < 0.51) clock #else (1 - clock) #end * joggle * y
translate model_center
pigment {
color rgb <0.300000, 0.300000, 0.300000>
}
}
上述代碼只是對(duì)點(diǎn)集模型增加了平移與旋轉(zhuǎn)變換:(1) 平移點(diǎn)集模型,使其中心與坐標(biāo)系原點(diǎn)重合;(2) 將點(diǎn)集模型向左緩慢偏移 15 度角,再向右緩慢偏移 15 度角;(3) 將點(diǎn)集的中心恢復(fù)到原來(lái)的位置。
然后在 foo.pov 的同一目錄增加 foo.ini 文件,內(nèi)容如下:
Input_File_Name = foo.pov
Initial_Frame = 1
Final_Frame = 30
接下來(lái),將 POV-Ray 解析器作用于 foo.ini:
$ povray foo.ini
上述命令需要一些時(shí)間,待其運(yùn)行結(jié)束后,會(huì)產(chǎn)生 30 幅圖片,名稱為 foo01.png, foo02.png, ... foo30.png。使用 imagemagick 工具箱的 convert 命令可將這組圖片合成為 GIF 動(dòng)圖 foo.gif:
$ convert -delay 10 -loop 0 foo*.png foo.gif
結(jié)果如下圖所示:
結(jié)語(yǔ)
雖然本文檔僅介紹了點(diǎn)集模型的繪制,但是對(duì)于更復(fù)雜的圖形繪制而言, 0 和 1 已經(jīng)有了,剩下的事情是 0 和 1 的組合。
附錄
總結(jié)
以上是生活随笔為你收集整理的python ray定时_当 Python 邂逅 POV-Ray的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【SUMO学习】初级 OSMWebWiz
- 下一篇: python制作猜数字小游戏