Added Fran Moreno's Kd-Tree implementation and RGBE functions.

This commit is contained in:
2017-02-21 16:38:43 -04:00
parent 827d5dea33
commit 4e9a30d0b5
5 changed files with 566 additions and 1 deletions

View File

@@ -3,7 +3,7 @@ TARGET = ray
OBJECTS = main.o sampling.o camera.o environment.o disk.o plane.o sphere.o \
phong_brdf.o hsa_brdf.o directional_light.o point_light.o \
spot_light.o sphere_area_light.o disk_area_light.o scene.o tracer.o \
path_tracer.o whitted_tracer.o
path_tracer.o whitted_tracer.o rgbe.o kd_tree.o
DEPENDS = $(OBJECTS:.o=.d)
CXXFLAGS = -ansi -pedantic -Wall -DGLM_FORCE_RADIANS -fopenmp
LDLIBS = -lfreeimage -ljson_spirit

313
kd_tree.cpp Normal file
View File

@@ -0,0 +1,313 @@
#include "kd_tree.hpp"
#include <queue>
treeNode::treeNode(Photon p, superKey plane)
{
photon = p;
haveChilds = false;
leftChild = NULL;
rightChild = NULL;
cutPlane = plane;
}
treeNode::~treeNode()
{
haveChilds = false;
if(leftChild) delete leftChild;
if(rightChild) delete rightChild;
leftChild = NULL;
rightChild = NULL;
}
inline bool treeNode::operator==(treeNode b)
{
return photon == b.photon;
}
inline bool treeNode::operator==(Photon p)
{
return photon == p;
}
inline bool treeNode::operator>(treeNode b)
{
return photon.greater(b.photon, cutPlane);
}
inline bool treeNode::operator>(Photon p)
{
return photon.greater(p, cutPlane);
}
inline bool treeNode::operator<(treeNode b)
{
return photon.lower(b.photon, cutPlane);
}
inline bool treeNode::operator<(Photon p)
{
return photon.lower(p, cutPlane);
}
inline bool treeNode::operator>=(Vec3 p)
{
return (cutPlane == XYZ && photon.position.x >= p.x) ||
(cutPlane == YZX && photon.position.y >= p.y) ||
(cutPlane == ZXY && photon.position.z >= p.z);
}
inline bool treeNode::operator<=(Vec3 p)
{
return (cutPlane == XYZ && photon.position.x <= p.x) ||
(cutPlane == YZX && photon.position.y <= p.y) ||
(cutPlane == ZXY && photon.position.z <= p.z);
}
template <class T>
void copyArray(T a[], int size, T b[])
{
for(int i = 0; i < size; i++)
{
b[i] = a[i];
}
}
template <class T>
void restoreArray(T a, int size)
{
for(int i = 0; i < size; i++)
a[i] = i;
}
template <class T>
void Merge(T a[], int begin, int middle, int end, T b[], superKey key, std::vector<Photon> originalData)
{
int i = begin, j = middle;
for(int k = begin; k < end; k++)
{
if(i < middle && (j >= end || originalData[a[i]].lessEqual(originalData[a[j]], key)))
{
b[k] = a[i];
i++;
}
else
{
b[k] = a[j];
j++;
}
}
}
template <class T>
void SplitMerge(T b[], int begin, int end, T a[], superKey key, std::vector<Photon> originalData)
{
if(end - begin < 2)
return;
int middle = (begin + end) / 2;
SplitMerge(a, begin, middle, b, key, originalData);
SplitMerge(a, middle, end, b, key, originalData);
Merge(b, begin, middle, end, a, key, originalData);
}
template <class T>
void MegeSort(T a[], T b[], int size, superKey key, std::vector<Photon> originalData)
{
SplitMerge(b, 0, size, a, key ,originalData);
}
kdTree::kdTree(){root = NULL;}
kdTree::~kdTree(){}
void kdTree::addPhoton(Photon p)
{
Photons.push_back(p);
}
void kdTree::createNodeKdTree(treeNode** node, std::vector<Photon> originalData , int* xyz, int* yzx, int* zxy, superKey key, int begin, int end, int* xyz_2, int* yzx_2, int* zxy_2)
{
if(end - begin < 2)
{
switch(key)
{
case XYZ:
*node = new treeNode(originalData[xyz[begin]], XYZ);
//std::cout << "Photon posicion " << xyz[begin] << " " << originalData[xyz[begin]] << std::endl;
break;
case YZX:
*node = new treeNode(originalData[yzx[begin]], YZX);
//std::cout << "Photon posicion " << yzx[begin] << " " << originalData[yzx[begin]] << std::endl;
break;
case ZXY:
*node = new treeNode(originalData[zxy[begin]], ZXY);
//std::cout << "Photon posicion " << zxy[begin] << " " << originalData[zxy[begin]] << std::endl;
break;
}
return;
}
int mid = (begin + end) / 2;
switch(key)
{
case XYZ:
*node = new treeNode(originalData[xyz[mid]], XYZ);
(*node)->setChildsFlag(true);
//std::cout << "Photon posicion " << xyz[mid] << " " << originalData[xyz[mid]] << std::endl;
reorderArrays(originalData, yzx, zxy, begin, mid, end, xyz[mid], XYZ, yzx_2, zxy_2);
key = YZX;
break;
case YZX:
*node = new treeNode(originalData[yzx[mid]], YZX);
(*node)->setChildsFlag(true);
//std::cout << "Photon posicion " << yzx[mid] << " " << originalData[yzx[mid]] << std::endl;
reorderArrays(originalData, xyz, zxy, begin, mid, end, yzx[mid], YZX, xyz_2, zxy_2);
key = ZXY;
break;
case ZXY:
*node = new treeNode(originalData[zxy[mid]], ZXY);
(*node)->setChildsFlag(true);
//std::cout << "Photon posicion " << zxy[mid] << " " << originalData[zxy[mid]] << std::endl;
reorderArrays(originalData, xyz, yzx, begin, mid, end, zxy[mid], ZXY, xyz_2, yzx_2);
key = XYZ;
break;
}
//std::cout<<"Rama izquierda" << std::endl;
createNodeKdTree((*node)->getLeftChild(), originalData, xyz_2, yzx_2, zxy_2, key, begin, mid, xyz, yzx, zxy);
//std::cout<<"Rama derecha" << std::endl;
createNodeKdTree((*node)->getRightChild(), originalData, xyz_2, yzx_2, zxy_2, key, mid + 1, end, xyz, yzx, zxy);
}
void kdTree::reorderArrays(std::vector<Photon> originalData, int* A1, int* A2, int begin, int mid, int end, int orderIndex, superKey key, int* B1, int* B2)
{
int lowerindex1 = begin, higherindex1 = mid + 1, lowerindex2 = begin, higherindex2 = mid + 1;
for(int i = begin; i < end; i++)
{
if(A1[i] != orderIndex)
{
if(originalData[A1[i]].lower(originalData[orderIndex], key))
{
B1[lowerindex1] = A1[i];
lowerindex1++;
}
else
{
B1[higherindex1] = A1[i];
higherindex1++;
}
}
if(A2[i] != orderIndex)
{
if(originalData[A2[i]].lower(originalData[orderIndex], key))
{
B2[lowerindex2] = A2[i];
lowerindex2++;
}
else
{
B2[higherindex2] = A2[i];
higherindex2++;
}
}
}
}
bool kdTree::buildKdTree()
{
int size = Photons.size();
//Arreglos con las superclaves de los photones
int *xyz = new int[size];
int *yzx = new int[size];
int *zxy = new int[size];
int *xyz_aux = new int[size];
int *yzx_aux = new int[size];
int *zxy_aux = new int[size];
for(int i = 0; i < size; i++)
{
xyz[i] = i;
yzx[i] = i;
zxy[i] = i;
xyz_aux[i] = i;
}
MegeSort(xyz, xyz_aux, size, XYZ, Photons);
restoreArray(xyz_aux, size);
MegeSort(yzx, xyz_aux, size, YZX, Photons);
restoreArray(xyz_aux, size);
MegeSort(zxy, xyz_aux, size, ZXY, Photons);
for(int i = 0; i < size; i++)
{
xyz_aux[i] = xyz[i];
yzx_aux[i] = yzx[i];
zxy_aux[i] = zxy[i];
}
createNodeKdTree(&root, Photons , xyz, yzx, zxy, XYZ, 0, size, xyz_aux, yzx_aux, zxy_aux);
//printTree();
return true;
}
void kdTree::printTree(){
std::queue<treeNode*> q;
q.push(root);
while(!q.empty())
{
treeNode* n = q.front();
q.pop();
if(n)
{
std::cout << *n << " ";
if(q.empty() || !q.front() || *(q.front()->getCutPlane()) != *(n->getCutPlane()))
std::cout << std::endl;
q.push(*(n->getLeftChild()));
q.push(*(n->getRightChild()));
}
}
}
void kdTree::printNode(treeNode* node)
{
}
std::vector<Photon> kdTree::findInRange (Vec3 min, Vec3 max)
{
std::vector<Photon> photons;
findInRange(min, max, photons, root);
return photons;
}
void kdTree::findInRange (Vec3 min, Vec3 max, std::vector<Photon> &photons, treeNode *node)
{
if(node == NULL) return;
Vec3 position = node->getPhoton()->position;
if(position >= min && position <= max)
photons.push_back(*node->getPhoton());
if(*node >= min)
findInRange(min, max, photons, *node->getLeftChild());
if(*node <= max)
findInRange(min, max, photons, *node->getRightChild());
}

