*new generic raytrace API

*Adapted octree to a more generic raytrace API
*ray shadow works (other untested stuff disabled atm)

On the scene tested the user-cpu time got from 1:24 to 1:19/20
probably because of removed callbacks or sligtly diferente memory usage
This commit is contained in:
2009-05-10 21:02:58 +00:00
parent 71c19dadbe
commit a5ede43320
9 changed files with 973 additions and 825 deletions

View File

@@ -30,6 +30,7 @@
#include <math.h>
#include <string.h>
#include <assert.h>
#include "MEM_guardedalloc.h"
@@ -105,7 +106,7 @@ struct LaplacianSystem {
float *p; /* values from all p vectors */
float *mindist; /* minimum distance to a bone for all vertices */
RayTree *raytree; /* ray tracing acceleration structure */
RayObject *raytree; /* ray tracing acceleration structure */
MFace **vface; /* a face that the vertex belongs to */
} heat;
@@ -394,77 +395,31 @@ float laplacian_system_get_solution(int v)
#define DISTANCE_EPSILON 1e-4f
/* Raytracing for vertex to bone visibility */
static LaplacianSystem *HeatSys = NULL;
static void heat_ray_coords_func(RayFace *face, float **v1, float **v2, float **v3, float **v4)
{
MFace *mface= (MFace*)face;
float (*verts)[3]= HeatSys->heat.verts;
*v1= verts[mface->v1];
*v2= verts[mface->v2];
*v3= verts[mface->v3];
*v4= (mface->v4)? verts[mface->v4]: NULL;
}
static int heat_ray_check_func(Isect *is, int ob, RayFace *face)
{
float *v1, *v2, *v3, *v4, nor[3];
/* don't intersect if the ray faces along the face normal */
heat_ray_coords_func(face, &v1, &v2, &v3, &v4);
if(v4) CalcNormFloat4(v1, v2, v3, v4, nor);
else CalcNormFloat(v1, v2, v3, nor);
return (INPR(nor, is->vec) < 0);
}
static void heat_ray_tree_create(LaplacianSystem *sys)
{
Mesh *me = sys->heat.mesh;
RayTree *tree;
MFace *mface;
float min[3], max[3];
int a;
/* create a raytrace tree from the mesh */
INIT_MINMAX(min, max);
for(a=0; a<me->totvert; a++)
DO_MINMAX(sys->heat.verts[a], min, max);
tree= RE_ray_tree_create(64, me->totface, min, max,
heat_ray_coords_func, heat_ray_check_func, NULL, NULL);
sys->heat.vface= MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces");
HeatSys= sys;
sys->heat.raytree = RayObject_mesh_create(me, me);
sys->heat.vface = MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces");
for(a=0, mface=me->mface; a<me->totface; a++, mface++) {
RE_ray_tree_add_face(tree, 0, mface);
sys->heat.vface[mface->v1]= mface;
sys->heat.vface[mface->v2]= mface;
sys->heat.vface[mface->v3]= mface;
if(mface->v4) sys->heat.vface[mface->v4]= mface;
}
HeatSys= NULL;
RE_ray_tree_done(tree);
sys->heat.raytree= tree;
}
static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone)
{
Isect isec;
MFace *mface;
float dir[3];
float end[3];
int visible;
assert( 0 );
mface= sys->heat.vface[vertex];
if(!mface)
return 1;
@@ -473,22 +428,24 @@ static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone)
memset(&isec, 0, sizeof(isec));
isec.mode= RE_RAY_SHADOW;
isec.lay= -1;
isec.face_last= NULL;
isec.faceorig= mface;
isec.orig.face = mface;
isec.skip = RE_SKIP_CULLFACE;
VECCOPY(isec.start, sys->heat.verts[vertex]);
PclosestVL3Dfl(isec.end, isec.start,
sys->heat.root[bone], sys->heat.tip[bone]);
PclosestVL3Dfl(end, isec.start, sys->heat.root[bone], sys->heat.tip[bone]);
VECSUB(isec.vec, end, isec.start);
isec.labda = 1.0f;
#if 0
TODO
/* add an extra offset to the start position to avoid self intersection */
VECSUB(dir, isec.end, isec.start);
VECCOPY(dir, isec.vec);
Normalize(dir);
VecMulf(dir, 1e-5);
VecAddf(isec.start, isec.start, dir);
HeatSys= sys;
visible= !RE_ray_tree_intersect(sys->heat.raytree, &isec);
HeatSys= NULL;
#endif
visible= !RayObject_raycast(sys->heat.raytree, &isec);
return visible;
}
@@ -752,7 +709,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones,
/* free */
if(vertsflipped) MEM_freeN(vertsflipped);
RE_ray_tree_free(sys->heat.raytree);
RayObject_free(sys->heat.raytree);
MEM_freeN(sys->heat.vface);
MEM_freeN(sys->heat.mindist);
@@ -1049,7 +1006,7 @@ typedef struct MeshDeformBind {
int *varidx;
/* raytrace */
RayTree *raytree;
RayObject *raytree;
} MeshDeformBind;
/* ray intersection */
@@ -1173,7 +1130,7 @@ static void meshdeform_ray_tree_free(MeshDeformBind *mdb)
static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec)
{
MFace *mface;
float face[4][3], co[3], uvw[3], len, nor[3];
float face[4][3], co[3], uvw[3], len, nor[3], end[3];
int f, hit, is= 0, totface;
isec->labda= 1e10;
@@ -1181,6 +1138,8 @@ static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec)
mface= mdb->cagedm->getFaceArray(mdb->cagedm);
totface= mdb->cagedm->getNumFaces(mdb->cagedm);
VECADDFAC( end, isec->start, isec->vec, isec->labda );
for(f=0; f<totface; f++, mface++) {
VECCOPY(face[0], mdb->cagecos[mface->v1]);
VECCOPY(face[1], mdb->cagecos[mface->v2]);
@@ -1188,26 +1147,26 @@ static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec)
if(mface->v4) {
VECCOPY(face[3], mdb->cagecos[mface->v4]);
hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
if(hit) {
CalcNormFloat(face[0], face[1], face[2], nor);
}
else {
hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[2], face[3], co, uvw);
hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw);
CalcNormFloat(face[0], face[2], face[3], nor);
}
}
else {
hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
CalcNormFloat(face[0], face[1], face[2], nor);
}
if(hit) {
len= VecLenf(isec->start, co)/VecLenf(isec->start, isec->end);
len= VecLenf(isec->start, co)/VecLenf(isec->start, end);
if(len < isec->labda) {
isec->labda= len;
isec->face= mface;
isec->hit.face = mface;
isec->isect= (INPR(isec->vec, nor) <= 0.0f);
is= 1;
}
@@ -1223,20 +1182,18 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float
Isect isec;
float (*cagecos)[3];
MFace *mface;
float vert[4][3], len;
float vert[4][3], len, end[3];
static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};
/* setup isec */
memset(&isec, 0, sizeof(isec));
isec.mode= RE_RAY_MIRROR; /* we want the closest intersection */
isec.lay= -1;
isec.face_last= NULL;
isec.faceorig= NULL;
isec.labda= 1e10f;
VECADD(isec.start, co1, epsilon);
VECADD(isec.end, co2, epsilon);
VECSUB(isec.vec, isec.end, isec.start);
VECADD(end, co2, epsilon);
VECSUB(isec.vec, end, isec.start);
#if 0
/*if(RE_ray_tree_intersect(mdb->raytree, &isec)) {*/
@@ -1244,7 +1201,7 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float
if(meshdeform_intersect(mdb, &isec)) {
len= isec.labda;
mface= isec.face;
mface=(MFace*)isec.hit.face;
/* create MDefBoundIsect */
isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));

View File

