*Added initial code of rayobject_rtbuild

An helper class to build trees
This commit is contained in:
2009-06-30 22:07:42 +00:00
parent 021e0cc53f
commit 1deba75110
5 changed files with 332 additions and 21 deletions
+7 -2
View File
@@ -47,7 +47,7 @@ void RE_rayobject_free(RayObject *r);
/* RayObject constructors */
RayObject* RE_rayobject_octree_create(int ocres, int size);
RayObject* RE_rayobject_bvh_create(int size);
RayObject* RE_rayobject_blibvh_create(int size);
RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob);
//RayObject* RayObject_derivedmesh_create(struct DerivedMesh*, void *ob);
@@ -59,8 +59,13 @@ struct Isect
float start[3];
float vec[3];
float labda;
/* length of vec, configured by RE_rayobject_raycast */
int bv_index[6];
float idot_axis[3];
float dist;
float dist; /* length of vec, configured by RE_rayobject_raycast */
/* float end[3]; - not used */
float u, v;
@@ -0,0 +1,84 @@
/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef RE_RAYOBJECT_RTBUILD_H
#define RE_RAYOBJECT_RTBUILD_H
#include "rayobject.h"
/*
* Ray Tree Builder
* this structs helps building any type of tree
* it contains several methods to organiza/split nodes
* allowing to create a given tree on the fly.
*
* Idea is that other trees BVH, BIH can use this code to
* generate with simple calls, and then convert to the theirs
* specific structure on the fly.
*/
#define MAX_CHILDS 32
typedef struct RTBuilder
{
/* list to all primitives in this tree */
RayObject **begin, **end;
/* axis used (if any) on the split method */
int split_axis;
/* links to child partitions calculated during splitting */
RayObject **child[MAX_CHILDS+1];
} RTBuilder;
/* used during creation */
RTBuilder* rtbuild_create(int size);
void rtbuild_free(RTBuilder *b);
void rtbuild_add(RTBuilder *b, RayObject *o);
int rtbuild_size(RTBuilder *b);
/* used during tree reorganization */
RTBuilder* rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp);
void rtbuild_mean_split(RTBuilder *b, int nchilds, int axis);
void rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds);
/*
static BVHNode *bvh_rearrange(BVHTree *tree, RTBuilder *b)
{
int i;
int nc = rtbuild_mean_split_largest_axis(b, BVH_NCHILDS);
RTBuilder tmp;
BVHNode *bvh = tree->next_node++;
bvh->split_axis = tmp->split_axis;
for(i=0; i<nc; i++)
bvh->child[i] = bvh_rearrange( rtbuild_get_child(b, i, &tmp) );
}
*/
#endif
@@ -36,19 +36,19 @@
#include "render_types.h"
#include "rayobject.h"
static int RayObject_bvh_intersect(RayObject *o, Isect *isec);
static void RayObject_bvh_add(RayObject *o, RayObject *ob);
static void RayObject_bvh_done(RayObject *o);
static void RayObject_bvh_free(RayObject *o);
static void RayObject_bvh_bb(RayObject *o, float *min, float *max);
static int RayObject_blibvh_intersect(RayObject *o, Isect *isec);
static void RayObject_blibvh_add(RayObject *o, RayObject *ob);
static void RayObject_blibvh_done(RayObject *o);
static void RayObject_blibvh_free(RayObject *o);
static void RayObject_blibvh_bb(RayObject *o, float *min, float *max);
static RayObjectAPI bvh_api =
{
RayObject_bvh_intersect,
RayObject_bvh_add,
RayObject_bvh_done,
RayObject_bvh_free,
RayObject_bvh_bb
RayObject_blibvh_intersect,
RayObject_blibvh_add,
RayObject_blibvh_done,
RayObject_blibvh_free,
RayObject_blibvh_bb
};
typedef struct BVHObject
@@ -60,7 +60,7 @@ typedef struct BVHObject
} BVHObject;
RayObject *RE_rayobject_bvh_create(int size)
RayObject *RE_rayobject_blibvh_create(int size)
{
BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject");
assert( RayObject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
@@ -88,7 +88,7 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTr
}
}
static int RayObject_bvh_intersect(RayObject *o, Isect *isec)
static int RayObject_blibvh_intersect(RayObject *o, Isect *isec)
{
BVHObject *obj = (BVHObject*)o;
BVHTreeRayHit hit;
@@ -103,7 +103,7 @@ static int RayObject_bvh_intersect(RayObject *o, Isect *isec)
return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, isec);
}
static void RayObject_bvh_add(RayObject *o, RayObject *ob)
static void RayObject_blibvh_add(RayObject *o, RayObject *ob)
{
BVHObject *obj = (BVHObject*)o;
float min_max[6];
@@ -116,13 +116,13 @@ static void RayObject_bvh_add(RayObject *o, RayObject *ob)
BLI_bvhtree_insert(obj->bvh, (int)ob, min_max, 2 );
}
static void RayObject_bvh_done(RayObject *o)
static void RayObject_blibvh_done(RayObject *o)
{
BVHObject *obj = (BVHObject*)o;
BLI_bvhtree_balance(obj->bvh);
}
static void RayObject_bvh_free(RayObject *o)
static void RayObject_blibvh_free(RayObject *o)
{
BVHObject *obj = (BVHObject*)o;
@@ -132,7 +132,7 @@ static void RayObject_bvh_free(RayObject *o)
MEM_freeN(obj);
}
static void RayObject_bvh_bb(RayObject *o, float *min, float *max)
static void RayObject_blibvh_bb(RayObject *o, float *min, float *max)
{
BVHObject *obj = (BVHObject*)o;
DO_MINMAX( obj->bb[0], min, max );
@@ -0,0 +1,222 @@
#include "rayobject_rtbuild.h"
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BKE_utildefines.h"
static int partition_nth_element(RTBuilder *b, int _begin, int _end, int n);
static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis);
static void RayObject_rtbuild_init(RTBuilder *b, RayObject **begin, RayObject **end)
{
int i;
b->begin = begin;
b->end = end;
b->split_axis = 0;
for(i=0; i<MAX_CHILDS; i++)
b->child[i] = 0;
}
RTBuilder* RayObject_rtbuild_create(int size)
{
RTBuilder *builder = (RTBuilder*) MEM_mallocN( sizeof(RTBuilder), "RTBuilder" );
RayObject **memblock= (RayObject**)MEM_mallocN( sizeof(RayObject*),"RTBuilder.objects");
RayObject_rtbuild_init(builder, memblock, memblock);
return builder;
}
void RayObject_rtbuild_free(RTBuilder *b)
{
MEM_freeN(b->begin);
MEM_freeN(b);
}
void RayObject_rtbuild_add(RTBuilder *b, RayObject *o)
{
*(b->end++) = o;
}
RTBuilder* rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp)
{
RayObject_rtbuild_init( tmp, b->child[child], b->child[child+1] );
return tmp;
}
int RayObject_rtbuild_size(RTBuilder *b)
{
return b->end - b->begin;
}
/* Split methods */
static void merge_bb(RTBuilder *b, float *min, float *max)
{
RayObject **index = b->begin;
for(; index != b->end; index++)
RE_rayobject_merge_bb(*index, min, max);
}
static int calc_largest_axis(RTBuilder *b)
{
float min[3], max[3], sub[3];
INIT_MINMAX(min, max);
merge_bb( b, min, max);
VECSUB(sub, max, min);
if(sub[0] > sub[1])
{
if(sub[0] > sub[2])
return 0;
else
return 2;
}
else
{
if(sub[1] > sub[2])
return 1;
else
return 2;
}
}
//Unballanced mean
//TODO better balance nodes
//TODO suport for variable number of partitions (its hardcoded in 2)
void rtbuild_mean_split(RTBuilder *b, int nchilds, int axis)
{
int nth[3] = {0, (b->end - b->begin)/2, b->end-b->begin};
split_leafs(b, nth, 2, axis);
}
void rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds)
{
int axis = calc_largest_axis(b);
rtbuild_mean_split(b, nchilds, axis);
}
/*
* Helper code
* PARTITION code / used on mean-split
* basicly this a std::nth_element (like on C++ STL algorithm)
*/
static void sort_swap(RTBuilder *b, int i, int j)
{
SWAP(RayObject*, b->begin[i], b->begin[j]);
}
static int sort_get_value(RTBuilder *b, int i)
{
float min[3], max[3];
RE_rayobject_merge_bb(b->begin[i], min, max);
return max[i];
}
static int medianof3(RTBuilder *d, int a, int b, int c)
{
float fa = sort_get_value( d, a );
float fb = sort_get_value( d, b );
float fc = sort_get_value( d, c );
if(fb < fa)
{
if(fc < fb)
return b;
else
{
if(fc < fa)
return c;
else
return a;
}
}
else
{
if(fc > fb)
return b;
else
{
if(fc > fa)
return c;
else
return a;
}
}
}
static void insertionsort(RTBuilder *b, int lo, int hi)
{
int i;
for(i=lo; i<hi; i++)
{
RayObject *t = b->begin[i];
float tv= sort_get_value(b, i);
int j=i;
while( j != lo && tv < sort_get_value(b, j-1))
{
b->begin[j] = b->begin[j-1];
j--;
}
b->begin[j] = t;
}
}
static int partition(RTBuilder *b, int lo, int mid, int hi)
{
float x = sort_get_value( b, mid );
int i=lo, j=hi;
while (1)
{
while (sort_get_value(b,i) < x) i++;
j--;
while (x < sort_get_value(b,j)) j--;
if(!(i < j))
return i;
sort_swap(b, i, j);
i++;
}
}
//
// PARTITION code / used on mean-split
// basicly this is an adapted std::nth_element (C++ STL <algorithm>)
//
// after a call to this function you can expect one of:
// every node to left of a[n] are smaller or equal to it
// every node to the right of a[n] are greater or equal to it
static int partition_nth_element(RTBuilder *b, int _begin, int _end, int n)
{
int begin = _begin, end = _end, cut;
while(end-begin > 3)
{
cut = partition(b, begin, medianof3(b, begin, begin+(end-begin)/2, end-1), end);
if(cut <= n)
begin = cut;
else
end = cut;
}
insertionsort(b, begin, end);
return n;
}
static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis)
{
int i;
b->split_axis = split_axis;
for(i=0; i < partitions-1; i++)
{
if(nth[i] >= nth[partitions])
break;
partition_nth_element(b, nth[i], nth[i+1], nth[partitions] );
}
}
@@ -180,7 +180,7 @@ RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
if(re->r.raystructure == R_RAYSTRUCTURE_HIER_BVH_OCTREE)
raytree = obr->raytree = RE_rayobject_octree_create( re->r.ocres, faces );
else //if(re->r.raystructure == R_RAYSTRUCTURE_HIER_BVH_BVH)
raytree = obr->raytree = RE_rayobject_bvh_create( faces );
raytree = obr->raytree = RE_rayobject_blibvh_create( faces );
face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces");
obr->rayobi = obi;
@@ -240,7 +240,7 @@ static void makeraytree_hier(Render *re)
num_objects++;
//Create raytree
re->raytree = RE_rayobject_bvh_create( num_objects );
re->raytree = RE_rayobject_blibvh_create( num_objects );
for(obi=re->instancetable.first; obi; obi=obi->next)
if(is_raytraceable(re, obi))
@@ -292,7 +292,7 @@ static void makeraytree_single(Render *re)
if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_OCTREE)
raytree = re->raytree = RE_rayobject_octree_create( re->r.ocres, faces );
else //if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_BVH)
raytree = re->raytree = RE_rayobject_bvh_create( faces );
raytree = re->raytree = RE_rayobject_blibvh_create( faces );
face = re->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces");