/*** GLOBAL DEFINES ***/ #define MAX_SOURCE_SIZE (0x100000) #define width 512 #define height 512 #define MAXDEPTH 5 #define MAXNTRIANGLE 37 #define MAXNLIGHT 4 //maxntriangle - число треугольников, с которыми будет искаться пересечение /*** 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)))); } // присылала в первом письме // simple copy from C inter intertriangle(ray ray, scene scene, __global triangle * pt, __global light * pl) { inter null = makeinterempty(); inter isect = null; bool isnull = true; for (int j = 0; j < MAXNTRIANGLE; j++) { triangle obj = pt[j]; isnull = true; 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) continue; pt_int = vplus(ray.start, vtimes(dist,ray.dir)); } isnull = isnull && !( (dotprod < 0) && ((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)) ); isect = (!isnull && (isect.isnull || dist < isect.dist))? makeinter(obj, ray, dist,vnorm(normal)): isect; } return isect; } colorin traceray(ray vray, scene scene, __global triangle * pt, __global light * pl) { inter null = makeinterempty(); colorin background = makecolorin(0, 0, 0); colorin defaultcolorin = makecolorin(0, 0, 0); colorin reflactioncolorin = makecolorin(1, 1, 1); colorin ret = background; colorin retPriv = background; inter isect = null; inter isect_tmp = isect; vec reflactionPos; vec reflectDir; for (int depth = 0; depth < MAXDEPTH + 1; vray = makeray(reflactionPos, reflectDir), depth++) { // ISect isect = scene.Things.Select(obj => obj.Intersect(vray)).Where(inter => inter != null).OrderBy(inter => inter.dist).FirstOrDefault(); isect = null; isect = intertriangle(vray, scene, pt, pl); if (isect.isnull) { reflactioncolorin = ctimes(background, reflactioncolorin); break; } //shadow vec pos = vplus(vtimes(isect.dist, isect.ray.dir), isect.ray.start); vec normal = isect.normal;//TODO: костыль?!: нормаль считается в reflactionPos, т.е. в позиции, полученной на предыдущем шаге; reflectDir = vminus(isect.ray.dir, vtimes(2 * vdot(normal, isect.ray.dir), normal)); //ret = getnaturalcolorin(isect.thing, pos, normal, reflectDir, scene, pt, pl); ret = getnaturalcolor(isect.thing.surface); for(unsigned int i = 0; i < MAXNLIGHT; i++) { vec ldis = vminus(pl[i].pos, pos); vec livec = vnorm(ldis); //testray ray lray = makeray(pos, livec); inter lisect = null; inter isect_tmp = lisect; // lisect lisect = scene.Things.Select(obj => obj.Intersect(lray)).Where(inter => inter != null).OrderBy(inter => inter.dist).FirstOrDefault(); lisect = intertriangle(lray, scene, pt, pl); float neatIsect = (lisect.isnull) ? 0 : lisect.dist; bool isInShadow = !((neatIsect > vmag(ldis)) || (neatIsect == 0)); if (!isInShadow) { float illum = vdot(livec, normal); colorin lcolorin = illum > 0 ? ctimesf(illum, pl[i].colorin) : makecolorin(0, 0, 0); float specular = vdot(livec, vnorm(reflectDir)); colorin scolorin = specular > 0 ? ctimesf(pow(specular, getroughness(isect.thing.surface)), pl[i].colorin) : makecolorin(0, 0, 0); ret = cplus(ret, cplus(ctimes(getdiffuse(pos, isect.thing.surface), lcolorin), ctimes(getspecular(pos, isect.thing.surface), scolorin))); } } ret = cplus(defaultcolorin, ret); if (depth >= MAXDEPTH) { reflactioncolorin = ctimes(cplus(ret, makecolorin(0.5, 0.5, 0.5)), reflactioncolorin); break; } reflactionPos = vplus(pos, vtimes(.001, reflectDir)); retPriv = cplus(retPriv, ctimes(ret, reflactioncolorin)); reflactioncolorin = ctimesf(getreflect(reflactionPos, isect.thing.surface), reflactioncolorin); } return cplus(retPriv, reflactioncolorin); } /* // присылала во втором письме // if MAXNTRIANGLE = 36 => two simple cube inter intertriangle(ray ray, scene scene, __global triangle * pt, __global light * pl) { inter null = makeinterempty(); inter isect = null; inter isect_tmp = isect; isect_tmp.isnull = true; isect.isnull = true; isect.dist = 0; isect_tmp.dist = 0; float dist = 0; for (int j = 0; j < MAXNTRIANGLE; j++) { triangle obj = pt[j]; //isect_tmp.isnull = true; 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); dist = 0.0f; if(dotprod < 0) { dist = -vdot(normal, vminus(ray.start,obj.v1))/vdot(normal,ray.dir); if(dist < 0) return null; pt_int = vplus(ray.start, vtimes(dist,ray.dir)); } isect_tmp.isnull = isect_tmp.isnull && !( (dotprod < 0) && ((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)) ); if (!isect_tmp.isnull) {isect_tmp.thing = pt[j]; isect_tmp.dist = dist; isect_tmp.normal = normal; isect_tmp.ray = ray;}; //if (!isect_tmp.isnull && (isect.isnull || isect_tmp.dist < isect.dist)) isect = isect_tmp; } if (!isect_tmp.isnull && (isect.isnull || isect_tmp.dist < isect.dist)) isect = isect_tmp; return isect; } colorin traceray(ray vray, scene scene, __global triangle * pt, __global light * pl) { inter null = makeinterempty(); colorin background = makecolorin(0, 0, 0); colorin defaultcolorin = makecolorin(0, 0, 0); colorin reflactioncolorin = makecolorin(1, 1, 1); colorin ret = background; colorin retPriv = background; inter isect = null; vec reflactionPos; vec reflectDir; vec ldis; vec livec; //for (int depth = 0; depth < MAXDEPTH + 1; vray = makeray(reflactionPos, reflectDir), depth++) { // intertriangle(pt[j], vray); -> isect isect = intertriangle(vray, scene, pt, pl); if (isect.isnull) { reflactioncolorin = ctimes(background, reflactioncolorin); //break; } //shadow //vec pos = vplus(vtimes(isect.dist, isect.ray.dir), isect.ray.start); //vec normal = isect.normal;//TODO: костыль?!: нормаль считается в reflactionPos, т.е. в позиции, полученной на предыдущем шаге; //reflectDir = vminus(isect.ray.dir, vtimes(2 * vdot(normal, isect.ray.dir), normal)); //getnaturalcolorin(isect.thing, pos, normal, reflectDir, scene, pt, pl); -> ret //ret = getnaturalcolorin(isect.thing, pos, normal, reflectDir, scene, pt, pl); //ret = getnaturalcolor(isect.thing.surface); //unsigned int i = 0; //ldis = vminus(pl[i].pos, pos); //livec = vnorm(ldis); //testray //ray lray = makeray(pos, livec); //inter lisect = null; //lisect = intertriangle(lray, scene, pt, pl); //float neatIsect = (lisect.isnull) ? 0 : lisect.dist; //bool isInShadow = !((neatIsect > vmag(ldis)) || (neatIsect == 0)); //if (!isInShadow) //{ // float illum = vdot(livec, normal); // colorin lcolorin = illum > 0 ? ctimesf(illum, pl[i].colorin) : makecolorin(0, 0, 0); // float specular = vdot(livec, vnorm(reflectDir)); // //colorin scolorin = specular > 0 ? ctimesf(pow(specular, getroughness(scene.thing.surface)), pl[i].colorin) : makecolorin(0, 0, 0); // //ret = cplus(ret, cplus(ctimes(getdiffuse(pos, scene.thing.surface), lcolorin), ctimes(getspecular(pos, scene.thing.surface), scolorin))); //} //ret = cplus(defaultcolorin, ret); //if (depth >= MAXDEPTH) //{ // reflactioncolorin = ctimes(cplus(ret, makecolorin(0.5, 0.5, 0.5)), reflactioncolorin); // break; //} //reflactionPos = vplus(pos, vtimes(.001, reflectDir)); //retPriv = cplus(retPriv, ctimes(ret, reflactioncolorin)); //reflactioncolorin = ctimesf(getreflect(reflactionPos, isect.thing.surface), reflactioncolorin); //if (!(isect.isnull)) return reflactioncolorin; //return cplus(retPriv, reflactioncolorin); } return cplus(retPriv, reflactioncolorin); } */ __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; }