@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
* Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
* RE_raytrace.h: ray tracing api, can be used independently from the renderer.
@@ -31,84 +31,64 @@
#ifndef RE_RAYTRACE_H
#define RE_RAYTRACE_H
/* Internals about raycasting structures can be found on intern/raytree.h */
typedef struct RayObject RayObject;
typedef struct Isect Isect;
struct DerivedMesh;
struct Mesh;
int RayObject_raycast(RayObject *r, Isect *i);
void RayObject_add (RayObject *r, RayObject *);
void RayObject_done(RayObject *r);
void RayObject_free(RayObject *r);
/* RayObject constructors */
RayObject* RayObject_octree_create(int ocres, int size);
//RayObject* RayObject_derivedmesh_create(struct DerivedMesh*, void *ob);
RayObject* RayObject_mesh_create(struct Mesh*, void *ob);
/* Ray Intersection */
struct Isect
{
float start[3];
float vec[3];
/* float end[3]; - not used */
float labda, u, v;
struct
{
void *ob;
void *face;
/* RayObject *obj; */
}
hit, orig;
RayObject *last_hit; /* last hit optimization */
short isect; /* which half of quad */
short mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
int lay; /* -1 default, set for layer lamps */
int skip; /* RE_SKIP_CULLFACE */
float col[4]; /* RGBA for shadow_tra */
void *userdata;
};
/* ray types */
#define RE_RAY_SHADOW 0
#define RE_RAY_MIRROR 1
#define RE_RAY_SHADOW_TRA 2
/* spatial tree for raytracing acceleration */
typedef void RayTree;
/* abstraction of face type */
typedef void RayFace;
/* skip options */
#define RE_SKIP_CULLFACE 1
/* object numbers above this are transformed */
#define RE_RAY_TRANSFORM_OFFS 0x8000000
/* TODO use: FLT_MAX? */
#define RE_RAYTRACE_MAXDIST 1e33
/* convert from pointer to index in array and back, with offset if the
* instance is transformed */
#define RAY_OBJECT_SET(re, obi) \
((obi == NULL)? 0: \
((obi - (re)->objectinstance) + ((obi->flag & R_TRANSFORMED)? RE_RAY_TRANSFORM_OFFS: 0)))
#define RAY_OBJECT_GET(re, i) \
((re)->objectinstance + ((i >= RE_RAY_TRANSFORM_OFFS)? i-RE_RAY_TRANSFORM_OFFS: i))
/* struct for intersection data */
typedef struct Isect {
float start[3]; /* start+vec = end, in ray_tree_intersect */
float vec[3];
float end[3];
float labda, u, v; /* distance to hitpoint, uv weights */
RayFace *face; /* face is where to intersect with */
int ob;
RayFace *faceorig; /* start face */
int oborig;
RayFace *face_last; /* for shadow optimize, last intersected face */
int ob_last;
short isect; /* which half of quad */
short mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
int lay; /* -1 default, set for layer lamps */
/* only used externally */
float col[4]; /* RGBA for shadow_tra */
/* octree only */
RayFace *facecontr;
int obcontr;
float ddalabda;
short faceisect; /* flag if facecontr was done or not */
/* custom pointer to be used in the RayCheckFunc */
void *userdata;
} Isect;
/* function callbacks for face type abstraction */
typedef void (*RayCoordsFunc)(RayFace *face,
float **v1, float **v2, float **v3, float **v4);
typedef int (*RayCheckFunc)(Isect *is, int ob, RayFace *face);
typedef float *(*RayObjectTransformFunc)(void *userdata, int ob);
/* tree building and freeing */
RayTree *RE_ray_tree_create(int ocres, int totface, float *min, float *max,
RayCoordsFunc coordfunc, RayCheckFunc checkfunc,
RayObjectTransformFunc transformfunc, void *userdata);
void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face);
void RE_ray_tree_done(RayTree *tree);
void RE_ray_tree_free(RayTree *tree);
/* intersection with full tree and single face */
int RE_ray_tree_intersect(RayTree *tree, Isect *is);
int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc check);
int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc,
RayCoordsFunc coordsfunc);
/* retrieve the diameter of the tree structure, for setting intersection
end distance */
float RE_ray_tree_max_size(RayTree *tree);
#endif /*__RE_RAYTRACE_H__*/

View File

@@ -0,0 +1,122 @@
/**
* $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_H
#define RE_RAYOBJECT_H
#include "RE_raytrace.h"
#include <float.h>
/* RayObject
A ray object is everything where we can cast rays like:
* a face/triangle
* an octree
* a bvh tree
* an octree of bvh's
* a bvh of bvh's
All types of RayObjects can be created by implementing the
callbacks of the RayObject.
Due to high computing time evolved with casting on faces
there is a special type of RayObject (named RayFace)
which won't use callbacks like other generic nodes.
In order to allow a mixture of RayFace+RayObjects,
all RayObjects must be 4byte aligned, allowing us to use the
2 least significant bits (with the mask 0x02) to define the
type of RayObject.
This leads to 4 possible types of RayObject, but at the moment
only 2 are used:
addr&2 - type of object
0 RayFace
1 RayObject (generic with API callbacks)
2 unused
3 unused
0 was choosed to RayFace because thats the one where speed will be needed.
You actually don't need to care about this if you are only using the API
described on RE_raytrace.h
*/
typedef struct RayFace
{
float *v1, *v2, *v3, *v4;
void *ob;
void *face;
} RayFace;
struct RayObject
{
struct RayObjectAPI *api;
};
typedef int (*RayObject_raycast_callback)(RayObject *, Isect *);
typedef void (*RayObject_add_callback)(RayObject *, RayObject *);
typedef void (*RayObject_done_callback)(RayObject *);
typedef void (*RayObject_free_callback)(RayObject *);
typedef void (*RayObject_bb_callback)(RayObject *, float *min, float *max);
typedef struct RayObjectAPI
{
RayObject_raycast_callback raycast;
RayObject_add_callback add;
RayObject_done_callback done;
RayObject_free_callback free;
RayObject_bb_callback bb;
} RayObjectAPI;
//TODO use intptr_t
#define RayObject_align(o) ((RayObject*)(((int)o)&(~3)))
#define RayObject_unalign(o) ((RayObject*)(((int)o)|1))
#define RayObject_isFace(o) ((((int)o)&3) == 0)
/*
* Extend min/max coords so that the rayobject is inside them
*/
void RayObject_merge_bb(RayObject *ob, float *min, float *max);
/*
* This function differs from RayObject_raycast
* RayObject_intersect does NOT perform last-hit optimization
* So this is probably a function to call inside raytrace structures
*/
int RayObject_intersect(RayObject *r, Isect *i);
#define ISECT_EPSILON ((float)FLT_EPSILON)
#endif

View File

