/* REMEMBER: * все глобальные массивы, при передачи в функции должны быть маркированы сдужеюным словом __global * все привести явно к float * никаких рекурсий * если серый экран(=ошбика) с булевскими и кажется уже все потеряно, значит MAXNTRIANGLE некорректно приходит(=нельзя использовать его) */ /*** GLOBAL DEFINES ***/ #define MAX_SOURCE_SIZE (0x100000) #define width 512 #define height 512 #define MAXDEPTH 5 #define MAXNTRIANGLE 36 #define MAXNLIGHT 4 /*** STRUCTS ***/ // BMP typedef struct BMP { int screenwidth; int screenheight; unsigned char* image_bytes; } BMP; // vector typedef struct vec { float x, y, z; } vec; vec makevec(float x, float y, float z) { vec vec; vec.x = (float)x; vec.y = (float)y; vec.z = (float)z; return vec; } vec vtimes(float n, vec v) { return makevec(v.x * n, v.y * n, v.z * n); } vec vminus(vec v1, vec v2) { return makevec(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); } vec vplus(vec v1, vec v2) { return makevec(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); } float vdot(vec v1, vec v2) { return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z); } float vsquare(vec v) { return vdot(v, v); } float vdet(vec v1, vec v2, vec v3) { return (v1.x*v2.y*v3.z + v2.x*v3.y*v1.z + v1.y*v2.z*v3.x) - (v1.z*v2.y*v3.x + v1.y*v2.x*v3.z + v2.z*v3.y*v1.x); } float vmag(vec v) { return sqrt(vdot(v, v)); } vec vnorm(vec v) { float m = vmag(v); float div = m == 0 ? -log(0.0f) : 1 / m; return vtimes(div, v); } vec vcross(vec v1, vec v2) { return makevec(((v1.y * v2.z) - (v1.z * v2.y)), ((v1.z * v2.x) - (v1.x * v2.z)), ((v1.x * v2.y) - (v1.y * v2.x))); } bool vequals(vec v1, vec v2) { return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); } // ray typedef struct ray { vec start, dir;} ray; ray makeray(vec start, vec dir) { ray ray; ray.start = start; ray.dir = dir; return ray;}; // color typedef struct color {unsigned char r; unsigned char g; unsigned char b; } color; color makecolor(unsigned char r, unsigned char g, unsigned char b) {color c; c.r = r; c.g = g; c.b = b; return c;}; // colorinternal typedef struct colorin { float r, g, b;} colorin; colorin makecolorin(float r, float g, float b) { colorin c; c.r = r; c.g = g; c.b = b; return c; } colorin ctimesf(float n, colorin v) { return makecolorin(n * v.r, n * v.g, n * v.b); } colorin ctimes(colorin v1, colorin v2) { return makecolorin(v1.r * v2.r, v1.g * v2.g, v1.b * v2.b); } colorin cplus(colorin v1, colorin v2) { return makecolorin(v1.r + v2.r, v1.g + v2.g, v1.b + v2.b); } colorin cminus(colorin v1, colorin v2) { return makecolorin(v1.r - v2.r, v1.g - v2.g, v1.b - v2.b); } float legalize(float d) { return d > 1 ? 1 : d; } color todrawingcolor(colorin c) { return makecolor((unsigned char )(legalize(c.r) * 255), (unsigned char )(legalize(c.g) * 255), (unsigned char )(legalize(c.b) * 255)); } // triangle typedef struct triangle { vec v1, v2, v3; unsigned int surface;} triangle; triangle maketriangle(vec v1, vec v2, vec v3, unsigned int surface) { triangle t; t.v1 = v1; t.v2 = v2; t.v3 = v3; t.surface = surface; return t; } // inter typedef struct inter { bool isnull; triangle thing; ray ray; float dist; vec normal; } inter; inter makeinter(triangle thing, ray ray, float dist, vec normal ) { inter inter; inter.isnull = false; inter.thing = thing; inter.ray = ray; inter.dist = dist; inter.normal = normal; return inter;} inter makeinterempty() { inter inter; inter.isnull = true; inter.dist = 0.0f; return inter;} // light typedef struct light { vec pos; colorin colorin; } light; light makelight(vec pos, colorin colorin) { light l; l.colorin = colorin; l.pos = pos; return l; }; // camera typedef struct camera { vec pos; vec forward; vec up; vec right; } camera; camera makecamera(vec pos, vec lookat) { vec forward = vnorm(vminus(lookat, pos)); vec down = makevec(0.0f, -1.0f, 0.0f); vec right = vtimes(1.5f, vnorm(vcross(forward, down))); vec up = vtimes(1.5f, vnorm(vcross(forward, vminus(makevec(0.0f,0.0f,0.0f),right)))); camera c; c.pos = pos; c.forward = forward; c.up = up; c.right = right; return c; }; // scene typedef struct scene { camera camera; int screenwidth, screenheight; triangle* ptriangle; unsigned int nthings; light* plight; unsigned int nlights; int maxdepth;} scene; scene makescene( camera camera, int screenwidth, int screenheight, triangle* ptriangle, unsigned int nthings, light* plight, unsigned int nlights, int maxdepth) { scene s; s.camera = camera; s.screenheight = screenheight; s.screenwidth = screenwidth; s.ptriangle = ptriangle; s.nthings = nthings; s.plight = plight; s.nlights = nlights; s.maxdepth = maxdepth; return s; } /*** SURFACE FUNCTIONS ***/ //диффузность(diffuse) colorin getdiffuse(vec pos, unsigned int surface) { switch (surface) { /*"checkerboard"*/ case 1: return (int)(floor((float)pos.z) + floor((float)pos.x)) % 2 != 0? makecolorin(1, 1, 1): makecolorin(0, 0, 0); /*"shiny"*/ case 2: return makecolorin(1, 1, 1); /*"battery"*/ case 3: return makecolorin(1, 1, 1); /*"shell"*/ case 4: return makecolorin(1, 1, 1); } return makecolorin(0,0,0); }; //зеркальность(specular) colorin getspecular(vec pos, unsigned int surface) { switch (surface) { /*"checkerboard"*/ case 1: return makecolorin(1, 1, 1); /*"shiny"*/ case 2: return makecolorin(.5, .5, .5); /*"battery"*/ case 3: return makecolorin(0, 0, 0); /*"shell"*/ case 4: return makecolorin(.5, .5, .5); } return makecolorin(0,0,0); }; //отражение(reflect) float getreflect(vec pos, unsigned int surface) { switch (surface) { /*"checkerboard"*/ case 1: return (int)(floor((float)pos.z) + floor((float)pos.x)) % 2 != 0? .1: .7; /*"shiny"*/ case 2: return .6; /*"battery"*/ case 3: return 0; /*"shell"*/ case 4: return 0.6; } return 0; }; //шороховатость(roughness) float getroughness(unsigned int surface) { switch (surface) { /*"checkerboard"*/ case 1: return 150; /*"shiny"*/ case 2: return 50; /*"battery"*/ case 3: return 50; /*"shell"*/ case 4: return 50; } return 50; }; //naturalcolor colorin getnaturalcolor(unsigned int surface) { switch (surface) { /*"checkerboard"*/ case 1: return makecolorin(0,0,0); /*"shiny"*/ case 2: return makecolorin(0,0,0); /*"battery"*/ case 3: return makecolorin(0,1,0); /*"shell"*/ case 4: return makecolorin(0,0,1); } return makecolorin(0,0,0); }; /*** RAY TRACING ***/ float recenterx(scene scene, float x) { return (x - (scene.screenwidth / 2.0)) / (2.0 * scene.screenwidth); } float recentery(scene scene, float y) { return -(y - (scene.screenheight / 2.0)) / (2.0 * scene.screenheight); } vec getpointcamera(scene scene, camera camera, float x, float y) { return vnorm(vplus(camera.forward, vplus(vtimes(recenterx(scene, x), camera.right), vtimes(recentery(scene, y), camera.up)))); } colorin traceray(ray ray, scene scene, __global triangle * pt, __global light * pl) { colorin background = makecolorin(0, 0, 0); colorin defaultcolorin = makecolorin(0, 1, 0); bool isnull = true; inter i; i.isnull = true; for (int j = 0; j < MAXNTRIANGLE; j++) { triangle obj = pt[j]; vec E1 = vminus(obj.v2,obj.v1); vec E2 = vminus(obj.v3,obj.v1); vec pt_int = makevec(0,0,0); vec normal = vcross(E1,E2); float dotprod = vdot(normal,ray.dir); float dist = 0.0f; if(dotprod < 0) { dist = -vdot(normal, vminus(ray.start,obj.v1))/vdot(normal,ray.dir); if(dist < 0) return background; pt_int = vplus(ray.start, vtimes(dist,ray.dir)); if ((vdot(vcross(vminus(obj.v2,obj.v1), vminus(pt_int,obj.v1)), normal) >= 0) && (vdot(vcross(vminus(obj.v3,obj.v2), vminus(pt_int,obj.v2)), normal) >= 0) && (vdot(vcross(vminus(obj.v1,obj.v3), vminus(pt_int,obj.v3)), normal) >= 0)) {isnull = false; i.isnull = false; } //i.isnull = isnull; if (!(i.isnull)) return defaultcolorin; } } i.isnull = isnull; if (!(i.isnull)) return defaultcolorin; return background; } __kernel void dataParallel(__global BMP* _scene, __global unsigned char* image_bytes, __global scene* scene, __global triangle * ptriangle, __global light * plight) { int w = get_global_id(0); int h = get_global_id(1); int row_increment = (*_scene).screenwidth * 3; ray ray = makeray((*scene).camera.pos, getpointcamera(*scene, (*scene).camera, (float)w, (float)h)); colorin colorin = traceray(ray, *scene, ptriangle, plight); color color = todrawingcolor(colorin); image_bytes[(h * row_increment) + (w * 3 + 0)] = color.r; image_bytes[(h * row_increment) + (w * 3 + 1)] = color.g; image_bytes[(h * row_increment) + (w * 3 + 2)] = color.b; }