#include <string.h>
#include <stdlib.h>
#include <float.h>
+#include <assert.h>
#include "MEM_guardedalloc.h"
#include "texture.h"
#include "RE_raytrace.h"
+#include "rayobject.h"
#define RAY_TRA 1
#define RAY_TRAFLIP 2
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+RayObject * RE_rayobject_tree_create(int type, int size) __attribute__((noinline));
+
+RayObject * RE_rayobject_tree_create(int type, int size)
{
- VlakRen *vlr= (VlakRen*)face;
+// if(type == R_RAYTRACE_TREE_BIH)
+ return RE_rayobject_vbvh_create(size);
+
+ if(type == R_RAYTRACE_TREE_BVH)
+ return RE_rayobject_bvh_create(size);
+ if(type == R_RAYTRACE_TREE_BIH)
+ return RE_rayobject_bih_create(size);
+ if(type == R_RAYTRACE_TREE_BLIBVH)
+ return RE_rayobject_blibvh_create(size);
- *v1 = (vlr->v1)? vlr->v1->co: NULL;
- *v2 = (vlr->v2)? vlr->v2->co: NULL;
- *v3 = (vlr->v3)? vlr->v3->co: NULL;
- *v4 = (vlr->v4)? vlr->v4->co: NULL;
}
+#ifdef RE_RAYCOUNTER
+RayCounter re_rc_counter[BLENDER_MAX_THREADS] = {};
+#endif
+
+#if 0
static int vlr_check_intersect(Isect *is, int ob, RayFace *face)
{
ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)is->userdata, ob);
else
return (is->lay & obi->lay);
}
+#endif
-static float *vlr_get_transform(void *userdata, int i)
+void freeraytree(Render *re)
{
- ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)userdata, i);
+ ObjectInstanceRen *obi;
+
+ if(re->raytree)
+ {
+ RE_rayobject_free(re->raytree);
+ re->raytree = NULL;
+ }
+ if(re->rayfaces)
+ {
+ MEM_freeN(re->rayfaces);
+ re->rayfaces = NULL;
+ }
- return (obi->flag & R_TRANSFORMED)? (float*)obi->mat: NULL;
+ for(obi=re->instancetable.first; obi; obi=obi->next)
+ {
+ ObjectRen *obr = obi->obr;
+ if(obr->raytree)
+ {
+ RE_rayobject_free(obr->raytree);
+ obr->raytree = NULL;
+ }
+ if(obr->rayfaces)
+ {
+ MEM_freeN(obr->rayfaces);
+ obr->rayfaces = NULL;
+ }
+ if(obi->raytree)
+ {
+ RE_rayobject_free(obi->raytree);
+ obi->raytree = NULL;
+ }
+ }
+
+#ifdef RE_RAYCOUNTER
+ {
+ RayCounter sum = {};
+ int i;
+ for(i=0; i<BLENDER_MAX_THREADS; i++)
+ RE_RC_MERGE(&sum, re_rc_counter+i);
+ RE_RC_INFO(&sum);
+ }
+#endif
}
-void freeraytree(Render *re)
+static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
{
- if(re->raytree) {
- RE_ray_tree_free(re->raytree);
- re->raytree= NULL;
- }
+ if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
+ if(vlr->mat->material_type != MA_TYPE_WIRE)
+ return 1;
+ return 0;
}
-void makeraytree(Render *re)
+static int is_raytraceable(Render *re, ObjectInstanceRen *obi)
{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- float min[3], max[3], co1[3], co2[3], co3[3], co4[3];
- double lasttime= PIL_check_seconds_timer();
- int v, totv = 0, totface = 0;
+ int v;
+ ObjectRen *obr = obi->obr;
- INIT_MINMAX(min, max);
+ if(re->excludeob && obr->ob == re->excludeob)
+ return 0;
- /* first min max raytree space */
- for(obi=re->instancetable.first; obi; obi=obi->next) {
- obr= obi->obr;
-
- if(re->excludeob && obr->ob == re->excludeob)
- continue;
-
- for(v=0;v<obr->totvlak;v++) {
- if((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
- /* baking selected to active needs non-traceable too */
- if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE)) {
- if(vlr->mat->material_type != MA_TYPE_WIRE) {
- VECCOPY(co1, vlr->v1->co);
- VECCOPY(co2, vlr->v2->co);
- VECCOPY(co3, vlr->v3->co);
-
- if(obi->flag & R_TRANSFORMED) {
- Mat4MulVecfl(obi->mat, co1);
- Mat4MulVecfl(obi->mat, co2);
- Mat4MulVecfl(obi->mat, co3);
- }
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ return 1;
+ }
+ return 0;
+}
- DO_MINMAX(co1, min, max);
- DO_MINMAX(co2, min, max);
- DO_MINMAX(co3, min, max);
- if(vlr->v4) {
- VECCOPY(co4, vlr->v4->co);
- if(obi->flag & R_TRANSFORMED)
- Mat4MulVecfl(obi->mat, co4);
- DO_MINMAX(co4, min, max);
- }
+RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
+{
+ //TODO
+ // out-of-memory safeproof
+ // break render
+ // update render stats
+ ObjectRen *obr = obi->obr;
+
+ if(obr->raytree == NULL)
+ {
+ RayObject *raytree;
+ RayFace *face;
+ int v;
+
+ //Count faces
+ int faces = 0;
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ faces++;
+ }
+ assert( faces > 0 );
- totface++;
- }
+ //Create Ray cast accelaration structure
+
+ //TODO dynamic ocres
+ 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_tree_create( re->r.raytrace_tree_type, faces );
+
+ face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces");
+ obr->rayobi = obi;
+
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ {
+ RE_rayface_from_vlak( face, obi, vlr );
+ RE_rayobject_add( raytree, RayObject_unalignRayFace(face) );
+ face++;
}
}
+ RE_rayobject_done( raytree );
}
- re->raytree= RE_ray_tree_create(re->r.ocres, totface, min, max,
- vlr_face_coords, vlr_check_intersect, vlr_get_transform, re);
- if(min[0] > max[0]) { /* empty raytree */
- RE_ray_tree_done(re->raytree);
- return;
+ if(obi->flag & R_TRANSFORMED)
+ {
+ obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi );
}
+
+ if(obi->raytree) return obi->raytree;
+ return obi->obr->raytree;
+}
- for(obi=re->instancetable.first; obi; obi=obi->next) {
- obr= obi->obr;
+/*
+ * create an hierarchic raytrace structure with all objects
+ *
+ * R_TRANSFORMED objects instances reuse the same tree by using the rayobject_instance
+ */
+static void makeraytree_hier(Render *re)
+{
+ //TODO
+ // out-of-memory safeproof
+ // break render
+ // update render stats
- if(re->excludeob && obr->ob == re->excludeob)
- continue;
+ ObjectInstanceRen *obi;
+ int num_objects = 0;
- for(v=0; v<obr->totvlak; v++, totv++) {
- if((v & 255)==0) {
- double time= PIL_check_seconds_timer();
+ re->i.infostr="Creating raytrace structure";
+ re->stats_draw(re->sdh, &re->i);
- vlr= obr->vlaknodes[v>>8].vlak;
- if(re->test_break(re->tbh))
- break;
- if(time-lasttime>1.0f) {
- char str[32];
- sprintf(str, "Filling Octree: %d", totv);
- re->i.infostr= str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr= NULL;
- lasttime= time;
- }
+ //Count number of objects
+ for(obi=re->instancetable.first; obi; obi=obi->next)
+ if(is_raytraceable(re, obi))
+ num_objects++;
+
+ //Create raytree
+ re->raytree = RE_rayobject_tree_create( re->r.raytrace_tree_type, num_objects );
+
+ for(obi=re->instancetable.first; obi; obi=obi->next)
+ if(is_raytraceable(re, obi))
+ {
+ RayObject *obj = makeraytree_object(re, obi);
+ RE_rayobject_add( re->raytree, obj );
+
+ if(re->test_break(re->tbh))
+ break;
+ }
+
+ if(!re->test_break(re->tbh))
+ {
+ RE_rayobject_done( re->raytree );
+ }
+
+ re->i.infostr= NULL;
+ re->stats_draw(re->sdh, &re->i);
+}
+
+static int has_special_rayobject(Render *re, ObjectInstanceRen *obi)
+{
+ if( (obi->flag & R_TRANSFORMED) )
+ {
+ ObjectRen *obr = obi->obr;
+ int v, faces = 0;
+
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ {
+ faces++;
+ if(faces > 4)
+ return 1;
}
- else vlr++;
-
- if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
- if(vlr->mat->material_type != MA_TYPE_WIRE)
- RE_ray_tree_add_face(re->raytree, RAY_OBJECT_SET(re, obi), vlr);
}
}
+ return 0;
+}
+/*
+ * create a single raytrace structure with all faces
+ */
+static void makeraytree_single(Render *re)
+{
+ ObjectInstanceRen *obi;
+ RayObject *raytree;
+ RayFace *face;
+ int faces = 0, obs = 0;
- RE_ray_tree_done(re->raytree);
+ for(obi=re->instancetable.first; obi; obi=obi->next)
+ if(is_raytraceable(re, obi))
+ {
+ int v;
+ ObjectRen *obr = obi->obr;
+ obs++;
+
+ if(has_special_rayobject(re, obi))
+ {
+ faces++;
+ }
+ else
+ {
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ faces++;
+ }
+ }
+ }
- re->i.infostr= NULL;
- re->stats_draw(re->sdh, &re->i);
+ //Create raytree
+ 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_tree_create( re->r.raytrace_tree_type, faces );
+
+ face = re->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces");
+
+ for(obi=re->instancetable.first; obi; obi=obi->next)
+ if(is_raytraceable(re, obi))
+ {
+ if(has_special_rayobject(re, obi))
+ {
+ RayObject *obj = makeraytree_object(re, obi);
+ RE_rayobject_add( re->raytree, obj );
+ }
+ else
+ {
+ int v;
+ ObjectRen *obr = obi->obr;
+
+ for(v=0;v<obr->totvlak;v++)
+ {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if(is_raytraceable_vlr(re, vlr))
+ {
+ RE_rayface_from_vlak(face, obi, vlr);
+ if((obi->flag & R_TRANSFORMED))
+ {
+ Mat4MulVecfl(obi->mat, face->v1);
+ Mat4MulVecfl(obi->mat, face->v2);
+ Mat4MulVecfl(obi->mat, face->v3);
+ if(RE_rayface_isQuad(face))
+ Mat4MulVecfl(obi->mat, face->v4);
+ }
+
+ RE_rayobject_add( raytree, RayObject_unalignRayFace(face) );
+ face++;
+ }
+ }
+ }
+ }
+ RE_rayobject_done( raytree );
+}
+
+void makeraytree(Render *re)
+{
+ float min[3], max[3], sub[3];
+ int i;
+ const char *tree_type = "Tree(unknown)";
+
+ re->r.raystructure = R_RAYSTRUCTURE_SINGLE_BVH;
+#ifdef RE_RAYCOUNTER
+ if(re->r.raytrace_tree_type == R_RAYTRACE_TREE_BVH)
+ tree_type = "BVH";
+ if(re->r.raytrace_tree_type == R_RAYTRACE_TREE_BIH)
+ tree_type = "BIH";
+ if(re->r.raytrace_tree_type == R_RAYTRACE_TREE_BLIBVH)
+ tree_type = "BLIBVH";
+
+ if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_OCTREE)
+ printf("Building single octree\n");
+ else if(re->r.raystructure == R_RAYSTRUCTURE_SINGLE_BVH)
+ printf("Building single tree(%s)\n", tree_type);
+ else if(re->r.raystructure == R_RAYSTRUCTURE_HIER_BVH_OCTREE)
+ printf("Building tree(%s) of octrees\n", tree_type);
+ else
+ printf("Building tree(%s) of trees(%s)\n", tree_type, tree_type);
+#endif
+
+ if(ELEM(re->r.raystructure, R_RAYSTRUCTURE_SINGLE_BVH, R_RAYSTRUCTURE_SINGLE_OCTREE))
+ BENCH(makeraytree_single(re), tree_build);
+ else
+ BENCH(makeraytree_hier(re), tree_build);
+
+
+ //Calculate raytree max_size
+ //This is ONLY needed to kept a bogus behaviour of SUN and HEMI lights
+ RE_rayobject_merge_bb( re->raytree, min, max );
+ for(i=0; i<3; i++)
+ {
+ min[i] += 0.01f;
+ max[i] += 0.01f;
+ sub[i] = max[i]-min[i];
+ }
+ re->maxdist = sqrt( sub[0]*sub[0] + sub[1]*sub[1] + sub[2]*sub[2] );
}
+
+
static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
{
- VlakRen *vlr= (VlakRen*)is->face;
- ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, is->ob);
+ ObjectInstanceRen *obi= (ObjectInstanceRen*)is->hit.ob;
+ VlakRen *vlr= (VlakRen*)is->hit.face;
int osatex= 0;
/* set up view vector */
ShadeResult shr;
Isect isec;
float f, f1, fr, fg, fb;
- float ref[3], maxsize=RE_ray_tree_max_size(R.raytree);
+ float ref[3];
float dist_mir = origshi->mat->dist_mir;
/* Warning, This is not that nice, and possibly a bit slow for every ray,
/* end warning! - Campbell */
VECCOPY(isec.start, start);
- if (dist_mir > 0.0) {
- isec.end[0]= start[0]+dist_mir*vec[0];
- isec.end[1]= start[1]+dist_mir*vec[1];
- isec.end[2]= start[2]+dist_mir*vec[2];
- } else {
- isec.end[0]= start[0]+maxsize*vec[0];
- isec.end[1]= start[1]+maxsize*vec[1];
- isec.end[2]= start[2]+maxsize*vec[2];
- }
+ VECCOPY(isec.vec, vec );
+ isec.labda = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
isec.mode= RE_RAY_MIRROR;
- isec.faceorig= (RayFace*)vlr;
- isec.oborig= RAY_OBJECT_SET(&R, obi);
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = 0;
+
+ isec.orig.ob = obi;
+ isec.orig.face = vlr;
+ RE_RC_INIT(isec, shi);
- if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if(RE_rayobject_raycast(R.raytree, &isec)) {
float d= 1.0f;
shi.mask= origshi->mask;
else {
ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, vec);
}
+ RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
}
/* **************** jitter blocks ********** */
do_tra= ((shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f);
do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0f);
-
/* raytrace mirror amd refract like to separate the spec color */
if(shi->combinedflag & SCE_PASS_SPEC)
if it has col[3]>0.0f continue. so exit when alpha is full */
ShadeInput shi;
ShadeResult shr;
-
- if(RE_ray_tree_intersect(R.raytree, is)) {
+ float initial_labda = is->labda;
+
+ if(RE_rayobject_raycast(R.raytree, is)) {
float d= 1.0f;
/* we got a face */
/* adapt isect struct */
VECCOPY(is->start, shi.co);
- is->oborig= RAY_OBJECT_SET(&R, shi.obi);
- is->faceorig= (RayFace*)shi.vlr;
+ is->labda = initial_labda-is->labda;
+ is->orig.ob = shi.obi;
+ is->orig.face = shi.vlr;
ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA);
}
+
+ RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
}
}
Isect isec;
ShadeInput shi;
ShadeResult shr_t;
- float vec[3], accum[3], div= 0.0f, maxsize= RE_ray_tree_max_size(R.raytree);
+ float vec[3], accum[3], div= 0.0f;
int a;
+ assert(0);
+
if(only_one) {
return 0;
}
accum[0]= accum[1]= accum[2]= 0.0f;
isec.mode= RE_RAY_MIRROR;
- isec.faceorig= (RayFace*)ship->vlr;
- isec.oborig= RAY_OBJECT_SET(&R, ship->obi);
+ isec.orig.ob = ship->obi;
+ isec.orig.face = ship->vlr;
+ isec.hint = 0;
+
+ VECCOPY(isec.start, ship->co);
+
+ RE_RC_INIT(isec, shi);
for(a=0; a<8*8; a++) {
vec[1]-= vec[1];
vec[2]-= vec[2];
}
- VECCOPY(isec.start, ship->co);
- isec.end[0]= isec.start[0] + maxsize*vec[0];
- isec.end[1]= isec.start[1] + maxsize*vec[1];
- isec.end[2]= isec.start[2] + maxsize*vec[2];
-
- if(RE_ray_tree_intersect(R.raytree, &isec)) {
+
+ VECCOPY(isec.vec, vec );
+ isec.labda = RE_RAYTRACE_MAXDIST;
+
+ if(RE_rayobject_raycast(R.raytree, &isec)) {
float fac;
/* Warning, This is not that nice, and possibly a bit slow for every ray,
static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
{
Isect isec;
+ RayHint point_hint;
QMCSampler *qsa=NULL;
float samp3d[3];
float up[3], side[3], dir[3], nrm[3];
float dxyview[3], skyadded=0, div;
int aocolor;
- isec.faceorig= (RayFace*)shi->vlr;
- isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
- isec.face_last= NULL;
- isec.ob_last= 0;
+ RE_RC_INIT(isec, *shi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = 0;
+
+ isec.hit.ob = 0;
+ isec.hit.face = 0;
+
+ isec.last_hit = NULL;
+
isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
isec.lay= -1;
+ VECCOPY(isec.start, shi->co);
+ RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start );
+ isec.hint = &point_hint;
+
+
shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
/* prevent sky colors to be added for only shadow (shadow becomes alpha) */
QMC_initPixel(qsa, shi->thread);
+
while (samples < max_samples) {
/* sampling, returns quasi-random vector in unit hemisphere */
Normalize(dir);
- VECCOPY(isec.start, shi->co);
- isec.end[0] = shi->co[0] - maxdist*dir[0];
- isec.end[1] = shi->co[1] - maxdist*dir[1];
- isec.end[2] = shi->co[2] - maxdist*dir[2];
+ isec.vec[0] = -dir[0];
+ isec.vec[1] = -dir[1];
+ isec.vec[2] = -dir[2];
+ isec.labda = maxdist;
prev = fac;
- if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if(RE_rayobject_raycast(R.raytree, &isec)) {
if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac);
else fac+= 1.0f;
}
static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
{
Isect isec;
+ RayHint point_hint;
float *vec, *nrm, div, bias, sh=0.0f;
float maxdist = R.wrld.aodist;
float dxyview[3];
int j= -1, tot, actual=0, skyadded=0, aocolor, resol= R.wrld.aosamp;
- isec.faceorig= (RayFace*)shi->vlr;
- isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
- isec.face_last= NULL;
- isec.ob_last= 0;
+ RE_RC_INIT(isec, *shi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = 0;
+
+ isec.hit.ob = 0;
+ isec.hit.face = 0;
+
+ isec.last_hit = NULL;
+
isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
isec.lay= -1;
+ VECCOPY(isec.start, shi->co);
+ RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start );
+ isec.hint = &point_hint;
shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
actual++;
- /* always set start/end, RE_ray_tree_intersect clips it */
- VECCOPY(isec.start, shi->co);
- isec.end[0] = shi->co[0] - maxdist*vec[0];
- isec.end[1] = shi->co[1] - maxdist*vec[1];
- isec.end[2] = shi->co[2] - maxdist*vec[2];
+ /* always set start/vec/labda */
+ isec.vec[0] = -vec[0];
+ isec.vec[1] = -vec[1];
+ isec.vec[2] = -vec[2];
+ isec.labda = maxdist;
/* do the trace */
- if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if(RE_rayobject_raycast(R.raytree, &isec)) {
if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac);
else sh+= 1.0f;
}
int samples=0;
float samp3d[3];
- float fac=0.0f, vec[3];
+ float fac=0.0f, vec[3], end[3];
float colsq[4];
float adapt_thresh = lar->adapt_thresh;
int min_adapt_samples=4, max_samples = lar->ray_totsamp;
float *co;
- int do_soft=1, full_osa=0;
+ int do_soft=1, full_osa=0, i;
+
+ float min[3], max[3];
+ RayHint bb_hint;
float jitco[RE_MAX_OSA][3];
int totjitco;
qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
QMC_initPixel(qsa, shi->thread);
+
+ INIT_MINMAX(min, max);
+ for(i=0; i<totjitco; i++)
+ {
+ DO_MINMAX(jitco[i], min, max);
+ }
+ RE_rayobject_hint_bb( R.raytree, &bb_hint, min, max);
+ isec->hint = &bb_hint;
+ isec->skip = RE_SKIP_VLR_NEIGHBOUR;
VECCOPY(vec, lampco);
-
while (samples < max_samples) {
- isec->faceorig= (RayFace*)shi->vlr;
- isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
+
+ isec->orig.ob = shi->obi;
+ isec->orig.face = shi->vlr;
/* manually jitter the start shading co-ord per sample
* based on the pre-generated OSA texture sampling offsets,
/* align samples to lamp vector */
Mat3MulVecfl(lar->mat, samp3d);
}
- isec->end[0]= vec[0]+samp3d[0];
- isec->end[1]= vec[1]+samp3d[1];
- isec->end[2]= vec[2]+samp3d[2];
+ end[0] = vec[0]+samp3d[0];
+ end[1] = vec[1]+samp3d[1];
+ end[2] = vec[2]+samp3d[2];
} else {
- VECCOPY(isec->end, vec);
+ VECCOPY(end, vec);
}
if(shi->strand) {
float jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco));
float v[3];
- VECSUB(v, co, isec->end);
+ VECSUB(v, co, end);
Normalize(v);
co[0] -= jitbias*v[0];
}
VECCOPY(isec->start, co);
+ isec->vec[0] = end[0]-isec->start[0];
+ isec->vec[1] = end[1]-isec->start[1];
+ isec->vec[2] = end[2]-isec->start[2];
+ isec->labda = 1.0f; // * Normalize(isec->vec);
/* trace the ray */
if(isec->mode==RE_RAY_SHADOW_TRA) {
colsq[2] += isec->col[2]*isec->col[2];
}
else {
- if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
+ if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
}
samples++;
float *jitlamp;
float fac=0.0f, div=0.0f, vec[3];
int a, j= -1, mask;
+ RayHint point_hint;
if(isec->mode==RE_RAY_SHADOW_TRA) {
shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
if(a==4) mask |= (mask>>4)|(mask>>8);
else if(a==9) mask |= (mask>>9);
+ VECCOPY(isec->start, shi->co);
+ isec->orig.ob = shi->obi;
+ isec->orig.face = shi->vlr;
+ RE_rayobject_hint_bb( R.raytree, &point_hint, isec->start, isec->start );
+ isec->hint = &point_hint;
+
while(a--) {
if(R.r.mode & R_OSA) {
}
}
- isec->faceorig= (RayFace*)shi->vlr;
- isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
-
vec[0]= jitlamp[0];
vec[1]= jitlamp[1];
vec[2]= 0.0f;
Mat3MulVecfl(lar->mat, vec);
- /* set start and end, RE_ray_tree_intersect clips it */
- VECCOPY(isec->start, shi->co);
- isec->end[0]= lampco[0]+vec[0];
- isec->end[1]= lampco[1]+vec[1];
- isec->end[2]= lampco[2]+vec[2];
+ /* set start and vec */
+ isec->vec[0] = vec[0]+lampco[0]-isec->start[0];
+ isec->vec[1] = vec[1]+lampco[1]-isec->start[1];
+ isec->vec[2] = vec[2]+lampco[2]-isec->start[2];
+ isec->labda = 1.0f;
+ isec->skip = RE_SKIP_VLR_NEIGHBOUR;
if(isec->mode==RE_RAY_SHADOW_TRA) {
/* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
shadfac[2] += isec->col[2];
shadfac[3] += isec->col[3];
}
- else if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
+ else if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
div+= 1.0f;
jitlamp+= 2;
void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
{
Isect isec;
- float lampco[3], maxsize;
+ float lampco[3];
/* setup isec */
+ RE_RC_INIT(isec, *shi);
if(shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
else isec.mode= RE_RAY_SHADOW;
+ isec.hint = 0;
if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
isec.lay= lar->lay;
/* only when not mir tracing, first hit optimm */
if(shi->depth==0) {
- isec.face_last= (RayFace*)lar->vlr_last[shi->thread];
- isec.ob_last= RAY_OBJECT_SET(&R, lar->obi_last[shi->thread]);
+ isec.last_hit = lar->last_hit[shi->thread];
}
else {
- isec.face_last= NULL;
- isec.ob_last= 0;
+ isec.last_hit = NULL;
}
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
- maxsize= RE_ray_tree_max_size(R.raytree);
- lampco[0]= shi->co[0] - maxsize*lar->vec[0];
- lampco[1]= shi->co[1] - maxsize*lar->vec[1];
- lampco[2]= shi->co[2] - maxsize*lar->vec[2];
+ /* jitter and QMC sampling add a displace vector to the lamp position
+ * that's incorrect because a SUN lamp does not has an exact position
+ * and the displace should be done at the ray vector instead of the
+ * lamp position.
+ * This is easily verified by noticing that shadows of SUN lights change
+ * with the scene BB.
+ *
+ * This was detected during SoC 2009 - Raytrace Optimization, but to keep
+ * consistency with older render code it wasn't removed.
+ *
+ * If the render code goes through some recode/serious bug-fix then this
+ * is something to consider!
+ */
+ lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
+ lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
+ lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];
}
else {
VECCOPY(lampco, lar->co);
} else {
if(lar->ray_totsamp<2) {
- isec.faceorig= (RayFace*)shi->vlr;
- isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+
shadfac[3]= 1.0f; // 1.0=full light
/* set up isec vec */
VECCOPY(isec.start, shi->co);
- VECCOPY(isec.end, lampco);
+ VECSUB(isec.vec, lampco, isec.start);
+ isec.labda = 1.0f;
if(isec.mode==RE_RAY_SHADOW_TRA) {
/* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0);
QUATCOPY(shadfac, isec.col);
}
- else if(RE_ray_tree_intersect(R.raytree, &isec)) shadfac[3]= 0.0f;
+ else if(RE_rayobject_raycast(R.raytree, &isec))
+ shadfac[3]= 0.0f;
}
else {
ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
/* for first hit optim, set last interesected shadow face */
if(shi->depth==0) {
- lar->vlr_last[shi->thread]= (VlakRen*)isec.face_last;
- lar->obi_last[shi->thread]= RAY_OBJECT_GET(&R, isec.ob_last);
+ lar->last_hit[shi->thread] = isec.last_hit;
}
}
static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co)
{
Isect isec;
- float lampco[3], maxsize;
+ float lampco[3];
+
+ assert(0);
/* setup isec */
+ RE_RC_INIT(isec, *shi);
isec.mode= RE_RAY_SHADOW_TRA;
+ isec.hint = 0;
if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1;
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
- maxsize= RE_ray_tree_max_size(R.raytree);
- lampco[0]= shi->co[0] - maxsize*lar->vec[0];
- lampco[1]= shi->co[1] - maxsize*lar->vec[1];
- lampco[2]= shi->co[2] - maxsize*lar->vec[2];
+ lampco[0]= shi->co[0] - RE_RAYTRACE_MAXDIST*lar->vec[0];
+ lampco[1]= shi->co[1] - RE_RAYTRACE_MAXDIST*lar->vec[1];
+ lampco[2]= shi->co[2] - RE_RAYTRACE_MAXDIST*lar->vec[2];
}
else {
VECCOPY(lampco, lar->co);
}
- isec.faceorig= (RayFace*)shi->vlr;
- isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
/* set up isec vec */
VECCOPY(isec.start, shi->co);
VECCOPY(isec.end, lampco);
- if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if(RE_rayobject_raycast(R.raytree, &isec)) {
/* we got a face */
/* render co */