@@ -53,6 +53,7 @@ struct VlakTableNode;
struct GHash;
struct RenderBuckets;
struct ObjectInstanceRen;
struct RayObject;
#define TABLEINITSIZE 1024
#define LAMPINITSIZE 256
@@ -168,7 +169,8 @@ struct Render
ListBase parts;
/* octree tables and variables for raytrace */
void *raytree;
struct RayObject *raytree;
struct RayObject *rayfaces; /* TODO Temporary */
/* occlusion tree */
void *occlusiontree;
@@ -491,8 +493,7 @@ typedef struct LampRen {
short YF_glowtype;
/* ray optim */
VlakRen *vlr_last[BLENDER_MAX_THREADS];
ObjectInstanceRen *obi_last[BLENDER_MAX_THREADS];
struct RayObject *last_hit[BLENDER_MAX_THREADS];
struct MTex *mtex[MAX_MTEX];

View File

@@ -0,0 +1,276 @@
/**
* $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 *****
*/
#include "assert.h"
#include "BKE_utildefines.h"
#include "RE_raytrace.h"
#include "rayobject.h"
/* ray - triangle or quad intersection */
static int intersect_rayface(RayFace *face, Isect *is)
{
float co1[3],co2[3],co3[3],co4[3];
float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
float m0, m1, m2, divdet, det1;
short ok=0;
if(is->orig.ob == face->ob && is->orig.face == face->face)
return 0;
/* disabled until i got real & fast cylinder checking, this code doesnt work proper for faster strands */
// if(is->mode==RE_RAY_SHADOW && is->vlr->flag & R_STRAND)
// return intersection_strand(is);
VECCOPY(co1, face->v1);
VECCOPY(co2, face->v2);
//TODO if(v4) { SWAP(float*, v3, v4); }
if(face->v4)
{
VECCOPY(co3, face->v4);
VECCOPY(co4, face->v3);
}
else
{
VECCOPY(co3, face->v3);
}
t00= co3[0]-co1[0];
t01= co3[1]-co1[1];
t02= co3[2]-co1[2];
t10= co3[0]-co2[0];
t11= co3[1]-co2[1];
t12= co3[2]-co2[2];
r0= is->vec[0];
r1= is->vec[1];
r2= is->vec[2];
x0= t12*r1-t11*r2;
x1= t10*r2-t12*r0;
x2= t11*r0-t10*r1;
divdet= t00*x0+t01*x1+t02*x2;
m0= is->start[0]-co3[0];
m1= is->start[1]-co3[1];
m2= is->start[2]-co3[2];
det1= m0*x0+m1*x1+m2*x2;
if(divdet!=0.0f) {
float u;
divdet= 1.0f/divdet;
u= det1*divdet;
if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t02-m2*t01;
cros1= m2*t00-m0*t02;
cros2= m0*t01-m1*t00;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
is->labda= labda;
is->u= u; is->v= v;
ok= 1;
}
}
}
}
if(ok==0 && face->v4) {
t20= co3[0]-co4[0];
t21= co3[1]-co4[1];
t22= co3[2]-co4[2];
divdet= t20*x0+t21*x1+t22*x2;
if(divdet!=0.0f) {
float u;
divdet= 1.0f/divdet;
u = det1*divdet;
if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t22-m2*t21;
cros1= m2*t20-m0*t22;
cros2= m0*t21-m1*t20;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
ok= 2;
is->labda= labda;
is->u= u; is->v= v;
}
}
}
}
}
if(ok) {
is->isect= ok; // wich half of the quad
/*
TODO
if(is->mode!=RE_RAY_SHADOW) {
/ * for mirror & tra-shadow: large faces can be filled in too often, this prevents
a face being detected too soon... * /
if(is->labda > is->ddalabda) {
return 0;
}
}
*/
#if 0
TODO
/* when a shadow ray leaves a face, it can be little outside the edges of it, causing
intersection to be detected in its neighbour face */
if(is->facecontr && is->faceisect); // optimizing, the tests below are not needed
else if(is->labda< .1) {
RayFace *face= is->orig.face;
float *origv1, *origv2, *origv3, *origv4;
short de= 0;
coordsfunc(face, &origv1, &origv2, &origv3, &origv4);
if(ob == is->orig.ob) {
if(v1==origv1 || v2==origv1 || v3==origv1 || v4==origv1) de++;
if(v1==origv2 || v2==origv2 || v3==origv2 || v4==origv2) de++;
if(v1==origv3 || v2==origv3 || v3==origv3 || v4==origv3) de++;
if(origv4) {
if(v1==origv4 || v2==origv4 || v3==origv4 || v4==origv4) de++;
}
}
if(de) {
/* so there's a shared edge or vertex, let's intersect ray with face
itself, if that's true we can safely return 1, otherwise we assume
the intersection is invalid, 0 */
if(is->facecontr==NULL) {
is->obcontr= is->orig.ob;
is->facecontr= face;
is->faceisect= intersection2(face, is->orig.ob, transformfunc, coordsfunc, is->userdata,
-r0, -r1, -r2,
is->start[0], is->start[1], is->start[2]);
}
if(is->faceisect) return 1;
return 0;
}
}
#endif
is->hit.ob = face->ob;
is->hit.face = face->face;
return 1;
}
return 0;
}
int RayObject_raycast(RayObject *r, Isect *i)
{
if(i->mode==RE_RAY_SHADOW && i->last_hit && RayObject_intersect(i->last_hit, i))
return 1;
return RayObject_intersect(r, i);
}
int RayObject_intersect(RayObject *r, Isect *i)
{
assert(i->mode==RE_RAY_SHADOW);
if(RayObject_isFace(r))
{
return intersect_rayface( (RayFace*) r, i);
}
else
{
//TODO should be done somewhere else
// float len = Normalize( i->vec );
int hit;
i->vec[0] *= i->labda;
i->vec[1] *= i->labda;
i->vec[2] *= i->labda;
i->labda = 1.0f; //RE_RAYTRACE_MAXDIST; //len;
r = RayObject_align( r );
hit = r->api->raycast( r, i );
// i->labda /= len;
return hit;
}
}
void RayObject_add(RayObject *r, RayObject *o)
{
r = RayObject_align( r );
return r->api->add( r, o );
}
void RayObject_done(RayObject *r)
{
r = RayObject_align( r );
r->api->done( r );
}
void RayObject_free(RayObject *r)
{
r = RayObject_align( r );
r->api->free( r );
}
void RayObject_merge_bb(RayObject *r, float *min, float *max)
{
if(RayObject_isFace(r))
{
RayFace *face = (RayFace*)r;
DO_MINMAX( face->v1, min, max );
DO_MINMAX( face->v2, min, max );
DO_MINMAX( face->v3, min, max );
if(face->v4) DO_MINMAX( face->v4, min, max );
}
else
{
r = RayObject_align( r );
r->api->bb( r, min, max );
}
}

View File

@@ -0,0 +1,128 @@
/**
* $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 *****
*/
#include "rayobject.h"
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_utildefines.h"
typedef struct RayMesh
{
RayObject rayobj;
Mesh *mesh;
void *ob;
RayFace *faces;
int num_faces;
} RayMesh;
static int RayObject_mesh_intersect(RayObject *o, Isect *isec);
static void RayObject_mesh_add(RayObject *o, RayObject *ob);
static void RayObject_mesh_done(RayObject *o);
static void RayObject_mesh_free(RayObject *o);
static void RayObject_mesh_bb(RayObject *o, float *min, float *max);
static RayObjectAPI mesh_api =
{
RayObject_mesh_intersect,
RayObject_mesh_add,
RayObject_mesh_done,
RayObject_mesh_free,
RayObject_mesh_bb
};
static int RayObject_mesh_intersect(RayObject *o, Isect *isec)
{
RayMesh *rm= (RayMesh*)o;
int i, hit = 0;
for(i = 0; i<rm->num_faces; i++)
if(RayObject_raycast( (RayObject*)rm->faces+i, isec ))
{
hit = 1;
if(isec->mode == RE_RAY_SHADOW)
break;
}
return hit;
}
static void RayObject_mesh_add(RayObject *o, RayObject *ob)
{
}
static void RayObject_mesh_done(RayObject *o)
{
}
static void RayObject_mesh_free(RayObject *o)
{
RayMesh *rm= (RayMesh*)o;
MEM_freeN( rm->faces );
MEM_freeN( rm );
}
static void RayObject_mesh_bb(RayObject *o, float *min, float *max)
{
RayMesh *rm= (RayMesh*)o;
int i;
for(i = 0; i<rm->mesh->totvert; i++)
DO_MINMAX( rm->mesh->mvert[i].co, min, max);
}
RayObject* RayObject_mesh_create(Mesh *mesh, void *ob)
{
RayMesh *rm= MEM_callocN(sizeof(RayMesh), "Octree");
int i;
RayFace *face;
MFace *mface;
rm->rayobj.api = &mesh_api;
rm->mesh = mesh;
rm->faces = MEM_callocN(sizeof(RayFace)*mesh->totface, "octree rayobject nodes");
rm->num_faces = mesh->totface;
face = rm->faces;
mface = mesh->mface;
for(i=0; i<mesh->totface; i++, face++, mface++)
{
face->v1 = mesh->mvert[mface->v1].co;
face->v2 = mesh->mvert[mface->v2].co;
face->v3 = mesh->mvert[mface->v3].co;
face->v4 = mface->v4 ? mesh->mvert[mface->v4].co : NULL;
face->ob = ob;
face->face = (void*)i;
}
return RayObject_unalign((RayObject*) rm);
}

View File

