Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

Organization

POV-Rayでよく使う制御文

はじめに

これは POV-Rayによる数学お絵かき入門 Advent Calendar 2017 の6日目の記事です.

POV-Rayでは幾つかの制御文が用意されていますが, その中でも今日は

  • while
  • if
  • macro

について書きます.

公式ドキュメントでは以下が近いです.
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_2_6
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_2_8

while

POV-Rayで繰り返しの処理を書くには次のようにします.

#while(条件)
    処理
#end

POV-Rayにはfor文が用意されていないため, 球面を複数並べる処理は次のように書きます.

#declare i=0;
#while(i<5)
    sphere{<i,0,0>,0.2 pigment{rgb<i/4,1-i/4,0>}}
    #declare i=i+1;
#end

この例では色の指定にもiを入れ込めて球面の色が変わるようになっています.https://i.imgur.com/j3sTDBZ.png

if

条件分岐を記述するためには次のように書きます.

#if(条件)
    処理1
#else
    処理2
#end

第四回に書いたように, POV-Rayでは真偽値が1と0で表現されます.
ifwhileの条件で判断される際には, 0に等しいか否かによって判断されます.

macro

マクロを書くには次のように書きます.

#macro(第1引数,...,第n引数)
    処理
#end

つまらない例ですが, 鉛直方向を向いた円柱のマクロは次のように書けます.

#macro(r,l)
    cylinder{<0,0,0>,<0,l,0>,r}
#end

第四回でも少し触れましたが, macro内で変数を宣言する際にはローカル変数にはlocal, グローバル変数にはdeclareを使います.

基本的にはmacroは関数と考えて差し支えありませんが, 厳密には異なります.
これに関しては連載後半で改めて記述する予定です.

多面体

立方体

whilemacroを使う
一番簡単な立方体から書きなおします.

対称性を考えれば, 頂点は次のように書けます.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
            #declare k=k+2;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

cylinderを付け加えて辺を描きます.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
            #declare k=k+2;
        #end
        cylinder{<i,j,1>,<i,j,-1>,0.05 pigment{rgb<1,0,1>}}
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

ここで次のマクロRotateを定義します.

#macro Rotate(w,i)
    #local j=i;
    #local wj=w;
    #while(j)
        #local wj=<wj.z,wj.x,wj.y>;
        #local j=j-1;
    #end
    wj
#end

このマクロによって, ベクトル$(1,1,1)$を回転軸として引数のベクトルが$120^\circ$回転します.

上と合わせれば次のように書けます.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
            #declare k=k+2;
        #end
        #declare l=0;
        #while (l<3)
            cylinder{Rotate(<i,j,1>,l),Rotate(<i,j,-1>,l),0.05 pigment{rgb<1,0,1>}}
            #declare l=l+1;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

正八面体

同様に次のように描けます.

#declare i=-1;
#while(i<2)
    #declare l=0;
    #while(l<3)
        sphere{Rotate(<i,0,0>,l),0.05 pigment{rgb<0,1,1>}}
        #declare j=-1;
        #while (j<2)
            cylinder{Rotate(<i,0,0>,l),Rotate(<0,j,0>,l),0.05 pigment{rgb<0,1,1>}}
            #declare j=j+2;
        #end
        #declare l=l+1;
    #end
    #declare i=i+2;
#end

正四面体

全列挙の方が早そうですが, 折角なので対称性を利用して描いてみましょう.
これまでと違って条件分岐ifも使います.
立方体の頂点を元に正四面体を2つ作ります.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            sphere{<i,j,k>,0.05 pigment{rgb<1,1,0>}}
            #declare k=k+2;
        #end
        #declare l=0;
        #while (l<3)
            cylinder{Rotate(<i,j,1>,l),Rotate(<i,-j,-1>,l),0.05 pigment{rgb<1,0,1>}}
            #declare l=l+1;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

2つの正四面体の内の1つだけ描画するために, spherecylinderifで囲みます.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            #if(mod(i*j*k,2)=1) sphere{<i,j,k>,0.05 pigment{rgb<1,1,0>}} #end
            #declare k=k+2;
        #end
        #declare l=0;
        #while (l<3)
            #if(mod(i*j,2)=1) cylinder{Rotate(<i,j,1>,l),Rotate(<i,-j,-1>,l),0.05 pigment{rgb<1,1,0>}} #end
            #declare l=l+1;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

正十二面体

前回愚直に書こうとして諦めた正十二面体も, 次のように書けます.

#declare phi=(1+sqrt(5))/2;

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare k=-1;
        #while(k<2)
            sphere{<i,j,k>,0.05 pigment{rgb<1,0,0>}}
            #declare k=k+2;
        #end
        #declare l=0;
        #while (l<3)
            sphere{Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i*phi,0,0>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i,j,1>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i,j,-1>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            #declare l=l+1;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

正二十面体

最後の例は正二十面体です.
これも各頂点座標が黄金比で書けます.

#declare i=-1;
#while(i<2)
    #declare j=-1;
    #while(j<2)
        #declare l=0;
        #while (l<3)
            sphere{Rotate(<i,j*phi,0>,l),0.05 pigment{rgb<0,0,1>}}
            cylinder{Rotate(<0,j*phi,0>,l),Rotate(<i,j*phi,0>,l),0.05 pigment{rgb<0,0,1>}}
            #declare k=-1;
            #while(k<2)
                cylinder{Rotate(<1,1*phi,0>,l)*<i,j,k>,Rotate(<1,1*phi,0>,l+1)*<i,j,k>,0.05 pigment{rgb<0,0,1>}}
                #declare k=k+2;
            #end
            #declare l=l+1;
        #end
        #declare j=j+2;
    #end
    #declare i=i+2;
#end

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?