Enter: レンダリング, Space: 粗くレンダリング, 十字キー: カメラの移動
できる限り直感的にベクトルの計算ができるよう、かなりマクロとか使いまくってるのでウンコード。
#module m
#define global INF expf(1000)
// Vector
#enum global X = 0
#enum global Y
#enum global Z
#define global let_vec(%1,%2,%3,%4) %1.X=%2:%1.Y=%3:%1.Z=%4
#define global copy_vec(%1,%2) let_vec %1,%2.X,%2.Y,%2.Z
#define global ret_vec(%1) let_vec %1,rx@m,ry@m,rz@m
#define global log_vec(%1,%2="Vec") logmes %2+strf("(%%f,%%f,%%f)",%1.X,%1.Y,%1.Z)
#define global plus_vec(%1,%2) _plus_vec %1.X,%1.Y,%1.Z,%2.X,%2.Y,%2.Z
#deffunc _plus_vec double x1,double y1,double z1,double x2,double y2,double z2
rx=x1+x2
ry=y1+y2
rz=z1+z2
return
#define global minus_vec(%1,%2) _minus_vec %1.X,%1.Y,%1.Z,%2.X,%2.Y,%2.Z
#deffunc _minus_vec double x1,double y1,double z1,double x2,double y2,double z2
rx=x1-x2
ry=y1-y2
rz=z1-z2
return
#define global cross_vec(%1,%2) _cross_vec %1.X,%1.Y,%1.Z,%2.X,%2.Y,%2.Z
#deffunc _cross_vec double x1,double y1,double z1,double x2,double y2,double z2
rx=y1*z2-z1*y2
ry=z1*x2-x1*z2
rz=x1*y2-y1*x2
return
#define global ctype dot_vec(%1,%2) _dot_vec(%1.X,%1.Y,%1.Z,%2.X,%2.Y,%2.Z)
#defcfunc _dot_vec double x1,double y1,double z1,double x2,double y2,double z2
return x1*x2+y1*y2+z1*z2
#define global ctype mag_vec(%1) _mag_vec(%1.X,%1.Y,%1.Z)
#defcfunc _mag_vec double x1,double y1,double z1
return sqrt(_dot_vec(x1,y1,z1,x1,y1,z1))
#define global times_vec(%1,%2) _times_vec %1.X,%1.Y,%1.Z,%2
#deffunc _times_vec double x1,double y1,double z1,double n
rx=n*x1
ry=n*y1
rz=n*z1
return
#define global norm_vec(%1) _norm_vec %1.X,%1.Y,%1.Z
#deffunc _norm_vec double x1,double y1,double z1
mag = _mag_vec(x1,y1,z1)
if (mag == 0) { div = INF }else{ div = 1.0 / mag }
_times_vec x1,y1,z1, div
return
// Color
#enum global R = 0
#enum global G
#enum global B
#define global let_col(%1,%2,%3,%4) %1.R=%2:%1.G=%3:%1.B=%4
#define global copy_col(%1,%2) let_col %1,%2.R,%2.G,%2.B
#define global ret_col(%1) let_col %1,rr@m,rg@m,rb@m
#define global setDraw_col(%1) color limit(int(%1.R*255),0,255),limit(int(%1.G*255),0,255),limit(int(%1.B*255),0,255)
#define global log_col(%1,%2="Col") logmes %2+strf("(%%f,%%f,%%f)",%1.R,%1.G,%1.B)
#define global plus_col(%1,%2) _plus_col %1.R,%1.G,%1.B,%2.R,%2.G,%2.B
#deffunc _plus_col double r1,double g1,double b1,double r2,double g2,double b2
rr=r1+r2
rg=g1+g2
rb=b1+b2
_norm_result_col
return
#define global times_col(%1,%2) _times_col %1.R,%1.G,%1.B,%2
#deffunc _times_col double r1,double g1,double b1,double n
rr=n*r1
rg=n*g1
rb=n*b1
_norm_result_col
return
#define global cross_col(%1,%2) _cross_col %1.R,%1.G,%1.B,%2.R,%2.G,%2.B
#deffunc _cross_col double r1,double g1,double b1,double r2,double g2,double b2
rr=r1*r2
rg=g1*g2
rb=b1*b2
_norm_result_col
return
#deffunc _norm_result_col
rr=limitf(rr,0,1.0):rg=limitf(rg,0,1.0):rb=limitf(rb,0,1.0)
return
#global
// Initialize
let_vec zero, 0.0, 0.0, 0.0
let_vec right, 1.0, 0.0, 0.0
let_vec left, -1.0, 0.0, 0.0
let_vec forward, 0.0, 0.0, 1.0
let_vec backward, 0.0, 0.0, -1.0
let_vec down, 0.0, -1.0, 0.0
let_vec up, 0.0, 1.0, 0.0
let_col white,1.0, 1.0, 1.0
let_col black,0.0, 0.0, 0.0
let_col grey, 0.5, 0.5, 0.5
let_col red, 1.0, 0.0, 0.0
let_col green,0.0, 1.0, 0.0
let_col blue, 0.0, 0.0, 1.0
// Camera
let_vec camera, 3.0, 2.0, 4.0
let_vec cameraLook, -1.0, 0.5, 0.0
// Light
ddim light, 4, 3
ddim lightColor, 4, 3
let_vec light.0, -2.0, 2.5, 0.0
let_vec light.1, 0.0, 3.5, 0.0
let_vec light.2, 1.5, 2.5, -1.5
let_vec light.3, 1.5, 2.5, 1.5
copy_col lightColor.0, white
copy_col lightColor.1, red
copy_col lightColor.2, blue
copy_col lightColor.3, green
// Sphere
ddim sphere, 2, 3
let_vec sphere.0, 0.0, 1.0, -0.25
let_vec sphere.1, -1.0, 0.5, 1.5
// Ground
let_vec ground, 0.0, -1.0, 0.0
// Background Color
copy_col bgColor, black
// Default Color
copy_col defColor, black
div = 20
gosub *render
// Main Loop
*main
gosub *keyCheck
await 60
goto *main
*render
gosub *cameraInit
if (div > 1) :redraw 0
repeat dw
dx = cnt
if (div == 1) :redraw 0, dx*div, 0, (dx+1)*div, ginfo_winy
repeat dh
dy = cnt
screenX = (double(dx) - w/2.0) / 2.0 / w
screenY = (-(double(dy) - h/2.0) / 2.0 / h) * aspect
copy_vec cameraRayStart, camera
times_vec cameraRgt, screenX :ret_vec cameraRayDir
times_vec cameraUp, screenY :ret_vec tmp
plus_vec cameraRayDir, tmp :ret_vec cameraRayDir
plus_vec cameraRayDir, cameraFor :ret_vec cameraRayDir
norm_vec cameraRayDir :ret_vec cameraRayDir
gosub *trace
setDraw_col cl
boxf dx*div, dy*div, (dx+1)*div, (dy+1)*div
loop
if (div == 1) :redraw 1, dx*div, 0, (dx+1)*div, ginfo_winy
loop
if (div > 1) :redraw 1
return
*keyCheck
stick key, 1+2+4+8
// no needs to redraw
if ((key & (1+2+4+8+32)) == 0) :return
// initialize cameraDelta
copy_vec cameraDelta, zero
if (key & 1) {
copy_vec cameraDelta, left
div = 20
}
if (key & 2) {
copy_vec cameraDelta, backward
div = 20
}
if (key & 4) {
copy_vec cameraDelta, right
div = 20
}
if (key & 8) {
copy_vec cameraDelta, forward
div = 20
}
plus_vec camera, cameraDelta :ret_vec camera
if (key & 32) {
div = 1
}
gosub *render
return
*cameraInit
// initialize
copy_vec cameraFor, zero
copy_vec cameraRgt, zero
copy_vec cameraUp , zero
// determine axis of camera
minus_vec cameraLook, camera :ret_vec cameraFor
norm_vec cameraFor :ret_vec cameraFor
cross_vec cameraFor, down :ret_vec cameraRgt
norm_vec cameraRgt :ret_vec cameraRgt
cross_vec cameraFor, cameraRgt:ret_vec cameraUp
norm_vec cameraUp :ret_vec cameraUp
dw = ginfo_winx / div
dh = ginfo_winy / div
w = double(dw)
h = double(dh)
aspect = h / w
return
*trace
copy_col cl, bgColor
repeat 5
// setup ray
copy_vec rayStart, cameraRayStart
copy_vec rayDir, cameraRayDir
trace_mode = 1
gosub *traceRay
// doesn't hit
if (distance >= INF) :break
// Reflection
times_vec normal, dot_vec(normal, rayDir) :ret_vec reflection
times_vec reflection, 2.0 :ret_vec reflection
minus_vec rayDir, reflection :ret_vec reflection
norm_vec reflection :ret_vec reflection
copy_vec rayStart, rayPosition
// Lighting
repeat length(light)
minus_vec light.cnt, rayStart :ret_vec lightPosition
norm_vec lightPosition :ret_vec lightDir
copy_vec rayDir, lightDir
trace_mode = 0
gosub *traceRay
// is in shadow
if (distance <= mag_vec(lightPosition)) {
continue
}
illum = dot_vec(lightDir, normal)
spec = dot_vec(lightDir, reflection)
copy_col illumColor, defColor
copy_col specColor, defColor
if (illum > 0) {
times_col lightColor.cnt, illum :ret_col illumColor
}
if (spec > 0) {
times_col lightColor.cnt, powf(spec,250.0) :ret_col specColor
}
cross_col illumColor, intersected :ret_col illumColor
cross_col specColor, lightColor.cnt :ret_col specColor
plus_col illumColor, specColor :ret_col illumColor
plus_col cl, illumColor :ret_col cl
loop
// setup next ray
copy_vec cameraRayStart, rayStart
copy_vec cameraRayDir, reflection
loop
return
*traceRay
distance = INF
// Sphere Intersection
repeat length(sphere)
minus_vec sphere.cnt, rayStart :ret_vec eo
v = dot_vec(eo, rayDir)
if (v >= 0) {
tmp_dist1 = 0.5 - (dot_vec(eo,eo) - v*v)
if (tmp_dist1 >= 0) {
tmp_dist2 = v - sqrt(tmp_dist1)
if (distance > tmp_dist2) {
distance = tmp_dist2
times_vec rayDir, distance :ret_vec rayPosition
plus_vec rayStart, rayPosition :ret_vec rayPosition
if (trace_mode == 1) {
copy_col intersected, grey
// normal
minus_vec rayPosition, sphere.cnt :ret_vec normal
norm_vec normal :ret_vec normal
}
}
}
}
loop
// Ground Intersection
d = dot_vec(up, rayDir)
if (d < 0) {
tmp_dist1 = (dot_vec(up, rayStart) - ground.Y) / -d
if (distance > tmp_dist1) {
distance = tmp_dist1
if (trace_mode == 1) {
times_vec rayDir, distance :ret_vec rayPosition
plus_vec rayStart, rayPosition :ret_vec rayPosition
if ((int(rayPosition.X) + int(rayPosition.Z)) \ 2 != 0) {
copy_col intersected, white
} else {
copy_col intersected, black
}
// normal
copy_vec normal, up
}
}
}
return