# HG changeset patch # User Radek Brich # Date 1196009909 -3600 # Node ID a0a3e334744f5152c329e528ceef78b8adb62806 # Parent fc18ac4833f275f9115b41b5e7798fb0a5c70c0a C++ demos: prepare infrastructure, add spheres_shadow.cc rename Ray::a to Ray::o KdNode::shapes changed to pointer and added to union together with *children (to save memory) diff -r fc18ac4833f2 -r a0a3e334744f .bzrignore --- a/.bzrignore Sun Nov 25 15:50:01 2007 +0100 +++ b/.bzrignore Sun Nov 25 17:58:29 2007 +0100 @@ -1,2 +1,4 @@ demos/*.png +ccdemos/*.png demos/kdtree.obj +demos/*.ply diff -r fc18ac4833f2 -r a0a3e334744f Makefile --- a/Makefile Sun Nov 25 15:50:01 2007 +0100 +++ b/Makefile Sun Nov 25 17:58:29 2007 +0100 @@ -1,4 +1,4 @@ -CCFLAGS=-I./src -Wall -Wno-write-strings -O3 -fno-strict-aliasing -DPTHREADS +CCFLAGS=-I./src -Wall -Wno-write-strings -g -O3 -fno-strict-aliasing -DPTHREADS LDFLAGS= ifeq ($(OS), Windows_NT) @@ -46,7 +46,7 @@ matrix.o: src/matrix.cc src/matrix.h src/vector.h noise.o: src/noise.cc src/noise.h scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h src/common.h -kdtree.o: src/kdtree.cc src/kdtree.h +kdtree.o: src/kdtree.cc src/kdtree.h src/scene.h raytracer.o: src/raytracer.cc src/raytracer.h src/scene.h src/vector.h src/noise.h # python module diff -r fc18ac4833f2 -r a0a3e334744f TODO --- a/TODO Sun Nov 25 15:50:01 2007 +0100 +++ b/TODO Sun Nov 25 17:58:29 2007 +0100 @@ -3,9 +3,6 @@ - optimize construction: do not use bounding boxes of shapes, instead implement box-shape intersection * transforms, camera * update Python binding, new classes - * rename: - - Ray.a -> Ray.o or Ray.origin - * C++ demos * more complex demos diff -r fc18ac4833f2 -r a0a3e334744f ccdemos/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ccdemos/Makefile Sun Nov 25 17:58:29 2007 +0100 @@ -0,0 +1,22 @@ +CCFLAGS=-g -I../src +LDFLAGS=-L.. -lpng `python-config --libs` +objs=image.o ../*.o + +all: image.o spheres_shadow + +%.o: %.c + $(CXX) -c -o $@ $*.c + +%.o: %.cc + $(CXX) -c -o $@ $*.cc $(CCFLAGS) + +%: %.o + (cd .. && make) + $(CXX) -o $@ $(objs) $*.o $(LDFLAGS) + +image.o: image.c +spheres_shadow.o: spheres_shadow.cc +spheres_shadow: spheres_shadow.o + +clean: + rm -f spheres_shadow *.o diff -r fc18ac4833f2 -r a0a3e334744f ccdemos/image.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ccdemos/image.c Sun Nov 25 17:58:29 2007 +0100 @@ -0,0 +1,114 @@ +/* This code is part of RGB Image Library + see URL: xxx */ + +/************************************************************************** + +RGB Image Library (rgbimagelib) +File: image.c + +Copyright (c) 2006 Radek Brich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include +#include +#include + +#include "image.h" + +int new_image(struct image **img, int width, int height, int pixelsize) +{ + *img = (struct image *) malloc(sizeof(struct image)); + (*img)->pixel_size = pixelsize; + (*img)->width = width; + (*img)->height = height; + (*img)->data = (char *) malloc(width * height * pixelsize); + return(0); +} + +int destroy_image(struct image **img) +{ + free((*img)->data); + free(*img); + *img = NULL; +} + +/* funkce pro ulozeni obrazku do PNG souboru (vyuziva knihovnu libpng) */ +int save_png(const char *fname, struct image *img) +{ + int y; /* pomocna promenna pro pruchod radku obrazu */ + FILE *f; + png_structp png; /* PNG data */ + png_infop pnginfo; /* PNG info */ + char *data; + + if ((f = fopen(fname, "wb")) == NULL) + return (0); + + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + fclose(f); + return (0); + } + + pnginfo = png_create_info_struct(png); + if (!pnginfo) { + fclose(f); + png_destroy_write_struct(&png, 0); + return (0); + } + + if (setjmp(png_jmpbuf(png))) { + fclose(f); + png_destroy_write_struct(&png, &pnginfo); + return (0); + } + + /* predat knihovne PNG ukazatel na soubor */ + png_init_io(png, f); + + /* parametry PNG */ + png_set_compression_level(png, Z_BEST_COMPRESSION); + png_set_IHDR(png, pnginfo, img->width, img->height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_set_sRGB(png, pnginfo, PNG_sRGB_INTENT_PERCEPTUAL); + png_set_sRGB_gAMA_and_cHRM(png, pnginfo, PNG_INFO_sRGB); + + /* zapsat hlavicku */ + png_write_info(png, pnginfo); + + /* zapsat data */ + data = img->data; + for (y = 0; y < img->height; y++, data += img->width * img->pixel_size) + png_write_row(png, (png_byte *) data); + + /* ukoncit soubor a uvolnit pomocne struktury */ + png_write_end(png, pnginfo); + png_destroy_write_struct(&png, 0); + + fclose(f); + + return (1); +} diff -r fc18ac4833f2 -r a0a3e334744f ccdemos/image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ccdemos/image.h Sun Nov 25 17:58:29 2007 +0100 @@ -0,0 +1,20 @@ +#ifndef IMAGE_H +#define IMAGE_H + +#define IMG_GRAYSCALE 1 +#define IMG_RGB 3 + +/* raw image */ +struct image { + int pixel_size; /* should be 1 for grayscale and 3 for RGB*/ + int width; + int height; + char *data; +}; + +int new_image(struct image **img, int width, int height, int pixelsize); +int destroy_image(struct image **img); + +int save_png(const char *fname, struct image *img); + +#endif diff -r fc18ac4833f2 -r a0a3e334744f ccdemos/spheres_shadow.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ccdemos/spheres_shadow.cc Sun Nov 25 17:58:29 2007 +0100 @@ -0,0 +1,47 @@ +#include "raytracer.h" +#include "image.h" + +int main() +{ + Raytracer rt; + Light light1(Vector3(0.0, 5.0, 5.0), Colour(0.7, 0.3, 0.6)); + rt.addlight(&light1); + + Light light2(Vector3(-2.0, 10.0, 2.0), Colour(0.4, 0.6, 0.3)); + rt.addlight(&light2); + + Material mat0(Colour(0.7, 0.7, 0.7)); + + Box box(Vector3(-20.0, -1.2, -20.0), Vector3(20.0, -1.0, 20.0), &mat0); + rt.addshape(&box); + + Material mat1(Colour(1.0, 0.0, 0.0)); + Sphere bigsphere(Vector3(3.0, 2.0, 7.0), 3.0, &mat1); + rt.addshape(&bigsphere); + + Material mat2(Colour(0.0, 1.0, 0.0)); + Sphere smallsphere(Vector3(-5.5, 1.5, 8.0), 2.0, &mat2); + rt.addshape(&smallsphere); + + Material mat3(Colour(0.0, 0.0, 1.0)); + Sphere tinysphere(Vector3(-1.2, 0.0, 2.0), 0.5, &mat3); + rt.addshape(&tinysphere); + + int w = 800; + int h = 600; + float *fdata = rt.render(w, h); + + struct image *img; + new_image(&img, w, h, 3); + + float *fd = fdata; + for (char *cd = img->data; cd != img->data + w*h*3; cd++, fd++) { + if (*fd > 1.0) + *cd = 255; + else + *cd = (unsigned char)(*fd * 255.0); + } + free(fdata); + save_png("spheres_shadow.png", img); + destroy_image(&img); +} diff -r fc18ac4833f2 -r a0a3e334744f src/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/common.h Sun Nov 25 17:58:29 2007 +0100 @@ -0,0 +1,9 @@ +#ifndef COMMON_H +#define COMMON_H + +#include + +#define Eps 1e-6 +#define Inf FLT_MAX + +#endif diff -r fc18ac4833f2 -r a0a3e334744f src/kdtree.cc --- a/src/kdtree.cc Sun Nov 25 15:50:01 2007 +0100 +++ b/src/kdtree.cc Sun Nov 25 17:58:29 2007 +0100 @@ -23,10 +23,10 @@ class SortableShapeList: public vector { public: - SortableShapeList(ShapeList &shapes, short axis) + SortableShapeList(ShapeList *shapes, short axis) { ShapeList::iterator shape; - for (shape = shapes.begin(); shape != shapes.end(); shape++) + for (shape = shapes->begin(); shape != shapes->end(); shape++) push_back(SortableShape(*shape, axis)); }; }; @@ -89,9 +89,9 @@ void KdNode::subdivide(BBox bbox, int depth) { - if (depth >= 20 || shapes.size() <= 4) + if (depth >= 20 || shapes->size() <= 4) { - leaf = true; + setLeaf(); return; } @@ -173,9 +173,9 @@ // choose best split pos const float K = 1.4; // constant, K = cost of traversal / cost of ray-triangle intersection float SAV = 2*(bbox.w()*bbox.h() + bbox.w()*bbox.d() + bbox.h()*bbox.d()); // surface area of node - float cost = SAV * (K + shapes.size()); // initial cost = non-split cost + float cost = SAV * (K + shapes->size()); // initial cost = non-split cost SplitPos *splitpos = NULL; - leaf = true; + bool leaf = true; BBox lbb = bbox; BBox rbb = bbox; for (spl = splitlist.begin(); spl != splitlist.end(); spl++) @@ -196,9 +196,12 @@ } if (leaf) + { + setLeaf(); return; + } -#if 1 +#if 0 // export kd-tree as .obj for visualization // this would be hard to reconstruct later static ofstream F("kdtree.obj"); @@ -289,7 +292,7 @@ void KdTree::build() { root = new KdNode(); - root->shapes = shapes; + root->shapes = &shapes; root->subdivide(bbox, 0); built = true; } @@ -320,14 +323,14 @@ /* distinguish between internal and external origin */ if (a >= 0.0) /* a ray with external origin */ - enPt->pb = ray.a + ray.dir * a; + enPt->pb = ray.o + ray.dir * a; else /* a ray with internal origin */ - enPt->pb = ray.a; + enPt->pb = ray.o; /* setup initial exit point in the stack */ StackElem *exPt = new StackElem(); exPt->t = b; - exPt->pb = ray.a + ray.dir * b; + exPt->pb = ray.o + ray.dir * b; exPt->node = NULL; /* set termination flag */ st.push(enPt); @@ -374,7 +377,7 @@ /* case P4 or N4 . . . traverse both children */ /* signed distance to the splitting plane */ - t = (splitVal - ray.a.cell[axis]) / ray.dir.cell[axis]; + t = (splitVal - ray.o.cell[axis]) / ray.dir.cell[axis]; /* setup the new exit point */ st.push(exPt); @@ -384,8 +387,8 @@ exPt->t = t; exPt->node = farchild; exPt->pb[axis] = splitVal; - exPt->pb[(axis+1)%3] = ray.a.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3]; - exPt->pb[(axis+2)%3] = ray.a.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3]; + exPt->pb[(axis+1)%3] = ray.o.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3]; + exPt->pb[(axis+2)%3] = ray.o.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3]; } /* while */ /* current node is the leaf . . . empty or full */ @@ -394,7 +397,7 @@ Shape *nearest_shape = NULL; float dist = exPt->t; ShapeList::iterator shape; - for (shape = node->shapes.begin(); shape != node->shapes.end(); shape++) + for (shape = node->shapes->begin(); shape != node->shapes->end(); shape++) if (*shape != origin_shape && (*shape)->intersect(ray, dist) && dist >= enPt->t) nearest_shape = *shape; @@ -431,7 +434,7 @@ if (node == NULL) node = root; if (node->isLeaf()) - str << "(leaf: " << node->shapes.size() << " shapes)"; + str << "(leaf: " << node->shapes->size() << " shapes)"; else { str << "(split " << (char)('x'+node->getAxis()) << " at " << node->getSplit() << "; L="; diff -r fc18ac4833f2 -r a0a3e334744f src/kdtree.h --- a/src/kdtree.h Sun Nov 25 15:50:01 2007 +0100 +++ b/src/kdtree.h Sun Nov 25 17:58:29 2007 +0100 @@ -31,13 +31,14 @@ class KdNode { float split; - bool leaf; /* is this node a leaf? */ - short axis; /* 0,1,2 => x,y,z */ - KdNode *children; + short axis; /* 0,1,2 => x,y,z; 3 => leaf */ public: - ShapeList shapes; + union { + KdNode *children; + ShapeList *shapes; + }; - KdNode() : leaf(true), axis(0), shapes() {}; + KdNode() : axis(3) { shapes = new ShapeList(); }; void setAxis(short aAxis) { axis = aAxis; }; short getAxis() { return axis; }; @@ -45,13 +46,13 @@ void setSplit(float aSplit) { split = aSplit; }; float getSplit() { return split; }; - void setLeaf(bool aLeaf) { leaf = aLeaf; }; - bool isLeaf() { return leaf; }; + void setLeaf() { axis = 3; }; + bool isLeaf() { return axis == 3; }; KdNode *getLeftChild() { return children; }; KdNode *getRightChild() { return children+1; }; - void addShape(Shape* aShape) { shapes.push_back(aShape); }; + void addShape(Shape* aShape) { shapes->push_back(aShape); }; void subdivide(BBox bbox, int depth); }; diff -r fc18ac4833f2 -r a0a3e334744f src/raytracer.cc --- a/src/raytracer.cc Sun Nov 25 15:50:01 2007 +0100 +++ b/src/raytracer.cc Sun Nov 25 17:58:29 2007 +0100 @@ -99,7 +99,7 @@ return bg_colour; } else { Colour acc = Colour(); - Vector3 P = ray.a + ray.dir * nearest_distance; // point of intersection + Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection Vector3 normal = nearest_shape->normal(P); acc = PhongShader_ambient(*nearest_shape->material, P); @@ -211,17 +211,13 @@ RenderrowData *d; printf("* building kd-tree\n"); - //cout << endl; top->optimize(); - //static_cast(top)->save(cout); - //cout << endl; //srand(time(NULL)); - // eye - viewing point + /* eye - viewing point */ Vector3 eye(0, 0, -5); - // for each pixel... vy = starty; #ifdef PTHREADS @@ -233,6 +229,7 @@ int t = 0; #endif + /* for each pixel... */ printf("* rendering row 0 ( 0%% done)"); for (int y = 0; y < h; y++) { d = (RenderrowData*) malloc(sizeof(RenderrowData)); diff -r fc18ac4833f2 -r a0a3e334744f src/scene.cc --- a/src/scene.cc Sun Nov 25 15:50:01 2007 +0100 +++ b/src/scene.cc Sun Nov 25 17:58:29 2007 +0100 @@ -21,13 +21,13 @@ { if (ray.dir.cell[i] == 0) { /* ray is parallel to these planes */ - if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > H.cell[i]) + if (ray.o.cell[i] < L.cell[i] || ray.o.cell[i] > H.cell[i]) return false; } else { /* compute the intersection distance of the planes */ - t1 = (L.cell[i] - ray.a.cell[i]) / ray.dir.cell[i]; - t2 = (H.cell[i] - ray.a.cell[i]) / ray.dir.cell[i]; + t1 = (L.cell[i] - ray.o.cell[i]) / ray.dir.cell[i]; + t2 = (H.cell[i] - ray.o.cell[i]) / ray.dir.cell[i]; if (t1 > t2) swap(t1, t2); @@ -50,7 +50,7 @@ bool Sphere::intersect(const Ray &ray, float &dist) { - Vector3 V = ((Ray)ray).a - center; + Vector3 V = ((Ray)ray).o - center; float Vd = - dot(V, ray.dir); float Det = Vd * Vd - (dot(V,V) - sqr_radius); @@ -81,7 +81,7 @@ { //allts = new vector(); - Vector3 V = ((Ray)ray).a - center; + Vector3 V = ((Ray)ray).o - center; float Vd = - dot(V, ray.dir); float Det = Vd * Vd - (dot(V,V) - sqr_radius); @@ -115,11 +115,7 @@ { BBox bbox = BBox(); bbox.L = center - radius; - //bbox.L.y = center.y - radius; - //bbox.L.z = center.z - radius; bbox.H = center + radius; - //bbox.H.y = center.y + radius; - //bbox.H.z = center.z + radius; return bbox; } @@ -131,8 +127,8 @@ Vector3 Box::normal(Vector3 &P) { - Vector3 N(0,1,0); - /*for (int i = 0; i < 3; i++) + Vector3 N; + for (int i = 0; i < 3; i++) { if (P.cell[i] >= L.cell[i]-Eps && P.cell[i] <= L.cell[i]+Eps) //if (P.cell[i] == L.cell[i]) @@ -146,7 +142,7 @@ N.cell[i] = +1.0; break; } - }*/ + } return N; } @@ -201,7 +197,7 @@ // see comment for previous method bool Triangle::intersect(const Ray &ray, float &dist) { - Vector3 O = ray.a; + Vector3 O = ray.o; Vector3 D = ray.dir; const int modulo3[5] = {0,1,2,0,1}; diff -r fc18ac4833f2 -r a0a3e334744f src/scene.h --- a/src/scene.h Sun Nov 25 15:50:01 2007 +0100 +++ b/src/scene.h Sun Nov 25 17:58:29 2007 +0100 @@ -19,9 +19,9 @@ class Ray { public: - Vector3 a, dir; - Ray(const Vector3 &aa, const Vector3 &adir): - a(aa), dir(adir) {}; + Vector3 o, dir; + Ray(const Vector3 &ao, const Vector3 &adir): + o(ao), dir(adir) {}; }; /* axis-aligned bounding box */