*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:
@@ -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));
|
||||
|
||||
126
source/blender/render/extern/include/RE_raytrace.h
vendored
126
source/blender/render/extern/include/RE_raytrace.h
vendored
@@ -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__*/
|
||||
|
||||
|
||||
122
source/blender/render/intern/include/rayobject.h
Normal file
122
source/blender/render/intern/include/rayobject.h
Normal 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
|
||||
@@ -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];
|
||||
|
||||
|
||||
276
source/blender/render/intern/source/rayobject.c
Normal file
276
source/blender/render/intern/source/rayobject.c
Normal 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 );
|
||||
}
|
||||
}
|
||||
|
||||
128
source/blender/render/intern/source/rayobject_mesh.c
Normal file
128
source/blender/render/intern/source/rayobject_mesh.c
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user