185
kd_tree.hpp Normal file
View File

@@ -0,0 +1,185 @@
#include <vector>
#include <limits>
#include <iostream>
#include "rgbe.hpp"
enum superKey
{
XYZ,
YZX,
ZXY
};
struct Vec3
{
float x;
float y;
float z;
Vec3() {
x = y = z = 0.0f;
}
inline bool equalFloat(const float x, const float y)
{
return (x - std::numeric_limits<float>::epsilon() <= y) && (x + std::numeric_limits<float>::epsilon() >= y);
}
inline bool operator<=(const Vec3 b)
{
return (x < b.x || (equalFloat(x, b.x) && (y < b.y || (equalFloat(y, b.y) && z <= b.z))));
}
inline bool operator>=(const Vec3 b)
{
return (x > b.x || (equalFloat(x, b.x) && (y > b.y || (equalFloat(y, b.y) && z >= b.z))));
}
inline friend std::ostream& operator<<(std::ostream& out, const Vec3& v)
{
return out << "X:" << v.x << " Y:" << v.y << " Z:" << v.z;
}
};
struct Photon
{
Vec3 position;
unsigned char radiance[4];
char phi, theta;
short unused_flag; // for 20 bytes struct.
Photon(Vec3 _p = Vec3(), float red = 0.0f, float green = 0.0f, float blue = 0.0f, char _phi = 0.0f, char _theta = 0.0f):
position(_p),
phi(_phi),
theta(_theta)
{
float2rgbe(radiance, red, green, blue);
}
inline bool equalFloat(const float x, const float y)
{
return (x - std::numeric_limits<float>::epsilon() <= y) && (x + std::numeric_limits<float>::epsilon() >= y);
}
inline bool operator==(const Photon p)
{
return equalFloat(position.x, p.position.x) && equalFloat(position.y, p.position.y) && equalFloat(position.z, p.position.z);
}
inline bool lessEqual(const Photon& b, superKey key)
{
return (key == XYZ && (position.x < b.position.x || (equalFloat(position.x, b.position.x) && (position.y < b.position.y || (equalFloat(position.y, b.position.y) && position.z <= b.position.z)))))
|| (key == YZX && (position.y < b.position.y || (equalFloat(position.y, b.position.y) && (position.z < b.position.z || (equalFloat(position.z, b.position.z) && position.x <= b.position.x)))))
|| (key == ZXY && (position.z < b.position.z || (equalFloat(position.z, b.position.z) && (position.x < b.position.x || (equalFloat(position.x, b.position.x) && position.y <= b.position.y)))));
}
inline bool lower(const Photon &b, superKey key)
{
return (key == XYZ && (position.x < b.position.x || (equalFloat(position.x, b.position.x) && (position.y < b.position.y || (equalFloat(position.y, b.position.y) && position.z < b.position.z)))))
|| (key == YZX && (position.y < b.position.y || (equalFloat(position.y, b.position.y) && (position.z < b.position.z || (equalFloat(position.z, b.position.z) && position.x < b.position.x)))))
|| (key == ZXY && (position.z < b.position.z || (equalFloat(position.z, b.position.z) && (position.x < b.position.x || (equalFloat(position.x, b.position.x) && position.y < b.position.y)))));
}
inline bool greater(const Photon &b, superKey key)
{
return (key == XYZ && (position.x > b.position.x || (equalFloat(position.x, b.position.x) && (position.y > b.position.y || (equalFloat(position.y, b.position.y) && position.z > b.position.z)))))
|| (key == YZX && (position.y > b.position.y || (equalFloat(position.y, b.position.y) && (position.z > b.position.z || (equalFloat(position.z, b.position.z) && position.x > b.position.x)))))
|| (key == ZXY && (position.z > b.position.z || (equalFloat(position.z, b.position.z) && (position.x > b.position.x || (equalFloat(position.x, b.position.x) && position.y > b.position.y)))));
}
inline friend std::ostream& operator<<(std::ostream& out, const Photon& p)
{
return out << "Position: " << p.position;
}
};
class treeNode
{
private:
Photon photon;
bool haveChilds;
superKey cutPlane;
treeNode* leftChild;
treeNode* rightChild;
public:
treeNode(Photon p, superKey plane);
~treeNode();
inline bool operator==(treeNode b);
inline bool operator>(treeNode b);
inline bool operator<(treeNode b);
inline bool operator==(Photon p);
inline bool operator>(Photon p);
inline bool operator<(Photon p);
inline bool operator>=(Vec3 p);
inline bool operator<=(Vec3 p);
inline friend std::ostream& operator<<(std::ostream& out, treeNode &t)
{
out << "Cut Plane ";
switch(*(t.getCutPlane()))
{
case XYZ:
out << "X ";
break;
case YZX:
out << "Y ";
break;
case ZXY:
out << "Z ";
break;
}
return out << "Photon " << *(t.getPhoton()) << " HaveChilds: " << *(t.getChildsFlag());
}
Photon* getPhoton(){return &photon;}
bool* getChildsFlag(){return &haveChilds;}
void setChildsFlag(bool childs){haveChilds = childs;}
superKey* getCutPlane(){return &cutPlane;}
treeNode** getLeftChild(){return &leftChild;}
treeNode** getRightChild(){return &rightChild;}
};
//Clase que genera el kdTree
class kdTree
{
public:
kdTree();
~kdTree();
void addPhoton(Photon p);
bool buildKdTree();
void printTree();
std::vector<Photon> findInRange (Vec3 min, Vec3 max);
private:
treeNode* root;
std::vector<Photon> Photons;
void createNodeKdTree(treeNode** node,
std::vector<Photon> originalData ,
int* xyz,
int* yzx,
int* zxy,
superKey key,
int begin,
int end,
int* xyz_2,
int* yzx_2,
int* zxy_2);
void reorderArrays(std::vector<Photon> originalData,
int* A1,
int* A2,
int begin,
int mid,
int end,
int orderIndex,
superKey Key,
int* B1,
int* B2);
void printNode(treeNode* node);
void findInRange (Vec3 min, Vec3 max, std::vector<Photon> &photons, treeNode *node);
};

