潰れた空間のCG


不規則な生活で頭がおかしくなったのか、
衝動的に、数学的なCGを書いてみたくなりました。


空間から、空間の一部をくりぬくとどう見えるかという、CGを合成します。



と言っても、物理や幾何はサッパリなので、適当に設定します。

で、スクリーンと画像の間をくりぬきます。

くりぬいた空間は球状。

球の表面は、反対側と接続されると言う事にします。
つまり、球の表面にぶつかった光線は、球の反対側から出てきます。


変換した画像がこれです。


元画像は
ファイル:19-v 2h Vasnetsov.jpg - Wikipedia
から拝借


なんか、ただ単にでっかい凸レンズが置いてあるだけのような・・・

面白くないですが、一応、ソースも置いておきます。

#encoding:shift-jis
from __future__ import with_statement, division, print_function
import Image
from math import *
from itertools import *

dist_size = (1024, 768)

src_image_path = u"岐路に立つ騎士(ヴィクトル・ヴァスネツォフ画,1878).jpg"
src = Image.open(src_image_path).convert("RGB")

D1  = 2 # 描画先スクリーンとの距離
S1 = (2 * dist_size[0] / dist_size[1], 2) # 描画先スクリーンのサイズ / 2

D0 = 4 # くりぬかれた球体との距離
R  = 1 # 球体の半径

D2 = 6 #元画像との距離
S2 = (6 * src.size[0] / src.size[1], 6)

MaxTheta = asin(R / D0)
assert 0 < MaxTheta

def s1pos_to_s2pos(s1pos):
    r1 = sqrt(s1pos[0]**2 + s1pos[1]**2)
    theta = atan(r1 / D1)
    alpha  = atan2(s1pos[1], s1pos[0])
    
    if abs(theta) < MaxTheta:
        r2 = -r1 * (2 * D0 - D2) / D1
    else:
        r2 = r1 * D2 / D1
    
    return (r2 * cos(alpha),
            r2 * sin(alpha))

def dist_to_src(dist_pixel_pos):
    s1pos = tuple(
        S1[i] * (dist_pixel_pos[i] / dist_size[i] - 0.5)
        for i in [0, 1])
    
    s2pos = s1pos_to_s2pos(s1pos)
    
    return tuple(
        src.size[i] * (s2pos[i] / S2[i] + 0.5)
        for i in [0, 1])

dist = Image.new("RGB", dist_size, (0, 0, 0))

for dist_pixel_pos in product(xrange(dist_size[0]), xrange(dist_size[1])):
    src_pixel_pos = dist_to_src(dist_pixel_pos)
    
    if (0 <= src_pixel_pos[0] < src.size[0] and
        0 <= src_pixel_pos[1] < src.size[1]):
        c = src.getpixel(src_pixel_pos)
    else:
        c = (0, 0, 0)
    
    dist.putpixel(dist_pixel_pos, c)

dist.save("a.png")
dist.show()