ペンローズ三角形

 小飼弾さんのブログをよく見るのだが,そこで紹介されていた,だまし絵の本がとても面白かった。杉原厚吉だまし絵のトリック―不可能立体を可能にする (DOJIN選書34)化学同人である。
 まだちゃんと読み終わっていないのだが,触発されて自分でもだまし絵を作ってみた。左は,最もよく言及されるだまし絵「ペンローズ三角形」である。三次元空間では不可能な図形のように見えることで超有名である。
 しかし,この図は3DCGソフトで作った三次元図形を,直投影風に二次元に描きあらわしたものである。本来の投影図は,多面体の稜のみをスクリーンに投影して得られた,線のみで描かれた図であるが,この図の場合は,立体からの平行光線がカメラのフィルムに像を結ぶようにして撮影した画像になっていて,立体を遠くから見た様子を表している。カメラとは別に,立体を照明するための光源も必要で,3DCGソフトは,三次元図形データとしての物体と,カメラ,照明光を三次元空間内に配置したときに,カメラに映る画像を作図してくれる。
 つまり,この図の示す立体は,あり得ない立体ではなく,ちゃんと実在する。不可能図形とされている「ペンローズ三角形」も,実は立体としてつくることが可能なのである。「だまし絵のトリック」では,不可能図形のだまし絵を分類し,立体として作ることが可能なものについて,たくさんの模型を掲げている。ボールが坂をひとりでに転がり上がるような不可能モーションについても触れられていて,それをつくるための模型の展開図も付いている。
 上のペンローズ三角形の種明かしをすると,下図のようになる。左は,直投影でなく透視投影風に描いたものである。つまり,近いものが大きく見え,遠いものが小さく見えるように,カメラを立体の近くにおいて,撮影したような図である。これを見れば,この立体は,実は三角形が閉じておらず,ただの三本の角棒を直角につないでいったものにすぎないことがわかる。手前の角棒の先端が斜めにカットされていて,直投影ではうまい具合にこの輪郭が奥の角棒の輪郭と一致していたにすぎない。透視投影では,図の左上の部分がつながっていないことが分かってしまう。

 上図右は,3DCGを描くときに立体を照らす照明を,無限遠からでなく有限の距離にある光源から当てたものである。よく見ないとわからないが,図の左上の部分に,冒頭に掲げた図には見られない線が入っているのがわかる。光源が近くにあるために,平行な面であっても,位置によって照明が当たる角度が異なるため,このように不完全なペンローズ三角形になってしまう。

 視点を遠くに置いた直投影に相当する図でも,見る角度を変えてしまうと,たちまち三角形の切れ目が露呈する。視点の角度が変わる様子を動画にしてみた。この動画は,ある角度から見るとペンローズ三角形に見える立体を,少しづつ角度を変えながら眺めた様子をあらわす。
ペンローズ三角形.gif 直
 結局,視点の距離,角度,照明の距離のすべてをうまい具合に選ばなければ,この立体はペンローズ三角形に見えないのである。
 考えてみれば,投影図に限らず,三次元図形を,二次元の図に描く場合,一枚の図ではどうしても元の立体の情報が抜け落ちてしまう。それでも通常は二次元的な図を一枚見るだけで,我々は立体の形をすぐに思い浮かべることができる。これはとても不思議なことだが,人間は経験に基づいて,足りない情報を補充して,立体的イメージを作っている。我々は二次元情報にすぎない図を見ても,ただちに立体感を感じ,直線だと直観する線を直線と解釈し,直角だと直感する角度を直角だと考える傾向がある。これは,直線や直角でできた物が身近にあふれているためだ。そしてその解釈は多くの場合に当たる。これを逆手にとったのがだまし絵である。経験による情報補充は厳密なものではないのだ。
 就学前後の子供は不可能図形をみても不思議に思わないらしい。十分な立体把握の経験がないためである。そのうち立体把握のための情報補充法を身につけると,以降,それは無意識で行われるようになり,だまし絵に対しても適用してしまうので,まんまとだまされる,というわけだ。

 最後に,3DCGソフトPOV-Ray用の,ペンローズ三角形のソースコードを以下に示しておく。ソフトはフリーでダウンロードできるので,それをインストールしてこのコードをコピペすると,冒頭のCGが得られるので,興味のある方は試してみてほしい。数値をいろいろいじると図も変わるので結構遊べると思う。

camera {
orthographic
location <50,50,50>
look_at <0, 0, 0>
angle 10
}

light_source {
<0,10,30>
color 1.5
parallel
point_at<0,0,0>
}

light_source {
<10,10,0>
color 0.5
parallel
point_at<0,0,0>
}

#declare Boxes =
merge{
box {<0,0,0>,<-1,-1,9>}
box {<-1,-1,9>,<8,0,10>}
box {<8,-1,10>,<9,8,9>}
pigment{rgb<1,0,0>}
}

#declare P_triangle =
difference{
object {Boxes}
box {<0,-1,-1>,<-2,2,2> rotate z*-45 translate <8,7,9> }
}

object { P_triangle no_shadow translate <-5,-3,-10>}
object { plane { z, -10 } pigment {rgb<1,1,1>} }