@@ -32,6 +32,7 @@
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include "MEM_guardedalloc.h"
@@ -41,10 +42,9 @@
#include "BLI_arithb.h"
#include "RE_raytrace.h"
#include "rayobject.h"
/* ********** structs *************** */
#define BRANCH_ARRAY 1024
#define NODE_ARRAY 4096
@@ -60,13 +60,14 @@ typedef struct OcVal
typedef struct Node
{
struct RayFace *v[8];
int ob[8];
struct RayObject *v[8];
struct OcVal ov[8];
struct Node *next;
} Node;
typedef struct Octree {
RayObject rayobj;
struct Branch **adrbranch;
struct Node **adrnode;
float ocsize; /* ocsize: mult factor, max size octree */
@@ -74,19 +75,29 @@ typedef struct Octree {
float min[3], max[3];
int ocres;
int branchcount, nodecount;
char *ocface; /* during building only */
RayCoordsFunc coordsfunc;
RayCheckFunc checkfunc;
RayObjectTransformFunc transformfunc;
void *userdata;
/* during building only */
char *ocface;
RayObject **ro_nodes;
int ro_nodes_size, ro_nodes_used;
} Octree;
/* ******** globals ***************** */
/* just for statistics */
static int raycount;
static int accepted, rejected, coherent_ray;
static int RayObject_octree_intersect(RayObject *o, Isect *isec);
static void RayObject_octree_add(RayObject *o, RayObject *ob);
static void RayObject_octree_done(RayObject *o);
static void RayObject_octree_free(RayObject *o);
static void RayObject_octree_bb(RayObject *o, float *min, float *max);
static RayObjectAPI octree_api =
{
RayObject_octree_intersect,
RayObject_octree_add,
RayObject_octree_done,
RayObject_octree_free,
RayObject_octree_bb
};
/* **************** ocval method ******************* */
/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
@@ -233,7 +244,7 @@ static int face_in_node(RayFace *face, short x, short y, short z, float rtf[][3]
return 0;
}
static void ocwrite(Octree *oc, int ob, RayFace *face, int quad, short x, short y, short z, float rtf[][3])
static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[][3])
{
Branch *br;
Node *no;
@@ -283,8 +294,7 @@ static void ocwrite(Octree *oc, int ob, RayFace *face, int quad, short x, short
while(no->v[a]!=NULL) a++;
}
no->v[a]= face;
no->ob[a]= ob;
no->v[a]= (RayObject*)face;
if(quad)
calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x>>2, y>>1, z, &no->ov[a]);
@@ -374,13 +384,10 @@ static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocfa
ocface[oc->ocres*ocx2+ocy2]=1;
}
static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin)
static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax)
{
short *ocmax;
int a, x, y, y1, y2;
ocmax=ocmin+3;
for(x=ocmin[c1];x<=ocmax[c1];x++) {
a= oc->ocres*x;
for(y=ocmin[c2];y<=ocmax[c2];y++) {
@@ -399,7 +406,7 @@ static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *oc
}
}
void RE_ray_tree_free(RayTree *tree)
static void RayObject_octree_free(RayObject *tree)
{
Octree *oc= (Octree*)tree;
@@ -439,65 +446,38 @@ void RE_ray_tree_free(RayTree *tree)
MEM_freeN(oc);
}
RayTree *RE_ray_tree_create(int ocres, int totface, float *min, float *max, RayCoordsFunc coordsfunc, RayCheckFunc checkfunc, RayObjectTransformFunc transformfunc, void *userdata)
RayObject *RayObject_octree_create(int ocres, int size)
{
Octree *oc;
float t00, t01, t02;
int c, ocres2;
Octree *oc= MEM_callocN(sizeof(Octree), "Octree");
oc= MEM_callocN(sizeof(Octree), "Octree");
oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
oc->coordsfunc= coordsfunc;
oc->checkfunc= checkfunc;
oc->transformfunc= transformfunc;
oc->userdata= userdata;
/* only for debug info */
raycount=0;
accepted= 0;
rejected= 0;
coherent_ray= 0;
oc->rayobj.api = &octree_api;
/* fill main octree struct */
oc->ocres= ocres;
ocres2= oc->ocres*oc->ocres;
oc->ocres = ocres;
VECCOPY(oc->min, min);
VECCOPY(oc->max, max);
oc->ro_nodes = MEM_callocN(sizeof(RayObject*)*size, "octree rayobject nodes");
oc->ro_nodes_size = size;
oc->ro_nodes_used = 0;
oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree");
/* the lookup table, per face, for which nodes to fill in */
oc->ocface= MEM_callocN( 3*ocres2 + 8, "ocface");
memset(oc->ocface, 0, 3*ocres2);
for(c=0;c<3;c++) { /* octree enlarge, still needed? */
oc->min[c]-= 0.01f;
oc->max[c]+= 0.01f;
}
t00= oc->max[0]-oc->min[0];
t01= oc->max[1]-oc->min[1];
t02= oc->max[2]-oc->min[2];
/* this minus 0.1 is old safety... seems to be needed? */
oc->ocfacx= (oc->ocres-0.1)/t00;
oc->ocfacy= (oc->ocres-0.1)/t01;
oc->ocfacz= (oc->ocres-0.1)/t02;
oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */
return (RayTree*)oc;
return RayObject_unalign((RayObject*) oc);
}
void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
static void RayObject_octree_add(RayObject *tree, RayObject *node)
{
Octree *oc = (Octree*)tree;
float *v1, *v2, *v3, *v4, ocfac[3], rtf[4][3];
assert( oc->ro_nodes_used < oc->ro_nodes_size );
oc->ro_nodes[ oc->ro_nodes_used++ ] = node;
}
static void octree_fill_rayface(Octree *oc, RayFace *face)
{
float ocfac[3], rtf[4][3];
float co1[3], co2[3], co3[3], co4[3];
short rts[4][3], ocmin[6], *ocmax;
short rts[4][3];
short ocmin[3], ocmax[3];
char *ocface= oc->ocface; // front, top, size view of face, to fill in
int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
@@ -507,28 +487,12 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
ocres2= oc->ocres*oc->ocres;
ocmax= ocmin+3;
VECCOPY(co1, face->v1);
VECCOPY(co2, face->v2);
VECCOPY(co3, face->v3);
if(face->v4)
VECCOPY(co4, face->v4);
oc->coordsfunc(face, &v1, &v2, &v3, &v4);
VECCOPY(co1, v1);
VECCOPY(co2, v2);
VECCOPY(co3, v3);
if(v4)
VECCOPY(co4, v4);
if(ob >= RE_RAY_TRANSFORM_OFFS) {
float (*mat)[4]= (float(*)[4])oc->transformfunc(oc->userdata, ob);
if(mat) {
Mat4MulVecfl(mat, co1);
Mat4MulVecfl(mat, co2);
Mat4MulVecfl(mat, co3);
if(v4)
Mat4MulVecfl(mat, co4);
}
}
for(c=0;c<3;c++) {
rtf[0][c]= (co1[c]-oc->min[c])*ocfac[c] ;
rts[0][c]= (short)rtf[0][c];
@@ -536,7 +500,7 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
rts[1][c]= (short)rtf[1][c];
rtf[2][c]= (co3[c]-oc->min[c])*ocfac[c] ;
rts[2][c]= (short)rtf[2][c];
if(v4) {
if(face->v4) {
rtf[3][c]= (co4[c]-oc->min[c])*ocfac[c] ;
rts[3][c]= (short)rtf[3][c];
}
@@ -546,7 +510,7 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
oc1= rts[0][c];
oc2= rts[1][c];
oc3= rts[2][c];
if(v4==NULL) {
if(face->v4==NULL) {
ocmin[c]= MIN3(oc1,oc2,oc3);
ocmax[c]= MAX3(oc1,oc2,oc3);
}
@@ -560,7 +524,7 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
}
if(ocmin[0]==ocmax[0] && ocmin[1]==ocmax[1] && ocmin[2]==ocmax[2]) {
ocwrite(oc, ob, face, (v4 != NULL), ocmin[0], ocmin[1], ocmin[2], rtf);
ocwrite(oc, face, (face->v4 != NULL), ocmin[0], ocmin[1], ocmin[2], rtf);
}
else {
@@ -570,7 +534,7 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
d2dda(oc, 1,2,0,1,ocface+ocres2,rts,rtf);
d2dda(oc, 1,2,0,2,ocface,rts,rtf);
d2dda(oc, 1,2,1,2,ocface+2*ocres2,rts,rtf);
if(v4==NULL) {
if(face->v4==NULL) {
d2dda(oc, 2,0,0,1,ocface+ocres2,rts,rtf);
d2dda(oc, 2,0,0,2,ocface,rts,rtf);
d2dda(oc, 2,0,1,2,ocface+2*ocres2,rts,rtf);
@@ -584,9 +548,9 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
d2dda(oc, 3,0,1,2,ocface+2*ocres2,rts,rtf);
}
/* nothing todo with triangle..., just fills :) */
filltriangle(oc, 0,1,ocface+ocres2,ocmin);
filltriangle(oc, 0,2,ocface,ocmin);
filltriangle(oc, 1,2,ocface+2*ocres2,ocmin);
filltriangle(oc, 0,1,ocface+ocres2,ocmin,ocmax);
filltriangle(oc, 0,2,ocface,ocmin,ocmax);
filltriangle(oc, 1,2,ocface+2*ocres2,ocmin,ocmax);
/* init static vars here */
face_in_node(face, 0,0,0, rtf);
@@ -599,7 +563,7 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
for(z=ocmin[2];z<=ocmax[2];z++) {
if(ocface[b+z] && ocface[a+z]) {
if(face_in_node(NULL, x, y, z, rtf))
ocwrite(oc, ob, face, (v4 != NULL), x,y,z, rtf);
ocwrite(oc, face, (face->v4 != NULL), x,y,z, rtf);
}
}
}
@@ -625,433 +589,116 @@ void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face)
}
}
void RE_ray_tree_done(RayTree *tree)
static void RayObject_octree_done(RayObject *tree)
{
Octree *oc= (Octree*)tree;
Octree *oc = (Octree*)tree;
int c;
float t00, t01, t02;
int ocres2 = oc->ocres*oc->ocres;
INIT_MINMAX(oc->min, oc->max);
/* Calculate Bounding Box */
for(c=0; c<oc->ro_nodes_used; c++)
RayObject_merge_bb(oc->ro_nodes[c], oc->min, oc->max);
/* Alloc memory */
oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree");
/* the lookup table, per face, for which nodes to fill in */
oc->ocface= MEM_callocN( 3*ocres2 + 8, "ocface");
memset(oc->ocface, 0, 3*ocres2);
for(c=0;c<3;c++) { /* octree enlarge, still needed? */
oc->min[c]-= 0.01f;
oc->max[c]+= 0.01f;
}
t00= oc->max[0]-oc->min[0];
t01= oc->max[1]-oc->min[1];
t02= oc->max[2]-oc->min[2];
/* this minus 0.1 is old safety... seems to be needed? */
oc->ocfacx= (oc->ocres-0.1)/t00;
oc->ocfacy= (oc->ocres-0.1)/t01;
oc->ocfacz= (oc->ocres-0.1)/t02;
oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */
for(c=0; c<oc->ro_nodes_used; c++)
{
assert( RayObject_isFace(oc->ro_nodes[c]) );
octree_fill_rayface(oc, (RayFace*)oc->ro_nodes[c]);
}
MEM_freeN(oc->ocface);
oc->ocface= NULL;
MEM_freeN(oc->ro_nodes);
printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx );
printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy );
printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz );
}
/* ************ raytracer **************** */
#define ISECT_EPSILON ((float)FLT_EPSILON)
/* only for self-intersecting test with current render face (where ray left) */
static int intersection2(RayFace *face, int ob, RayObjectTransformFunc transformfunc, RayCoordsFunc coordsfunc, void *userdata, float r0, float r1, float r2, float rx1, float ry1, float rz1)
static void RayObject_octree_bb(RayObject *tree, float *min, float *max)
{
float *v1, *v2, *v3, *v4, co1[3], co2[3], co3[3], co4[3];
float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
float m0, m1, m2, divdet, det, det1;
float u1, v, u2;
coordsfunc(face, &v1, &v2, &v3, &v4);
/* happens for baking with non existing face */
if(v1==NULL)
return 1;
if(v4) {
SWAP(float*, v3, v4);
}
VECCOPY(co1, v1);
VECCOPY(co2, v2);
VECCOPY(co3, v3);
if(v4)
VECCOPY(co4, v4);
if(ob >= RE_RAY_TRANSFORM_OFFS) {
float (*mat)[4]= (float(*)[4])transformfunc(userdata, ob);
if(mat) {
Mat4MulVecfl(mat, co1);
Mat4MulVecfl(mat, co2);
Mat4MulVecfl(mat, co3);
if(v4)
Mat4MulVecfl(mat, co4);
}
}
t00= co3[0]-co1[0];
t01= co3[1]-co1[1];
t02= co3[2]-co1[2];
t10= co3[0]-co2[0];
t11= co3[1]-co2[1];
t12= co3[2]-co2[2];
x0= t11*r2-t12*r1;
x1= t12*r0-t10*r2;
x2= t10*r1-t11*r0;
divdet= t00*x0+t01*x1+t02*x2;
m0= rx1-co3[0];
m1= ry1-co3[1];
m2= rz1-co3[2];
det1= m0*x0+m1*x1+m2*x2;
if(divdet!=0.0f) {
u1= det1/divdet;
if(u1<ISECT_EPSILON) {
det= t00*(m1*r2-m2*r1);
det+= t01*(m2*r0-m0*r2);
det+= t02*(m0*r1-m1*r0);
v= det/divdet;
if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) {
return 1;
}
}
}
if(v4) {
t20= co3[0]-co4[0];
t21= co3[1]-co4[1];
t22= co3[2]-co4[2];
divdet= t20*x0+t21*x1+t22*x2;
if(divdet!=0.0f) {
u2= det1/divdet;
if(u2<ISECT_EPSILON) {
det= t20*(m1*r2-m2*r1);
det+= t21*(m2*r0-m0*r2);
det+= t22*(m0*r1-m1*r0);
v= det/divdet;
if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) {
return 2;
}
}
}
}
return 0;
}
#if 0
/* ray - line intersection */
/* disabled until i got real & fast cylinder checking, this code doesnt work proper
for faster strands */
static int intersection_strand(Isect *is)
{
float v1[3], v2[3]; /* length of strand */
float axis[3], rc[3], nor[3], radline, dist, len;
/* radius strand */
radline= 0.5f*VecLenf(is->vlr->v1->co, is->vlr->v2->co);
VecMidf(v1, is->vlr->v1->co, is->vlr->v2->co);
VecMidf(v2, is->vlr->v3->co, is->vlr->v4->co);
VECSUB(rc, v1, is->start); /* vector from base ray to base cylinder */
VECSUB(axis, v2, v1); /* cylinder axis */
CROSS(nor, is->vec, axis);
len= VecLength(nor);
if(len<FLT_EPSILON)
return 0;
dist= INPR(rc, nor)/len; /* distance between ray and axis cylinder */
if(dist<radline && dist>-radline) {
float dot1, dot2, dot3, rlen, alen, div;
float labda;
/* calculating the intersection point of shortest distance */
dot1 = INPR(rc, is->vec);
dot2 = INPR(is->vec, axis);
dot3 = INPR(rc, axis);
rlen = INPR(is->vec, is->vec);
alen = INPR(axis, axis);
div = alen * rlen - dot2 * dot2;
if (ABS(div) < FLT_EPSILON)
return 0;
labda = (dot1*dot2 - dot3*rlen)/div;
radline/= sqrt(alen);
/* labda: where on axis do we have closest intersection? */
if(labda >= -radline && labda <= 1.0f+radline) {
VlakRen *vlr= is->faceorig;
VertRen *v1= is->vlr->v1, *v2= is->vlr->v2, *v3= is->vlr->v3, *v4= is->vlr->v4;
/* but we dont do shadows from faces sharing edge */
if(v1==vlr->v1 || v2==vlr->v1 || v3==vlr->v1 || v4==vlr->v1) return 0;
if(v1==vlr->v2 || v2==vlr->v2 || v3==vlr->v2 || v4==vlr->v2) return 0;
if(v1==vlr->v3 || v2==vlr->v3 || v3==vlr->v3 || v4==vlr->v3) return 0;
if(vlr->v4) {
if(v1==vlr->v4 || v2==vlr->v4 || v3==vlr->v4 || v4==vlr->v4) return 0;
}
return 1;
}
}
return 0;
}
#endif
/* ray - triangle or quad intersection */
int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc, RayCoordsFunc coordsfunc)
{
RayFace *face= is->face;
int ob= is->ob;
float *v1,*v2,*v3,*v4,co1[3],co2[3],co3[3],co4[3];
float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
float m0, m1, m2, divdet, det1;
short ok=0;
/* disabled until i got real & fast cylinder checking, this code doesnt work proper
for faster strands */
// if(is->mode==RE_RAY_SHADOW && is->vlr->flag & R_STRAND)
// return intersection_strand(is);
coordsfunc(face, &v1, &v2, &v3, &v4);
if(v4) {
SWAP(float*, v3, v4);
}
VECCOPY(co1, v1);
VECCOPY(co2, v2);
VECCOPY(co3, v3);
if(v4)
VECCOPY(co4, v4);
if(ob) {
float (*mat)[4]= (float(*)[4])transformfunc(is->userdata, ob);
if(mat) {
Mat4MulVecfl(mat, co1);
Mat4MulVecfl(mat, co2);
Mat4MulVecfl(mat, co3);
if(v4)
Mat4MulVecfl(mat, co4);
}
}
t00= co3[0]-co1[0];
t01= co3[1]-co1[1];
t02= co3[2]-co1[2];
t10= co3[0]-co2[0];
t11= co3[1]-co2[1];
t12= co3[2]-co2[2];
r0= is->vec[0];
r1= is->vec[1];
r2= is->vec[2];
x0= t12*r1-t11*r2;
x1= t10*r2-t12*r0;
x2= t11*r0-t10*r1;
divdet= t00*x0+t01*x1+t02*x2;
m0= is->start[0]-co3[0];
m1= is->start[1]-co3[1];
m2= is->start[2]-co3[2];
det1= m0*x0+m1*x1+m2*x2;
if(divdet!=0.0f) {
float u;
divdet= 1.0f/divdet;
u= det1*divdet;
if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t02-m2*t01;
cros1= m2*t00-m0*t02;
cros2= m0*t01-m1*t00;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
is->labda= labda;
is->u= u; is->v= v;
ok= 1;
}
}
}
}
if(ok==0 && v4) {
t20= co3[0]-co4[0];
t21= co3[1]-co4[1];
t22= co3[2]-co4[2];
divdet= t20*x0+t21*x1+t22*x2;
if(divdet!=0.0f) {
float u;
divdet= 1.0f/divdet;
u = det1*divdet;
if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
float v, cros0, cros1, cros2;
cros0= m1*t22-m2*t21;
cros1= m2*t20-m0*t22;
cros2= m0*t21-m1*t20;
v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
float labda;
labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
ok= 2;
is->labda= labda;
is->u= u; is->v= v;
}
}
}
}
}
if(ok) {
is->isect= ok; // wich half of the quad
if(is->mode!=RE_RAY_SHADOW) {
/* for mirror & tra-shadow: large faces can be filled in too often, this prevents
a face being detected too soon... */
if(is->labda > is->ddalabda) {
return 0;
}
}
/* when a shadow ray leaves a face, it can be little outside the edges of it, causing
intersection to be detected in its neighbour face */
if(is->facecontr && is->faceisect); // optimizing, the tests below are not needed
else if(is->labda< .1) {
RayFace *face= is->faceorig;
float *origv1, *origv2, *origv3, *origv4;
short de= 0;
coordsfunc(face, &origv1, &origv2, &origv3, &origv4);
if(ob == is->oborig) {
if(v1==origv1 || v2==origv1 || v3==origv1 || v4==origv1) de++;
if(v1==origv2 || v2==origv2 || v3==origv2 || v4==origv2) de++;
if(v1==origv3 || v2==origv3 || v3==origv3 || v4==origv3) de++;
if(origv4) {
if(v1==origv4 || v2==origv4 || v3==origv4 || v4==origv4) de++;
}
}
if(de) {
/* so there's a shared edge or vertex, let's intersect ray with face
itself, if that's true we can safely return 1, otherwise we assume
the intersection is invalid, 0 */
if(is->facecontr==NULL) {
is->obcontr= is->oborig;
is->facecontr= face;
is->faceisect= intersection2(face, is->oborig, transformfunc, coordsfunc, is->userdata, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2]);
}
if(is->faceisect) return 1;
return 0;
}
}
return 1;
}
return 0;
Octree *oc = (Octree*)tree;
DO_MINMAX(oc->min, min, max);
DO_MINMAX(oc->max, min, max);
}
/* check all faces in this node */
static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval, RayCheckFunc checkfunc)
static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval)
{
RayFace *face;
int ob;
short nr=0;
OcVal *ov;
/* return on any first hit */
if(is->mode==RE_RAY_SHADOW) {
face= no->v[0];
ob= no->ob[0];
while(face) {
if(!(is->faceorig == face && is->oborig == ob)) {
if(checkfunc(is, ob, face)) {
ov= no->ov+nr;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
//accepted++;
is->ob= ob;
is->face= face;
if(RE_ray_face_intersection(is, oc->transformfunc, oc->coordsfunc)) {
is->ob_last= ob;
is->face_last= face;
return 1;
}
}
//else rejected++;
}
}
for(; no; no = no->next)
for(nr=0; nr<8; nr++)
{
RayObject *face = no->v[nr];
OcVal *ov = no->ov+nr;
nr++;
if(nr==8) {
no= no->next;
if(no==0) return 0;
nr=0;
if(!face) break; //TODO? return 0;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) )
{
if( RayObject_intersect(face,is) )
return 1;
}
face= no->v[nr];
ob= no->ob[nr];
}
}
else { /* else mirror or glass or shadowtra, return closest face */
else
{ /* else mirror or glass or shadowtra, return closest face */
Isect isect;
int found= 0;
is->labda= 1.0f; /* needed? */
isect= *is; /* copy for sorting */
assert(0);
face= no->v[0];
ob= no->ob[0];
while(face) {
if(!(is->faceorig == face && is->oborig == ob)) {
if(checkfunc(is, ob, face)) {
ov= no->ov+nr;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
//accepted++;
isect.ob= ob;
isect.face= face;
if(RE_ray_face_intersection(&isect, oc->transformfunc, oc->coordsfunc)) {
if(isect.labda<is->labda) {
*is= isect;
found= 1;
}
}
}
//else rejected++;
}
}
is->labda= 1.0f; /* needed? */
isect= *is; /* copy for sorting */
for(; no; no = no->next)
for(nr=0; nr<8; nr++)
{
RayObject *face = no->v[nr];
OcVal *ov = no->ov+nr;
nr++;
if(nr==8) {
no= no->next;
if(no==NULL) break;
nr=0;
if(!face) return 0;
if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) )
{
if( RayObject_raycast(face,is) )
if(isect.labda<is->labda) {
*is= isect;
found= 1;
}
}
face= no->v[nr];
ob= no->ob[nr];
}
return found;
@@ -1175,21 +822,14 @@ static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, i
*/
int RE_ray_tree_intersect(RayTree *tree, Isect *is)
{
Octree *oc= (Octree*)tree;
return RE_ray_tree_intersect_check(tree, is, oc->checkfunc);
}
/* return 1: found valid intersection */
/* starts with is->faceorig */
int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc)
/* starts with is->orig.face */
static int RayObject_octree_intersect(RayObject *tree, Isect *is)
{
Octree *oc= (Octree*)tree;
Node *no;
OcVal ocval;
float vec1[3], vec2[3];
float vec1[3], vec2[3], end[3];
float u1,u2,ox1,ox2,oy1,oy2,oz1,oz2;
float labdao,labdax,ldx,labday,ldy,labdaz,ldz, ddalabda;
int dx,dy,dz;
@@ -1200,45 +840,51 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
if(oc->branchcount==0) return 0;
/* do this before intersect calls */
#if 0
is->facecontr= NULL; /* to check shared edge */
is->obcontr= 0;
is->faceisect= is->isect= 0; /* shared edge, quad half flag */
is->userdata= oc->userdata;
#endif
#if 0
/* only for shadow! */
if(is->mode==RE_RAY_SHADOW) {
/* check with last intersected shadow face */
if(is->face_last!=NULL && !(is->face_last==is->faceorig && is->ob_last==is->oborig)) {
if(checkfunc(is, is->ob_last, is->face_last)) {
is->ob= is->ob_last;
is->face= is->face_last;
/* TODO check with last intersected shadow face */
if(is->last.face!=NULL && !(is->last.face==is->orig.face && is->last.ob==is->orig.ob)) {
if(checkfunc(is, is->last.ob, is->last.face)) {
is->ob= is->last.ob;
is->face= is->last.face;
VECSUB(is->vec, is->end, is->start);
if(RE_ray_face_intersection(is, oc->transformfunc, oc->coordsfunc)) return 1;
}
}
}
#endif
ldx= is->end[0] - is->start[0];
VECADDFAC( end, is->start, is->vec, is->labda );
ldx= end[0] - is->start[0];
u1= 0.0f;
u2= 1.0f;
/* clip with octree cube */
if(cliptest(-ldx, is->start[0]-oc->min[0], &u1,&u2)) {
if(cliptest(ldx, oc->max[0]-is->start[0], &u1,&u2)) {
ldy= is->end[1] - is->start[1];
ldy= end[1] - is->start[1];
if(cliptest(-ldy, is->start[1]-oc->min[1], &u1,&u2)) {
if(cliptest(ldy, oc->max[1]-is->start[1], &u1,&u2)) {
ldz= is->end[2] - is->start[2];
ldz = end[2] - is->start[2];
if(cliptest(-ldz, is->start[2]-oc->min[2], &u1,&u2)) {
if(cliptest(ldz, oc->max[2]-is->start[2], &u1,&u2)) {
c1=1;
if(u2<1.0f) {
is->end[0]= is->start[0]+u2*ldx;
is->end[1]= is->start[1]+u2*ldy;
is->end[2]= is->start[2]+u2*ldz;
end[0]= is->start[0]+u2*ldx;
end[1]= is->start[1]+u2*ldy;
end[2]= is->start[2]+u2*ldz;
}
if(u1>0.0f) {
assert( 0 );
is->start[0]+=u1*ldx;
is->start[1]+=u1*ldy;
is->start[2]+=u1*ldz;
@@ -1259,9 +905,9 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
ox1= (is->start[0]-oc->min[0])*oc->ocfacx;
oy1= (is->start[1]-oc->min[1])*oc->ocfacy;
oz1= (is->start[2]-oc->min[2])*oc->ocfacz;
ox2= (is->end[0]-oc->min[0])*oc->ocfacx;
oy2= (is->end[1]-oc->min[1])*oc->ocfacy;
oz2= (is->end[2]-oc->min[2])*oc->ocfacz;
ox2= (end[0]-oc->min[0])*oc->ocfacx;
oy2= (end[1]-oc->min[1])*oc->ocfacy;
oz2= (end[2]-oc->min[2])*oc->ocfacz;
ocx1= (int)ox1;
ocy1= (int)oy1;
@@ -1269,9 +915,16 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
ocx2= (int)ox2;
ocy2= (int)oy2;
ocz2= (int)oz2;
// for(ocx1=0; ocx1<oc->ocres; ocx1++)
// for(ocy1=0; ocy1<oc->ocres; ocy1++)
// for(ocz1=0; ocz1<oc->ocres; ocz1++)
// {
// no= ocread(oc, ocx1, ocy1, ocz1);
// if( testnode(oc, is, no, ocval) ) return 1;
// }
/* for intersection */
VECSUB(is->vec, is->end, is->start);
// return 0;
if(ocx1==ocx2 && ocy1==ocy2 && ocz1==ocz2) {
no= ocread(oc, ocx1, ocy1, ocz1);
@@ -1280,8 +933,8 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
vec1[0]= ox1; vec1[1]= oy1; vec1[2]= oz1;
vec2[0]= ox2; vec2[1]= oy2; vec2[2]= oz2;
calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
is->ddalabda= 1.0f;
if( testnode(oc, is, no, ocval, checkfunc) ) return 1;
// is->ddalabda= 1.0f;
if( testnode(oc, is, no, ocval) ) return 1;
}
}
else {
@@ -1359,8 +1012,8 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
vec2[2]= oz1-ddalabda*doz;
calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
is->ddalabda= ddalabda;
if( testnode(oc, is, no, ocval, checkfunc) ) return 1;
// is->ddalabda= ddalabda;
if( testnode(oc, is, no, ocval) ) return 1;
}
labdao= ddalabda;
@@ -1430,13 +1083,10 @@ int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc checkfunc
}
/* reached end, no intersections found */
is->ob_last= 0;
is->face_last= NULL;
is->hit.ob = 0;
is->hit.face = NULL;
return 0;
}
float RE_ray_tree_max_size(RayTree *tree)
{
return ((Octree*)tree)->ocsize;
}

View File

@@ -29,6 +29,7 @@
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include "MEM_guardedalloc.h"
@@ -56,6 +57,7 @@
#include "texture.h"
#include "RE_raytrace.h"
#include "rayobject.h"
#define RAY_TRA 1
#define RAY_TRAFLIP 2
@@ -68,6 +70,7 @@
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
#if 0
static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
{
VlakRen *vlr= (VlakRen*)face;
@@ -101,27 +104,28 @@ static float *vlr_get_transform(void *userdata, int i)
return (obi->flag & R_TRANSFORMED)? (float*)obi->mat: NULL;
}
#endif
void freeraytree(Render *re)
{
if(re->raytree) {
RE_ray_tree_free(re->raytree);
RayObject_free(re->raytree);
re->raytree= NULL;
MEM_freeN( re->rayfaces );
}
}
void makeraytree(Render *re)
{
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;
RayFace *faces, *cur_face;
INIT_MINMAX(min, max);
/* first min max raytree space */
//TODO (for now octree only supports RayFaces so we need to create them)
//
//count faces
for(obi=re->instancetable.first; obi; obi=obi->next) {
obr= obi->obr;
@@ -134,51 +138,31 @@ void makeraytree(Render *re)
/* baking selected to active needs non-traceable too */
if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE)) {
if((vlr->mat->mode & MA_WIRE)==0) {
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);
}
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);
}
totface++;
}
}
}
}
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;
}
re->raytree = RayObject_octree_create( re->r.ocres, totface );
//Fill rayfaces
re->rayfaces = (RayObject*)MEM_callocN(totface*sizeof(RayFace), "render faces");
cur_face = faces = (RayFace*)re->rayfaces;
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++, totv++) {
if((v & 255)==0) {
for(v=0;v<obr->totvlak;v++) {
if((v & 255)==0)
{
double time= PIL_check_seconds_timer();
vlr= obr->vlaknodes[v>>8].vlak;
vlr= obr->vlaknodes[v>>8].vlak;
if(re->test_break(re->tbh))
break;
@@ -192,23 +176,35 @@ void makeraytree(Render *re)
}
}
else vlr++;
if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
if((vlr->mat->mode & MA_WIRE)==0)
RE_ray_tree_add_face(re->raytree, RAY_OBJECT_SET(re, obi), vlr);
/* baking selected to active needs non-traceable too */
if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE)) {
if((vlr->mat->mode & MA_WIRE)==0) {
cur_face->v1 = vlr->v1->co;
cur_face->v2 = vlr->v2->co;
cur_face->v3 = vlr->v3->co;
cur_face->v4 = vlr->v4 ? vlr->v4->co : NULL;
cur_face->ob = (void*)obi;
cur_face->face = vlr;
RayObject_add( re->raytree, (RayObject*) cur_face );
cur_face++;
}
}
}
}
RE_ray_tree_done(re->raytree);
RayObject_done( re->raytree );
//TODO vlr_face_coords, vlr_check_intersect, vlr_get_transform, re);
re->i.infostr= NULL;
re->stats_draw(re->sdh, &re->i);
}
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 */
@@ -420,29 +416,25 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
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;
assert(0);
/* Warning, This is not that nice, and possibly a bit slow for every ray,
however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
memset(&shi, 0, sizeof(ShadeInput));
/* 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);
if(RE_ray_tree_intersect(R.raytree, &isec)) {
isec.orig.ob = obi;
isec.orig.face = vlr;
if(RayObject_raycast(R.raytree, &isec)) {
float d= 1.0f;
shi.mask= origshi->mask;
@@ -1279,8 +1271,10 @@ static void ray_trace_shadow_tra(Isect *is, int depth, int traflag)
if it has col[3]>0.0f continue. so exit when alpha is full */
ShadeInput shi;
ShadeResult shr;
assert(0);
if(RE_ray_tree_intersect(R.raytree, is)) {
if(RayObject_raycast(R.raytree, is)) {
float d= 1.0f;
/* we got a face */
@@ -1312,8 +1306,9 @@ static void ray_trace_shadow_tra(Isect *is, int depth, int traflag)
/* adapt isect struct */
VECCOPY(is->start, shi.co);
is->oborig= RAY_OBJECT_SET(&R, shi.obi);
is->faceorig= (RayFace*)shi.vlr;
is->orig.ob = shi.obi;
is->orig.face = shi.vlr;
ray_trace_shadow_tra(is, depth-1, traflag | RAY_TRA);
}
@@ -1329,9 +1324,11 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
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;
}
@@ -1339,8 +1336,8 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
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;
for(a=0; a<8*8; a++) {
@@ -1352,12 +1349,12 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
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(RayObject_raycast(R.raytree, &isec)) {
float fac;
/* Warning, This is not that nice, and possibly a bit slow for every ray,
@@ -1545,10 +1542,16 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
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;
assert(0);
isec.orig.ob = shi->obi;
isec.orig.face = shi->vlr;
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;
@@ -1601,13 +1604,14 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
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(RayObject_raycast(R.raytree, &isec)) {
if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac);
else fac+= 1.0f;
}
@@ -1672,10 +1676,16 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
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;
assert(0);
isec.orig.ob = shi->obi;
isec.orig.face = shi->vlr;
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;
@@ -1725,14 +1735,15 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
actual++;
/* always set start/end, RE_ray_tree_intersect clips it */
/* always set start/vec/labda */
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];
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(RayObject_raycast(R.raytree, &isec)) {
if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac);
else sh+= 1.0f;
}
@@ -1838,7 +1849,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
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;
@@ -1848,6 +1859,8 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
float jitco[RE_MAX_OSA][3];
int totjitco;
// assert(0);
colsq[0] = colsq[1] = colsq[2] = 0.0;
if(isec->mode==RE_RAY_SHADOW_TRA) {
shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
@@ -1879,8 +1892,9 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
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,
@@ -1916,11 +1930,11 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
/* 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) {
@@ -1928,7 +1942,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
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];
@@ -1937,6 +1951,11 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
}
VECCOPY(isec->start, co);
// VECSUB(isec->vec, end, isec->start);
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) {
@@ -1955,7 +1974,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
colsq[2] += isec->col[2]*isec->col[2];
}
else {
if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
if( RayObject_raycast(R.raytree, isec) ) fac+= 1.0f;
}
samples++;
@@ -1996,6 +2015,8 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa
float fac=0.0f, div=0.0f, vec[3];
int a, j= -1, mask;
assert(0);
if(isec->mode==RE_RAY_SHADOW_TRA) {
shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
}
@@ -2022,19 +2043,18 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa
}
}
isec->faceorig= (RayFace*)shi->vlr;
isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
isec->orig.ob = shi->obi;
isec->orig.face = shi->vlr;
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 */
/* set start and vec */
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];
VECCOPY(isec->vec, vec);
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) */
@@ -2047,7 +2067,7 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa
shadfac[2] += isec->col[2];
shadfac[3] += isec->col[3];
}
else if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
else if( RayObject_raycast(R.raytree, isec) ) fac+= 1.0f;
div+= 1.0f;
jitlamp+= 2;
@@ -2071,7 +2091,7 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa
void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
{
Isect isec;
float lampco[3], maxsize;
float lampco[3];
/* setup isec */
if(shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
@@ -2084,19 +2104,16 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
/* 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];
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);
@@ -2109,13 +2126,15 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
} 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) */
@@ -2125,7 +2144,11 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
ray_trace_shadow_tra(&isec, DEPTH_SHADOW_TRA, 0);
QUATCOPY(shadfac, isec.col);
}
else if(RE_ray_tree_intersect(R.raytree, &isec)) shadfac[3]= 0.0f;
else
{
assert(0);
if(RayObject_raycast(R.raytree, &isec)) shadfac[3]= 0.0f;
}
}
else {
ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
@@ -2134,8 +2157,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
/* 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;
}
}
@@ -2145,7 +2167,9 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
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 */
isec.mode= RE_RAY_SHADOW_TRA;
@@ -2153,23 +2177,22 @@ static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float
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(RayObject_raycast(R.raytree, &isec)) {
/* we got a face */
/* render co */

View File

@@ -31,6 +31,7 @@
#include <math.h>
#include <float.h>
#include <string.h>
#include <assert.h>
/* External modules: */
#include "MEM_guardedalloc.h"
@@ -2234,6 +2235,7 @@ static void bake_displacement(void *handle, ShadeInput *shi, float dist, int x,
}
}
#if 0
static int bake_check_intersect(Isect *is, int ob, RayFace *face)
{
BakeShade *bs = (BakeShade*)is->userdata;
@@ -2243,9 +2245,13 @@ static int bake_check_intersect(Isect *is, int ob, RayFace *face)
return (R.objectinstance[ob].obr->ob != bs->actob);
}
#endif
static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
{
//TODO
assert( 0 );
#if 0
float maxdist;
int hit;
@@ -2253,15 +2259,17 @@ static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *start, flo
if(R.r.bake_maxdist > 0.0f)
maxdist= R.r.bake_maxdist;
else
maxdist= RE_ray_tree_max_size(R.raytree) + R.r.bake_biasdist;
maxdist= FLT_MAX + R.r.bake_biasdist;
//TODO normalized direction?
VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);
isect->dir[0] = dir[0]*sign;
isect->dir[1] = dir[1]*sign;
isect->dir[2] = dir[2]*sign;
isect->labda = maxdist;
isect->end[0] = isect->start[0] + dir[0]*maxdist*sign;
isect->end[1] = isect->start[1] + dir[1]*maxdist*sign;
isect->end[2] = isect->start[2] + dir[2]*maxdist*sign;
hit = RE_ray_tree_intersect_check(R.raytree, isect, bake_check_intersect);
hit = RayObject_raycast(raytree, isect);
//TODO bake_check_intersect
if(hit) {
hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
@@ -2271,6 +2279,8 @@ static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *start, flo
}
return hit;
#endif
return 0;
}
static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
@@ -2387,8 +2397,9 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
for(sign=-1; sign<=1; sign+=2) {
memset(&isec, 0, sizeof(isec));
isec.mode= RE_RAY_MIRROR;
isec.faceorig= (RayFace*)vlr;
isec.oborig= RAY_OBJECT_SET(&R, obi);
isec.orig.ob = obi;
isec.orig.face = vlr;
isec.userdata= bs;
if(bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
@@ -2412,8 +2423,8 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
/* if hit, we shade from the new point, otherwise from point one starting face */
if(hit) {
vlr= (VlakRen*)minisec.face;
obi= RAY_OBJECT_GET(&R, minisec.ob);
obi= (ObjectInstanceRen*)minisec.hit.ob;
vlr= (VlakRen*)minisec.hit.face;
quad= (minisec.isect == 2);
VECCOPY(shi->co, minco);