// raytracing.c
#include <acknex.h>
#include <default.c>
BMAP* preview_map = "#1024x768x24";
BMAP* ray_bmp;
PANEL* ray_pan =
{
layer = 3;
flags = SHOW | TRANSLUCENT | FILTER | OVERLAY;
}
PANEL* pan_preview =
{
flags = SHOW | TRANSLUCENT;
alpha = 50;
bmap = preview_map;
layer = 2;
}
VECTOR sun_dir;
int k = 0;
var factor = 1;
/// calculates sunshadow
float rayshadow(VECTOR* start)
{
if (k) return 0.8;
VECTOR temp;
vec_set(&temp, sun_dir);
vec_scale(&temp, 10000);
vec_add(&temp, start);
var distance = c_trace(start, &temp, IGNORE_PASSABLE|USE_POLYGON);
if (distance == 0)
{
return 0.8;
}else
{
return 0.1;
}
}
float fresnel(VECTOR* light, VECTOR* normal, float R0)
{
return R0 + (1.0-R0) * pow(1.0-vec_dot(light, normal), 1.0);
}
void raytrace(VECTOR* start, VECTOR* dir, VECTOR* color, int depth)
{
if (depth>3)
{
color->x = 0;
color->y = 0;
color->z = 0;
return 0;
}
depth+=1;
VECTOR temp;
vec_set(&temp, dir);
vec_scale(&temp, 10000);
vec_add(&temp, start);
var distance = c_trace(start, &temp, IGNORE_PASSABLE|USE_POLYGON|SCAN_TEXTURE);
if (distance == 0) ///the sky is the limit
{
color->x = 120;
color->y = 80;
color->z = 60;
return;
}else
{
VECTOR normal;
normal.x = hit->nx;
normal.y = hit->ny;
normal.z = hit->nz;
if (hit->skin1) /// fetch the texture
{
var format= bmap_lock(hit->skin1,0);
var pixel = pixel_for_bmap(hit->skin1, hit->u1, hit->v1);
var alpha;
pixel_to_vec(color, &alpha, format, pixel);
bmap_unlock(hit->skin1);
// vec_set(color, hit->blue);
}else
vec_set(color, _vec(255,255,255));
var diffuse = 1;
VECTOR refcolo;
vec_set(&refcolo, _vec(0,0,0));
if (hit->v != 0) /// get the normal of hit point
{
normal.x = hit->v.nx;
normal.y = hit->v.nz;
normal.z = hit->v.ny;
vec_rotate(&normal, you->pan);
}
vec_normalize(&normal, 1);
VECTOR hitt, n, toCamera, reflect;
vec_set(&hitt, hit.x);
vec_diff(&toCamera, &hitt, camera.x);
vec_normalize(&toCamera, 1);
/// get the reflection vector
vec_set(&reflect, &toCamera);
var d = vec_dot(&toCamera, &normal)*2;
// if (d>0) diffuse=0;
vec_set(&reflect, &normal);
vec_scale(&reflect, d);
vec_diff(&reflect, &toCamera, &reflect);
vec_normalize(&reflect, 1);
vec_set(&temp, hit.x);
vec_set(&n, &normal);
VECTOR col2;
vec_add(&temp, normal);
/// fresnel term for reflection
float refractionIndexRatio =0.3;
const float R0 = pow(1.0-refractionIndexRatio, 2.0)/ pow(1.0+refractionIndexRatio, 2.0);
var fres =clamp(fresnel(vec_inverse(&toCamera), &normal, R0), 0, 1);
/// refraction effect for glas objects
if (you && is(you, FLAG1))
{
diffuse = 0;
VECTOR refract, tt;
float index = 0.9;
if (distance<0) index = 1.0/index;
/// get the refraction vector
vec_inverse(&toCamera);
float a1 = -vec_dot(&normal, &toCamera);
float a2 = sqrt(1-pow(index, 2)*(1-pow(a1,2)));
var t = index*a1-a2;
if (a1<0) t = index*a1+a2;
vec_set(&refract, &normal);
vec_scale(&refract, t);
vec_set(&tt, &toCamera);
vec_scale(&tt, index);
vec_add(&refract, &tt);
vec_set(&temp, &hitt);
vec_sub(&temp, &normal);
vec_sub(&temp, &normal);
raytrace(&temp, &refract, &refcolo, depth); ///hu, recursion
vec_scale(&refcolo, 0.9);
}
raytrace(&temp, &reflect, &col2, depth); ///reflection color
vec_scale(&col2, 0.5);
vec_scale(&col2, fres);
/// some lighting
var light = clamp(vec_dot(&n, &sun_dir), 0, 1)*0.8*diffuse;
light += pow(clamp(vec_dot(&reflect, &sun_dir), 0, 1), 30)*1.8*fres;
light*= rayshadow(&hitt);
vec_scale(color, light);
vec_add(color, &col2);
vec_add(color, &refcolo);
return;
}
}
function main()
{
fps_max = 50000;
wait(2);
// video_window(vector(0, 100, 0), vector(1024, 768,0), 1, "test");
wait(2);
video_set(1024, 768, 0, 2);
level_load("playground.wmb");
wait(3);
sun_color.red = 100;
sun_color.green = 100;
sun_color.blue = 100;
sky_color.red = 1;
sky_color.green = 0;
sky_color.blue = 0;
time_smooth = 0.99;
BMAP* ray2_bmp = bmap_createblack(1024/16, 768/16, 24);
BMAP* ray1_bmp = bmap_createblack(1024, 768, 24);
ray_bmp = ray1_bmp;
ray_pan->bmap = ray_bmp;
ray_pan->size_x =bmap_width(ray_bmp);
ray_pan->size_y =bmap_height(ray_bmp);
ray_pan->scale_x = 1024/bmap_width(ray_bmp);
ray_pan->scale_y = 768/bmap_height(ray_bmp);
wait(1);
var zoom = 0;
int dest = 0;
VECTOR temp,temp2;
camera.bmap = preview_map;
while(1)
{
int px,py;
vec_for_angle(&sun_dir, sun_angle);
// vec_inverse (&sun_dir);
bmap_fill(ray_bmp,vector(0,0,0),0);
for (px=0; px<bmap_width(ray_bmp); px++)
{
/// resolution settings
k= key_k;
if (k)
{
ray_pan->alpha = 40;
ray_bmp = ray2_bmp;
factor = 16;
ray_pan->bmap = ray_bmp;
ray_pan->size_x =bmap_width(ray_bmp);
ray_pan->size_y =bmap_height(ray_bmp);
ray_pan->scale_x = 1024/bmap_width(ray_bmp);
ray_pan->scale_y = 768/bmap_height(ray_bmp);
}else
{
ray_bmp = ray1_bmp;
factor = 1;
ray_pan->bmap = ray_bmp;
ray_pan->size_x =bmap_width(ray_bmp);
ray_pan->size_y =bmap_height(ray_bmp);
ray_pan->scale_x = 1024/bmap_width(ray_bmp);
ray_pan->scale_y = 768/bmap_height(ray_bmp);
ray_pan->alpha = 100;
}
var format = bmap_lock(ray_bmp, 0);
for (py =0; py<bmap_height(ray_bmp); py++)
{
temp.x = px*1024/bmap_width(ray_bmp);
temp.y = py*768/bmap_height(ray_bmp);
temp.z = 1;
vec_for_screen(temp, camera);
vec_diff(&temp2, &temp, camera.x);
VECTOR color;
raytrace(&temp, &temp2, &color, k*2);
color.x = clamp(color.x, 0, 255);
color.y = clamp(color.y, 0, 255);
color.z = clamp(color.z, 0, 255);
var pixel = pixel_for_vec(color, 100, format);
pixel_to_bmap(ray_bmp, px, py, pixel);
}
bmap_unlock(ray_bmp);
wait(1);
}
bmap_save(ray_bmp, "ray.png");
beep();
}
}