[ ray ] 超簡単レイトレプログラム

ずーっとほったらかしにしてた、レイトレ球レンダリングを、
ハッと思い立って書いてみました。


で、その結果↓
raytest070331a.jpg

交差判定だのなんだのってところが、どうやってんの!?ってずーっと思ってて、
一旦判明したんだけどプログラムにするやり方がわかんなくて、
で、なんとなく思いついたから仕事終わってから会社で書いてみた。

前に失敗した時の経験なども生かし、交差判定するところまではほぼ問題なくクリア。
するするっと、数十分程度、かな。厳密にはわからんけどサクッとイケた。
イヤッホーーーゥ!!

そんで上の画像は、それにディフューズ計算を簡単に入れてみたもの。
なんか、端がもっと黒くなってもいいような気がするんだけど、
まぁそこは僕のコーディングミスかもしれないのでスルー。

今回もまたppmで画像を出す方式で書きました。
使用した言語はpython。
プログラムの行数は100行もないくらい。80行前後。
きゃー短い。

この調子で、一般的なレンダリング技術ぐらいはなんとなく理解しておきたいなぁ。

そうそう、ライトも追加してみようと思って、視点ベクトルと法線で計算していたdiffuseを
ライトと法線で計算しようと思ったら、

ValueError: math domain error

というエラーが出て計算できないので諦めた。
原因不明。人為的なものじゃないと思うんだけどなぁ、、
まぁ、仕方ないので要調査です。

以下、一応ソースコード載せておきます。
恥ずかしながら。。
間違いなどあれば是非ご指摘くださいませーーー。

————————————————————————–

from math import *

class Vector:
    def __init__( self, x, y, z ):
        self.x = x
        self.y = y
        self.z = z
    def sub( self, other ):
        self.x -= other.x
        self.y -= other.y
        self.z -= other.z
        return Vector( self.x, self.y, self.z )
    def mult( self, other ):
        return self.x*other.x+self.y*other.y+self.z*other.z
    def square( self ):
        return self.x*self.x+self.y*self.y+self.z*self.z
    def dot( self, other ):
        length = sqrt( self.x*self.x+self.y*self.y+self.z*self.z )
        n1x = self.x / length
        n1y = self.y / length
        n1z = self.z / length
        length = sqrt( other.x*other.x+other.y*other.y+other.z*other.z )
        n2x = other.x / length
        n2y = other.y / length
        n2z = other.z / length
        return sqrt( n1x*n2x+n1y*n2y+n1z*n2z )

class Sphere:
    def __init__( self, r ):
        self.r = r
    def intersect( self, ray, eye ):
        a = ray.square()
        b = ray.mult( eye )*2
        c = eye.square()-self.r
        return b*b-4*a*c
    def distance( self, ray, eye ):
        a = ray.square()
        b = ray.mult( eye )*2
        c = eye.square()-self.r
        return ( -b + sqrt( b*b -4*a*c ) ) / 2*a

# main routine
filename = “E:\\raytest.ppm”
file = open( filename, ‘w’, -1 )
width = 200
height = 200
radius = 10.0
max = 5.0
i = j = 0
x = y = -max
z = -10.0
screenY = -max
perStep = max*2/width
sphere = Sphere( radius )
file.write( “P3\n”+str(width)+” “+str(height)+”\n255\n” )
for i in range( height ):
    x += perStep
    y = screenY
    for j in range( width ):
        y += perStep
        eye = Vector( x, y, z )
        ray = Vector( x, y, z+1.0 )
        ray = ray.sub( eye )
        d = sphere.intersect( ray, eye )
        if d >= 0:
            t = sphere.distance( ray, eye )
            px = eye.x + t*ray.x
            py = eye.y + t*ray.y
            pz = eye.z + t*ray.z
            p = Vector( px, py, pz )
            p.dot( ray )
            diffuse = p.dot( ray )
            result = int( 255*diffuse )
            file.write( str(result)+” “+str(result)+” “+str(result)+” ” )
        else:
            file.write( “255 255 255 ” )
    file.write( “\n” )
print( ” – – – – – rendering finished – – – – – ” )

コメントを残す

メールアドレスが公開されることはありません。