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)
--- 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
--- 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
--- 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
--- /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
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+
+#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);
+}
--- /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
--- /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);
+}
--- /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 <float.h>
+
+#define Eps 1e-6
+#define Inf FLT_MAX
+
+#endif
--- 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<SortableShape>
{
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=";
--- 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);
};
--- 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<KdTree*>(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));
--- 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<float>();
- 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};
--- 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 */