40
rgbe.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include <cmath>
#include "rgbe.hpp"
/* standard conversion from float pixels to rgbe pixels */
/* note: you can remove the "inline"s if your compiler complains about it */
void float2rgbe(unsigned char rgbe[4], float red, float green, float blue) {
float v;
int e;
v = red;
if (green > v) v = green;
if (blue > v) v = blue;
if (v < 1e-32) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
}
else {
v = frexp(v,&e) * 256.0/v;
rgbe[0] = (unsigned char) (red * v);
rgbe[1] = (unsigned char) (green * v);
rgbe[2] = (unsigned char) (blue * v);
rgbe[3] = (unsigned char) (e + 128);
}
}
/* standard conversion from rgbe to float pixels */
/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */
/* in the range [0,1] to map back into the range [0,1]. */
void rgbe2float(float & red, float & green, float & blue, unsigned char rgbe[4]) {
float f;
if (rgbe[3]) { /*nonzero pixel*/
f = ldexp(1.0,rgbe[3]-(int)(128+8));
red = rgbe[0] * f;
green = rgbe[1] * f;
blue = rgbe[2] * f;
}
else
red = green = blue = 0.0;
}

27
rgbe.hpp Normal file
View File

@@ -0,0 +1,27 @@
/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
* WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
* IT IS STRICTLY USE AT YOUR OWN RISK. */
/* This file contains code to read and write four byte rgbe file format
developed by Greg Ward. It handles the conversions between rgbe and
pixels consisting of floats. The data is assumed to be an array of floats.
By default there are three floats per pixel in the order red, green, blue.
(RGBE_DATA_??? values control this.) Only the mimimal header reading and
writing is implemented. Each routine does error checking and will return
a status value as defined below. This code is intended as a skeleton so
feel free to modify it to suit your needs.
(Place notice here if you modified the code.)
posted to http://www.graphics.cornell.edu/~bjw/
written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95
based on code written by Greg Ward
*/
#pragma once
#ifndef RGBE_HPP
#define RGBE_HPP
extern void float2rgbe(unsigned char rgbe[4], float red, float green, float blue);
extern void rgbe2float(float & red, float & green, float & blue, unsigned char rgbe[4]);
#endif