diff options
32 files changed, 1172 insertions, 1046 deletions
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 94eed530ad6..853e9e108d6 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -374,6 +374,7 @@ Scene *add_scene(const char *name) sce->r.fg_stamp[3]= 1.0f; sce->r.bg_stamp[0]= sce->r.bg_stamp[1]= sce->r.bg_stamp[2]= 0.0f; sce->r.bg_stamp[3]= 0.25f; + sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES; sce->r.seq_prev_type= OB_SOLID; sce->r.seq_rend_type= OB_SOLID; diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 58aad270583..ee99e3af3b9 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -43,9 +43,14 @@ set(INC set(SRC intern/raytrace/rayobject.cpp + intern/raytrace/rayobject_empty.cpp + intern/raytrace/rayobject_octree.cpp + intern/raytrace/rayobject_raycounter.cpp + intern/raytrace/rayobject_svbvh.cpp + intern/raytrace/rayobject_blibvh.cpp + intern/raytrace/rayobject_instance.cpp intern/raytrace/rayobject_qbvh.cpp intern/raytrace/rayobject_rtbuild.cpp - intern/raytrace/rayobject_svbvh.cpp intern/raytrace/rayobject_vbvh.cpp intern/source/convertblender.c intern/source/envmap.c @@ -57,10 +62,6 @@ set(SRC intern/source/pixelblending.c intern/source/pixelshading.c intern/source/pointdensity.c - intern/source/rayobject_blibvh.c - intern/source/rayobject_instance.c - intern/source/rayobject_octree.c - intern/source/rayobject_raycounter.c intern/source/rayshade.c intern/source/rendercore.c intern/source/render_texture.c @@ -77,7 +78,6 @@ set(SRC intern/source/zbuf.c extern/include/RE_pipeline.h - extern/include/RE_raytrace.h extern/include/RE_render_ext.h extern/include/RE_shader_ext.h intern/include/envmap.h @@ -89,6 +89,8 @@ set(SRC intern/include/pointdensity.h intern/include/raycounter.h intern/include/rayobject.h + intern/include/rayintersection.h + intern/include/raycounter.h intern/include/render_types.h intern/include/rendercore.h intern/include/renderdatabase.h diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h deleted file mode 100644 index cf463c0795e..00000000000 --- a/source/blender/render/extern/include/RE_raytrace.h +++ /dev/null @@ -1,217 +0,0 @@ -/** - * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2007 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): André Pinto. - * - * ***** END GPL LICENSE BLOCK ***** - * RE_raytrace.h: ray tracing api, can be used independently from the renderer. - */ - -#ifndef RE_RAYTRACE_H -#define RE_RAYTRACE_H - -#ifdef __cplusplus -extern "C" { -#endif - -// #define RE_RAYCOUNTER /* enable counters per ray, usefull for measuring raytrace structures performance */ - -#define RE_RAY_LCTS_MAX_SIZE 256 -#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */ -//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */ - -#ifdef RE_RAYCOUNTER - -typedef struct RayCounter RayCounter; -struct RayCounter -{ - - struct - { - unsigned long long test, hit; - - } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit; -}; -#endif - -/* Internals about raycasting structures can be found on intern/raytree.h */ -typedef struct RayObject RayObject; -typedef struct Isect Isect; -typedef struct RayHint RayHint; -typedef struct RayTraceHint RayTraceHint; - -struct DerivedMesh; -struct Mesh; -struct VlakRen; -struct ObjectInstanceRen; - -int RE_rayobject_raycast(RayObject *r, Isect *i); -void RE_rayobject_add (RayObject *r, RayObject *); -void RE_rayobject_done(RayObject *r); -void RE_rayobject_free(RayObject *r); - -/* Extend min/max coords so that the rayobject is inside them */ -void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max); - -/* initializes an hint for optiming raycast where it is know that a ray will pass by the given BB often the origin point */ -void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max); - -/* initializes an hint for optiming raycast where it is know that a ray will be contained inside the given cone*/ -/* void RE_rayobject_hint_cone(RayObject *r, RayHint *hint, float *); */ - -/* RayObject constructors */ -RayObject* RE_rayobject_octree_create(int ocres, int size); -RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob); -RayObject* RE_rayobject_empty_create(void); - -RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */ -RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */ -RayObject* RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */ -RayObject* RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */ - - -/* - * This ray object represents a triangle or a quad face. - * All data needed to realize intersection is "localy" available. - */ -typedef struct RayFace -{ - float v1[4], v2[4], v3[4], v4[3]; - int quad; - void *ob; - void *face; - -} RayFace; - -#define RE_rayface_isQuad(a) ((a)->quad) - -RayObject* RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr); -RayObject* RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *co1, float *co2, float *co3, float *co4); - - -/* - * This ray object represents faces directly from a given VlakRen structure. - * Thus allowing to save memory, but making code triangle intersection dependant on render structures - */ -typedef struct VlakPrimitive -{ - struct ObjectInstanceRen *ob; - struct VlakRen *face; -} VlakPrimitive; - -RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr); - - - -/* - * Raytrace hints - */ -typedef struct LCTSHint LCTSHint; -struct LCTSHint -{ - int size; - RayObject *stack[RE_RAY_LCTS_MAX_SIZE]; -}; - -struct RayHint -{ - union - { - LCTSHint lcts; - } data; -}; - - -/* Ray Intersection */ -struct Isect -{ - float start[3]; - float vec[3]; - float labda; - - /* length of vec, configured by RE_rayobject_raycast */ - int bv_index[6]; - float idot_axis[3]; - float dist; - -/* float end[3]; - not used */ - - float u, v; - - struct - { - void *ob; - void *face; - } - hit, orig; - - RayObject *last_hit; /* last hit optimization */ - -#ifdef RT_USE_HINT - RayTraceHint *hint, *hit_hint; -#endif - - 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 */ - int check; - - float col[4]; /* RGBA for shadow_tra */ - - void *userdata; - - RayHint *hint; - -#ifdef RE_RAYCOUNTER - RayCounter *raycounter; -#endif -}; - -/* ray types */ -#define RE_RAY_SHADOW 0 -#define RE_RAY_MIRROR 1 -#define RE_RAY_SHADOW_TRA 2 - -/* skip options */ -#define RE_SKIP_CULLFACE (1 << 0) -/* if using this flag then *face should be a pointer to a VlakRen */ -#define RE_SKIP_VLR_NEIGHBOUR (1 << 1) - -/* check options */ -#define RE_CHECK_VLR_NONE 0 -#define RE_CHECK_VLR_RENDER 1 -#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2 -#define RE_CHECK_VLR_BAKE 3 - -/* TODO use: FLT_MAX? */ -#define RE_RAYTRACE_MAXDIST 1e33 - -#ifdef __cplusplus -} -#endif - - -#endif /*__RE_RAYTRACE_H__*/ diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 26e34a741f7..2b451810e37 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -30,7 +30,6 @@ #ifndef RE_SHADER_EXT_H #define RE_SHADER_EXT_H -#include "RE_raytrace.h" /* For RE_RAYCOUNTER */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* this include is for shading and texture exports */ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h index 5377a1147af..1a9b91c17a8 100644 --- a/source/blender/render/intern/include/raycounter.h +++ b/source/blender/render/intern/include/raycounter.h @@ -26,16 +26,27 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifndef RE_RAYCOUNTER_H #define RE_RAYCOUNTER_H -#include "RE_raytrace.h" +//#define RE_RAYCOUNTER /* enable counters per ray, usefull for measuring raytrace structures performance */ +#ifdef __cplusplus +extern "C" { +#endif #ifdef RE_RAYCOUNTER -/* #define RE_RC_INIT(isec, shi) (isec).count = re_rc_counter+(shi).thread */ -#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).raycounter) +/* ray counter functions */ + +typedef struct RayCounter { + struct { + unsigned long long test, hit; + } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit; +} RayCounter; + +#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter) void RE_RC_INFO (RayCounter *rc); void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp); #define RE_RC_COUNT(var) (var)++ @@ -44,12 +55,17 @@ extern RayCounter re_rc_counter[]; #else -# define RE_RC_INIT(isec,shi) -# define RE_RC_INFO(rc) -# define RE_RC_MERGE(dest,src) -# define RE_RC_COUNT(var) +/* ray counter stubs */ + +#define RE_RC_INIT(isec,shi) +#define RE_RC_INFO(rc) +#define RE_RC_MERGE(dest,src) +#define RE_RC_COUNT(var) #endif +#ifdef __cplusplus +} +#endif #endif diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h new file mode 100644 index 00000000000..5a8b989abbc --- /dev/null +++ b/source/blender/render/intern/include/rayintersection.h @@ -0,0 +1,124 @@ +/** + * $Id: rayintersection.h 29491 2010-06-16 18:57:23Z blendix $ + * + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + * RE_raytrace.h: ray tracing api, can be used independently from the renderer. + */ + +#ifndef __RENDER_RAYINTERSECTION_H__ +#define __RENDER_RAYINTERSECTION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct RayObject; + +/* Ray Hints */ + +#define RE_RAY_LCTS_MAX_SIZE 256 +#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */ +//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */ + +typedef struct LCTSHint { + int size; + struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE]; +} LCTSHint; + +typedef struct RayHint { + union { LCTSHint lcts; } data; +} RayHint; + +/* Ray Intersection */ + +typedef struct Isect { + /* ray start, direction (normalized vector), and max distance. on hit, + the distance is modified to be the distance to the hit point. */ + float start[3]; + float dir[3]; + float dist; + + /* precomputed values to accelerate bounding box intersection */ + int bv_index[6]; + float idot_axis[3]; + + /* intersection options */ + int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */ + int lay; /* -1 default, set for layer lamps */ + int skip; /* skip flags */ + int check; /* check flags */ + void *userdata; /* used by bake check */ + + /* hit information */ + float u, v; + int isect; /* which half of quad */ + + struct { + void *ob; + void *face; + } hit, orig; + + /* last hit optimization */ + struct RayObject *last_hit; + + /* hints */ +#ifdef RT_USE_HINT + RayTraceHint *hint, *hit_hint; +#endif + RayHint *hint; + + /* ray counter */ +#ifdef RE_RAYCOUNTER + RayCounter *raycounter; +#endif +} Isect; + +/* ray types */ +#define RE_RAY_SHADOW 0 +#define RE_RAY_MIRROR 1 +#define RE_RAY_SHADOW_TRA 2 + +/* skip options */ +#define RE_SKIP_CULLFACE (1 << 0) +/* if using this flag then *face should be a pointer to a VlakRen */ +#define RE_SKIP_VLR_NEIGHBOUR (1 << 1) + +/* check options */ +#define RE_CHECK_VLR_NONE 0 +#define RE_CHECK_VLR_RENDER 1 +#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2 +#define RE_CHECK_VLR_BAKE 3 + +/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */ +#define RE_RAYTRACE_MAXDIST 1e15f +#define RE_RAYTRACE_EPSILON 0.0f + +#ifdef __cplusplus +} +#endif + +#endif /* __RENDER_RAYINTERSECTION_H__ */ + diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h index e16ec83fb61..61b7a23cf54 100644 --- a/source/blender/render/intern/include/rayobject.h +++ b/source/blender/render/intern/include/rayobject.h @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifndef RE_RAYOBJECT_H #define RE_RAYOBJECT_H @@ -33,176 +34,86 @@ extern "C" { #endif -#include "RE_raytrace.h" -#include "render_types.h" -#include <stdio.h> -#include <float.h> - +struct Isect; +struct ObjectInstanceRen; +struct RayHint; +struct VlakRen; /* 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 0x03) to define the - type of RayObject. - - This leads to 4 possible types of RayObject: - - addr&3 - type of object - 0 Self (reserved for each structure) - 1 RayFace (tri/quad primitive) - 2 RayObject (generic with API callbacks) - 3 VlakPrimitive - (vlak primitive - to be used when we have a vlak describing the data - eg.: on render code) - - 0 means it's reserved and has it own meaning inside each ray acceleration structure - (this way each structure can use the allign offset to determine if a node represents a - RayObject primitive, which can be used to save memory) - - You actually don't need to care about this if you are only using the API - described on RE_raytrace.h - */ -/* used to align a given ray object */ -#define RE_rayobject_align(o) ((RayObject*)(((intptr_t)o)&(~3))) - -/* used to unalign a given ray object */ -#define RE_rayobject_unalignRayFace(o) ((RayObject*)(((intptr_t)o)|1)) -#define RE_rayobject_unalignRayAPI(o) ((RayObject*)(((intptr_t)o)|2)) -#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject*)(((intptr_t)o)|3)) - -/* used to test the type of ray object */ -#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0) -#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1) -#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2) -#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3) - - - -/* - * This class is intended as a place holder for control, configuration of the rayobject like: - * - stop building (TODO maybe when porting build to threads this could be implemented with some thread_cancel function) - * - max number of threads and threads callback to use during build - * ... - */ -typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data); -typedef struct RayObjectControl RayObjectControl; -struct RayObjectControl -{ - void *data; - RE_rayobjectcontrol_test_break_callback test_break; -}; - -/* - * This rayobject represents a generic object. With it's own callbacks for raytrace operations. - * It's suitable to implement things like LOD. - */ -struct RayObject -{ - struct RayObjectAPI *api; - - struct RayObjectControl control; -}; + Can be a face/triangle, bvh tree, object instance, etc. This is the + public API used by the renderer, see rayobject_internal.h for the + internal implementation details. */ +typedef struct RayObject RayObject; +/* Intersection, see rayintersection.h */ +int RE_rayobject_raycast(RayObject *r, struct Isect *i); -typedef int (*RE_rayobject_raycast_callback)(RayObject *, Isect *); -typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject); -typedef void (*RE_rayobject_done_callback)(RayObject *); -typedef void (*RE_rayobject_free_callback)(RayObject *); -typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float *min, float *max); -typedef float (*RE_rayobject_cost_callback)(RayObject *); -typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, RayHint *, float *, float *); +/* Acceleration Structures */ -typedef struct RayObjectAPI -{ - RE_rayobject_raycast_callback raycast; - RE_rayobject_add_callback add; - RE_rayobject_done_callback done; - RE_rayobject_free_callback free; - RE_rayobject_merge_bb_callback bb; - RE_rayobject_cost_callback cost; - RE_rayobject_hint_bb_callback hint_bb; - -} RayObjectAPI; +RayObject* RE_rayobject_octree_create(int ocres, int size); +RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob); +RayObject* RE_rayobject_empty_create(); +RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */ +RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */ +RayObject* RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */ +RayObject* RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */ -/* - * This function differs from RE_rayobject_raycast - * RE_rayobject_intersect does NOT perform last-hit optimization - * So this is probably a function to call inside raytrace structures - */ -int RE_rayobject_intersect(RayObject *r, Isect *i); +/* Building */ -/* - * Returns distance ray must travel to hit the given bounding box - * BB should be in format [2][3] - */ -/* float RE_rayobject_bb_intersect(const Isect *i, const float *bb); */ -int RE_rayobject_bb_intersect_test(const Isect *i, const float *bb); /* same as bb_intersect but doens't calculates distance */ +void RE_rayobject_add(RayObject *r, RayObject *); +void RE_rayobject_done(RayObject *r); +void RE_rayobject_free(RayObject *r); -/* - * Returns the expected cost of raycast on this node, primitives have a cost of 1 - */ -float RE_rayobject_cost(RayObject *r); +void RE_rayobject_set_control(RayObject *r, void *data, int (*test_break)(void *data)); +/* RayObject representing faces, all data is locally available instead + of referring to some external data structure, for possibly faster + intersection tests. */ -/* - * Returns true if for some reason a heavy processing function should stop - * (eg.: user asked to stop during a tree a build) - */ -int RE_rayobjectcontrol_test_break(RayObjectControl *c); +typedef struct RayFace { + float v1[4], v2[4], v3[4], v4[3]; + int quad; + void *ob; + void *face; +} RayFace; +#define RE_rayface_isQuad(a) ((a)->quad) -#define ISECT_EPSILON ((float)FLT_EPSILON) +RayObject* RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr); +/* RayObject representing faces directly from a given VlakRen structure. Thus + allowing to save memory, but making code triangle intersection dependant on + render structures. */ +typedef struct VlakPrimitive { + struct ObjectInstanceRen *ob; + struct VlakRen *face; +} VlakPrimitive; -#if !defined(_WIN32) && !defined(_WIN64) +RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr); -#include <sys/time.h> -#include <time.h> +/* Bounding Box */ -#define BENCH(a,name) \ - { \ - double _t1, _t2; \ - struct timeval _tstart, _tend; \ - clock_t _clock_init = clock(); \ - gettimeofday ( &_tstart, NULL); \ - (a); \ - gettimeofday ( &_tend, NULL); \ - _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 ); \ - _t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 ); \ - printf("BENCH:%s: %fs (real) %fs (cpu)\n", #name, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\ - } -#else +/* extend min/max coords so that the rayobject is inside them */ +void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max); -#define BENCH(a,name) (a) +/* initializes an hint for optiming raycast where it is know that a ray will pass by the given BB often the origin point */ +void RE_rayobject_hint_bb(RayObject *r, struct RayHint *hint, float *min, float *max); -#endif +/* initializes an hint for optiming raycast where it is know that a ray will be contained inside the given cone*/ +/* void RE_rayobject_hint_cone(RayObject *r, struct RayHint *hint, float *); */ +/* Internals */ +#include "../raytrace/rayobject_internal.h" #ifdef __cplusplus } #endif - #endif + diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 84fa7e931b2..a599b1306fb 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -607,6 +607,7 @@ typedef struct LampRen { #define R_DIVIDE_24 32 /* vertex normals are tangent or view-corrected vector, for hair strands */ #define R_TANGENT 64 +#define R_TRACEBLE 128 /* strandbuffer->flag */ #define R_STRAND_BSPLINE 1 diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index e9e30f64fdd..3b0929bbe27 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -48,6 +48,7 @@ struct RenderPart; struct RenderLayer; struct ObjectRen; struct ListBase; +struct RayObject; /* ------------------------------------------------------------------------- */ @@ -95,7 +96,7 @@ int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct Rend extern void freeraytree(Render *re); extern void makeraytree(Render *re); -RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi); +struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi); extern void ray_shadow(ShadeInput *, LampRen *, float *); extern void ray_trace(ShadeInput *, ShadeResult *); diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h index 37b1bd7ca29..827aaf3672c 100644 --- a/source/blender/render/intern/include/volumetric.h +++ b/source/blender/render/intern/include/volumetric.h @@ -26,6 +26,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +struct Isect; +struct ShadeInput; +struct ShadeResult; + float vol_get_density(struct ShadeInput *shi, float *co); void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co_); diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h index c31d1213b99..dd23967297a 100644 --- a/source/blender/render/intern/raytrace/bvh.h +++ b/source/blender/render/intern/raytrace/bvh.h @@ -26,12 +26,16 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#include "rayobject.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + #include "raycounter.h" -#include "rayobject_rtbuild.h" +#include "rayintersection.h" +#include "rayobject.h" #include "rayobject_hint.h" - -#include "BLI_utildefines.h" +#include "rayobject_rtbuild.h" #include <assert.h> @@ -45,21 +49,49 @@ #ifdef __SSE__ inline int test_bb_group4(__m128 *bb_group, const Isect *isec) { - const __m128 tmin0 = _mm_setzero_ps(); - const __m128 tmax0 = _mm_load1_ps(&isec->labda); - - const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[0]], _mm_load1_ps(&isec->start[0]) ), _mm_load1_ps(&isec->idot_axis[0])) ); - const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[1]], _mm_load1_ps(&isec->start[0]) ), _mm_load1_ps(&isec->idot_axis[0])) ); - const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[2]], _mm_load1_ps(&isec->start[1]) ), _mm_load1_ps(&isec->idot_axis[1])) ); - const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[3]], _mm_load1_ps(&isec->start[1]) ), _mm_load1_ps(&isec->idot_axis[1])) ); - const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[4]], _mm_load1_ps(&isec->start[2]) ), _mm_load1_ps(&isec->idot_axis[2])) ); - const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[5]], _mm_load1_ps(&isec->start[2]) ), _mm_load1_ps(&isec->idot_axis[2])) ); + const __m128 tmax0 = _mm_set_ps1(isec->dist); + + float start[3], idot_axis[3]; + copy_v3_v3(start, isec->start); + copy_v3_v3(idot_axis, isec->idot_axis); + + const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) ); + const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) ); + const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) ); + const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) ); + const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) ); + const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) ); return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3)); } #endif +/* + * Determines the distance that the ray must travel to hit the bounding volume of the given node + * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe + * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9] + */ +static int rayobject_bb_intersect_test(const Isect *isec, const float *_bb) +{ + const float *bb = _bb; + + float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; + float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; + float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; + float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; + float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; + float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; + + RE_RC_COUNT(isec->raycounter->bb.test); + + if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; + if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0; + if(t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0; + RE_RC_COUNT(isec->raycounter->bb.hit); + + return 1; +} /* bvh tree generics */ template<class Tree> static int bvh_intersect(Tree *obj, Isect *isec); @@ -108,7 +140,7 @@ static float bvh_cost(Tree *obj) /* bvh tree nodes generics */ template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec) { - return RE_rayobject_bb_intersect_test(isec, (const float*)node->bb); + return rayobject_bb_intersect_test(isec, (const float*)node->bb); } @@ -133,7 +165,7 @@ static inline void bvh_node_merge_bb(Node *node, float *min, float *max) */ template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos); -template<class Node,int MAX_STACK_SIZE,bool TEST_ROOT> +template<class Node,int MAX_STACK_SIZE,bool TEST_ROOT,bool SHADOW> static int bvh_node_stack_raycast(Node *root, Isect *isec) { Node *stack[MAX_STACK_SIZE]; @@ -158,7 +190,7 @@ static int bvh_node_stack_raycast(Node *root, Isect *isec) else { hit |= RE_rayobject_intersect( (RayObject*)node, isec); - if(hit && isec->mode == RE_RAY_SHADOW) return hit; + if(SHADOW && hit) return hit; } } return hit; diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index c267b89fc2c..dd4932f0bd9 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -22,135 +22,90 @@ * * The Original Code is: all of this file. * - * Contributor(s): Andr Pinto. + * Contributor(s): André Pinto. * * ***** END GPL LICENSE BLOCK ***** */ + #include <assert.h> +#include "MEM_guardedalloc.h" + #include "BLI_math.h" #include "BLI_utildefines.h" - - #include "DNA_material_types.h" -#include "RE_raytrace.h" - -#include "render_types.h" +#include "rayintersection.h" #include "rayobject.h" #include "raycounter.h" +#include "render_types.h" -/* - * Determines the distance that the ray must travel to hit the bounding volume of the given node - * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe - * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9] - */ -int RE_rayobject_bb_intersect_test(const Isect *isec, const float *_bb) -{ - const float *bb = _bb; - - float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; - float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; - float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; - float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; - float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; - float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; - - RE_RC_COUNT(isec->raycounter->bb.test); - - if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; - if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0; - if(t1x > isec->labda || t1y > isec->labda || t1z > isec->labda) return 0; - RE_RC_COUNT(isec->raycounter->bb.hit); - - return 1; -} +/* RayFace + note we force always inline here, because compiler refuses to otherwise + because function is too long. Since this is code that is called billions + of times we really do want to inline. */ -/* only for self-intersecting test with current render face (where ray left) */ -static int intersection2(VlakRen *face, float r0, float r1, float r2, float rx1, float ry1, float rz1) +MALWAYS_INLINE RayObject* rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4) { - float 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; + rayface->ob = ob; + rayface->face = face; + + copy_v3_v3(rayface->v1, v1); + copy_v3_v3(rayface->v2, v2); + copy_v3_v3(rayface->v3, v3); - VECCOPY(co1, face->v1->co); - VECCOPY(co2, face->v2->co); - if(face->v4) + if(v4) { - VECCOPY(co3, face->v4->co); - VECCOPY(co4, face->v3->co); + copy_v3_v3(rayface->v4, v4); + rayface->quad = 1; } else { - VECCOPY(co3, face->v3->co); + rayface->quad = 0; } - 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; + return RE_rayobject_unalignRayFace(rayface); +} - 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; +MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0); - 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(obi->transform_primitives) + { + mul_m4_v3(obi->mat, rayface->v1); + mul_m4_v3(obi->mat, rayface->v2); + mul_m4_v3(obi->mat, rayface->v3); - if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) { - return 1; - } - } + if(RE_rayface_isQuad(rayface)) + mul_m4_v3(obi->mat, rayface->v4); } +} - if(face->v4) { +RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0); +} - t20= co3[0]-co4[0]; - t21= co3[1]-co4[1]; - t22= co3[2]-co4[2]; +/* VlakPrimitive */ - 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; +RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr) +{ + face->ob = obi; + face->face = vlr; + + return RE_rayobject_unalignVlakPrimitive(face); } -static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr) +/* Checks for ignoring faces or materials */ + +MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr) { /* for baking selected to active non-traceable materials might still * be in the raytree */ - if(!(vlr->mat->mode & MA_TRACEBLE)) + if(!(vlr->flag & R_TRACEBLE)) return 0; /* I know... cpu cycle waste, might do smarter once */ @@ -160,7 +115,7 @@ static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen return (is->lay & obi->lay); } -static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) +MALWAYS_INLINE int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) { /* solid material types only */ if (vlr->mat->material_type == MA_TYPE_SURFACE) @@ -169,168 +124,223 @@ static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, V return 0; } -static inline int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) +MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr) { return (obi->obr->ob != is->userdata); } -static inline int rayface_check_cullface(RayFace *face, Isect *is) -{ - float nor[3]; - - /* don't intersect if the ray faces along the face normal */ - if(face->quad) normal_quad_v3( nor,face->v1, face->v2, face->v3, face->v4); - else normal_tri_v3( nor,face->v1, face->v2, face->v3); - - return (INPR(nor, is->vec) < 0); -} +/* Ray Triangle/Quad Intersection */ -/* ray - triangle or quad intersection */ -/* this function shall only modify Isect if it detects an hit */ -static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) +MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda) { - float co1[3],co2[3],co3[3],co4[3]={0}; - float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2; - float m0, m1, m2, divdet, det1; - float labda, u, v; - short ok=0; - - if(is->orig.ob == face->ob && is->orig.face == face->face) - return 0; - - /* check if we should intersect this face */ - if(is->check == RE_CHECK_VLR_RENDER) - { - if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - } - else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) - { - if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) - return 0; - } - else if(is->check == RE_CHECK_VLR_BAKE) { - if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0) - return 0; - } + float co1[3], co2[3], co3[3], co4[3]; + float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l; + int quad; - if(is->skip & RE_SKIP_CULLFACE) - { - if(rayface_check_cullface(face, is) == 0) - return 0; - } + quad= RE_rayface_isQuad(face); - RE_RC_COUNT(is->raycounter->faces.test); + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); - //Load coords - VECCOPY(co1, face->v1); - VECCOPY(co2, face->v2); - if(RE_rayface_isQuad(face)) - { - VECCOPY(co3, face->v4); - VECCOPY(co4, face->v3); - } - else - { - VECCOPY(co3, face->v3); - } + copy_v3_v3(r, dir); - 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; + /* intersect triangle */ + sub_v3_v3v3(t0, co3, co2); + sub_v3_v3v3(t1, co3, co1); - divdet= t00*x0+t01*x1+t02*x2; + cross_v3_v3v3(x, r, t1); + divdet= dot_v3v3(t0, x); - 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; + sub_v3_v3v3(m, start, co3); + det1= dot_v3v3(m, x); - if(divdet!=0.0f) { - + if(divdet != 0.0f) { divdet= 1.0f/divdet; - u= det1*divdet; - if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) { - float 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); + v= det1*divdet; - if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) { - labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; - if(labda>-ISECT_EPSILON && labda<is->labda) { - ok= 1; + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { + l= divdet*dot_v3v3(cros, t1); + + /* check if intersection is within ray length */ + if(l > -RE_RAYTRACE_EPSILON && l < *lambda) { + uv[0]= u; + uv[1]= v; + *lambda= l; + return 1; } } } } - if(ok==0 && RE_rayface_isQuad(face)) { - - t20= co3[0]-co4[0]; - t21= co3[1]-co4[1]; - t22= co3[2]-co4[2]; + /* intersect second triangle in quad */ + if(quad) { + copy_v3_v3(co4, face->v4); + sub_v3_v3v3(t0, co3, co4); + divdet= dot_v3v3(t0, x); - divdet= t20*x0+t21*x1+t22*x2; - if(divdet!=0.0f) { + if(divdet != 0.0f) { divdet= 1.0f/divdet; - u = det1*divdet; + v = det1*divdet; - if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) { - float 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 < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); - if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) { - labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) { + l= divdet*dot_v3v3(cros, t1); - if(labda>-ISECT_EPSILON && labda<is->labda) { - ok= 2; + if(l >- RE_RAYTRACE_EPSILON && l < *lambda) { + uv[0]= u; + uv[1]= -(1.0f + v + u); + *lambda= l; + return 2; } } } } } + return 0; +} + +/* Simpler yes/no Ray Triangle/Quad Intersection */ + +MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face) +{ + float co1[3], co2[3], co3[3], co4[3]; + float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1; + int quad; + + quad= RE_rayface_isQuad(face); + + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); + + negate_v3_v3(r, dir); /* note, different than above function */ + + /* intersect triangle */ + sub_v3_v3v3(t0, co3, co2); + sub_v3_v3v3(t1, co3, co1); + + cross_v3_v3v3(x, r, t1); + divdet= dot_v3v3(t0, x); + + sub_v3_v3v3(m, start, co3); + det1= dot_v3v3(m, x); + + if(divdet != 0.0f) { + divdet= 1.0f/divdet; + v= det1*divdet; + + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) + return 1; + } + } + + /* intersect second triangle in quad */ + if(quad) { + copy_v3_v3(co4, face->v4); + sub_v3_v3v3(t0, co3, co4); + divdet= dot_v3v3(t0, x); + + if(divdet != 0.0f) { + divdet= 1.0f/divdet; + v = det1*divdet; + + if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) { + float cros[3]; + + cross_v3_v3v3(cros, m, t0); + u= divdet*dot_v3v3(cros, r); + + if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) + return 2; + } + } + } + + return 0; +} + +/* RayFace intersection with checks and neighbour verifaction included, + Isect is modified if the face is hit. */ + +MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) +{ + float dist, uv[2]; + int ok= 0; + + /* avoid self-intersection */ + if(is->orig.ob == face->ob && is->orig.face == face->face) + return 0; + + /* check if we should intersect this face */ + if(is->check == RE_CHECK_VLR_RENDER) + { + if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) + { + if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + else if(is->check == RE_CHECK_VLR_BAKE) { + if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0) + return 0; + } + + /* ray counter */ + RE_RC_COUNT(is->raycounter->faces.test); + + dist= is->dist; + ok= isec_tri_quad(is->start, is->dir, face, uv, &dist); + if(ok) { - /* 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 */ + /* 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->skip & RE_SKIP_VLR_NEIGHBOUR) { - if(labda < 0.1f && is->orig.ob == face->ob) + if(dist < 0.1f && is->orig.ob == face->ob) { VlakRen * a = (VlakRen*)is->orig.face; VlakRen * b = (VlakRen*)face->face; - /* 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 */ + /* 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(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1 || a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2 || a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3 - || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) - if(!intersection2((VlakRen*)a, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2])) - { - return 0; + || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) { + /* create RayFace from original face, transformed if necessary */ + RayFace origface; + ObjectInstanceRen *ob= (ObjectInstanceRen*)is->orig.ob; + rayface_from_vlak(&origface, ob, (VlakRen*)is->orig.face); + + if(!isec_tri_quad_neighbour(is->start, is->dir, &origface)) + { + return 0; + } } } } @@ -338,8 +348,8 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) RE_RC_COUNT(is->raycounter->faces.hit); is->isect= ok; // which half of the quad - is->labda= labda; - is->u= u; is->v= v; + is->dist= dist; + is->u= uv[0]; is->v= uv[1]; is->hit.ob = face->ob; is->hit.face = face->face; @@ -352,51 +362,18 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) return 0; } -RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) -{ - return RE_rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0 ); -} - -RayObject* RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4) -{ - rayface->ob = ob; - rayface->face = face; - - VECCOPY(rayface->v1, v1); - VECCOPY(rayface->v2, v2); - VECCOPY(rayface->v3, v3); - if(v4) - { - VECCOPY(rayface->v4, v4); - rayface->quad = 1; - } - else - { - rayface->quad = 0; - } - - return RE_rayobject_unalignRayFace(rayface); -} - -RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr) -{ - face->ob = obi; - face->face = vlr; - return RE_rayobject_unalignVlakPrimitive(face); -} - +/* Intersection */ int RE_rayobject_raycast(RayObject *r, Isect *isec) { int i; + RE_RC_COUNT(isec->raycounter->raycast.test); - /* Setup vars used on raycast */ - isec->dist = len_v3(isec->vec); - + /* setup vars used on raycast */ for(i=0; i<3; i++) { - isec->idot_axis[i] = 1.0f / isec->vec[i]; + isec->idot_axis[i] = 1.0f / isec->dir[i]; isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0; isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i]; @@ -406,7 +383,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) } #ifdef RT_USE_LAST_HIT - /* Last hit heuristic */ + /* last hit heuristic */ if(isec->mode==RE_RAY_SHADOW && isec->last_hit) { RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test); @@ -433,6 +410,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) #endif return 1; } + return 0; } @@ -447,103 +425,93 @@ int RE_rayobject_intersect(RayObject *r, Isect *i) //TODO optimize (useless copy to RayFace to avoid duplicate code) VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r); RayFace nface; - RE_rayface_from_vlak(&nface, face->ob, face->face); - - if(face->ob->transform_primitives) - { - mul_m4_v3(face->ob->mat, nface.v1); - mul_m4_v3(face->ob->mat, nface.v2); - mul_m4_v3(face->ob->mat, nface.v3); - if(RE_rayface_isQuad(&nface)) - mul_m4_v3(face->ob->mat, nface.v4); - } + rayface_from_vlak(&nface, face->ob, face->face); return intersect_rayface(r, &nface, i); } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - return r->api->raycast( r, i ); + r = RE_rayobject_align(r); + return r->api->raycast(r, i); + } + else { + assert(0); + return 0; } - else assert(0); - return 0; /* wont reach this, quiet compilers */ } +/* Building */ + void RE_rayobject_add(RayObject *r, RayObject *o) { - r = RE_rayobject_align( r ); - return r->api->add( r, o ); + r = RE_rayobject_align(r); + return r->api->add(r, o); } void RE_rayobject_done(RayObject *r) { - r = RE_rayobject_align( r ); - r->api->done( r ); + r = RE_rayobject_align(r); + r->api->done(r); } void RE_rayobject_free(RayObject *r) { - r = RE_rayobject_align( r ); - r->api->free( r ); + r = RE_rayobject_align(r); + r->api->free(r); } +float RE_rayobject_cost(RayObject *r) +{ + if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) + { + return 1.0f; + } + else if(RE_rayobject_isRayAPI(r)) + { + r = RE_rayobject_align(r); + return r->api->cost(r); + } + else { + assert(0); + return 1.0f; + } +} + +/* Bounding Boxes */ + void RE_rayobject_merge_bb(RayObject *r, float *min, float *max) { if(RE_rayobject_isRayFace(r)) { RayFace *face = (RayFace*) RE_rayobject_align(r); - DO_MINMAX( face->v1, min, max ); - DO_MINMAX( face->v2, min, max ); - DO_MINMAX( face->v3, min, max ); - if(RE_rayface_isQuad(face)) DO_MINMAX( face->v4, min, max ); + DO_MINMAX(face->v1, min, max); + DO_MINMAX(face->v2, min, max); + DO_MINMAX(face->v3, min, max); + if(RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max); } else if(RE_rayobject_isVlakPrimitive(r)) { VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r); RayFace nface; - RE_rayface_from_vlak(&nface, face->ob, face->face); - - if(face->ob->transform_primitives) - { - mul_m4_v3(face->ob->mat, nface.v1); - mul_m4_v3(face->ob->mat, nface.v2); - mul_m4_v3(face->ob->mat, nface.v3); - if(RE_rayface_isQuad(&nface)) - mul_m4_v3(face->ob->mat, nface.v4); - } - - DO_MINMAX( nface.v1, min, max ); - DO_MINMAX( nface.v2, min, max ); - DO_MINMAX( nface.v3, min, max ); - if(RE_rayface_isQuad(&nface)) DO_MINMAX( nface.v4, min, max ); - } - else if(RE_rayobject_isRayAPI(r)) - { - r = RE_rayobject_align( r ); - r->api->bb( r, min, max ); - } - else assert(0); -} + rayface_from_vlak(&nface, face->ob, face->face); -float RE_rayobject_cost(RayObject *r) -{ - if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) - { - return 1.0; + DO_MINMAX(nface.v1, min, max); + DO_MINMAX(nface.v2, min, max); + DO_MINMAX(nface.v3, min, max); + if(RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max); } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - return r->api->cost( r ); + r = RE_rayobject_align(r); + r->api->bb(r, min, max); } else - { assert(0); - return 1.0; /* XXX, better default value? */ - } } +/* Hints */ + void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max) { if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) @@ -552,60 +520,30 @@ void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max) } else if(RE_rayobject_isRayAPI(r)) { - r = RE_rayobject_align( r ); - return r->api->hint_bb( r, hint, min, max ); + r = RE_rayobject_align(r); + return r->api->hint_bb(r, hint, min, max); } - else assert(0); + else + assert(0); } +/* RayObjectControl */ + int RE_rayobjectcontrol_test_break(RayObjectControl *control) { if(control->test_break) - return control->test_break( control->data ); + return control->test_break(control->data); return 0; } - -/* - * Empty raytree - */ -static int RE_rayobject_empty_intersect(RayObject *o, Isect *is) +void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break) { - return 0; -} - -static void RE_rayobject_empty_free(RayObject *o) -{ -} - -static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max) -{ - return; -} - -static float RE_rayobject_empty_cost(RayObject *o) -{ - return 0.0; + if(RE_rayobject_isRayAPI(r)) + { + r = RE_rayobject_align(r); + r->control.data = data; + r->control.test_break = test_break; + } } -static void RE_rayobject_empty_hint_bb(RayObject *o, RayHint *hint, float *min, float *max) -{} - -static RayObjectAPI empty_api = -{ - RE_rayobject_empty_intersect, - NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob); - NULL, //static void RE_rayobject_instance_done(RayObject *o); - RE_rayobject_empty_free, - RE_rayobject_empty_bb, - RE_rayobject_empty_cost, - RE_rayobject_empty_hint_bb -}; - -static RayObject empty_raytree = { &empty_api, {0, 0} }; - -RayObject *RE_rayobject_empty_create() -{ - return RE_rayobject_unalignRayAPI( &empty_raytree ); -} diff --git a/source/blender/render/intern/source/rayobject_blibvh.c b/source/blender/render/intern/raytrace/rayobject_blibvh.cpp index fa5c32a8e8d..7d59cc2df30 100644 --- a/source/blender/render/intern/source/rayobject_blibvh.c +++ b/source/blender/render/intern/raytrace/rayobject_blibvh.cpp @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: rayobject_blibvh.cpp 29491 2010-06-16 18:57:23Z blendix $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Andr Pinto. + * Contributor(s): André Pinto. * * ***** END GPL LICENSE BLOCK ***** */ @@ -33,8 +33,8 @@ #include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "RE_raytrace.h" -#include "render_types.h" + +#include "rayintersection.h" #include "rayobject.h" static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec); @@ -71,14 +71,12 @@ typedef struct BVHObject RayObject **leafs, **next_leaf; BVHTree *bvh; float bb[2][3]; - } BVHObject; - RayObject *RE_rayobject_blibvh_create(int size) { BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject"); - assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */ + assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */ obj->rayobj.api = &bvh_api; obj->bvh = BLI_bvhtree_new(size, 0.0, 4, 6); @@ -107,7 +105,7 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTr if(isec->mode == RE_RAY_SHADOW) hit->dist = 0; else - hit->dist = isec->labda*isec->dist; + hit->dist = isec->dist; } } @@ -120,11 +118,10 @@ static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec) data.isec = isec; data.leafs = obj->leafs; - VECCOPY(dir, isec->vec); - normalize_v3(dir); + copy_v3_v3(dir, isec->dir); hit.index = 0; - hit.dist = isec->labda*isec->dist; + hit.dist = isec->dist; return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, (void*)&data); } @@ -139,7 +136,7 @@ static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob) DO_MIN(min_max , obj->bb[0]); DO_MAX(min_max+3, obj->bb[1]); - BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2 ); + BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2); *(obj->next_leaf++) = ob; } @@ -165,6 +162,7 @@ static void RE_rayobject_blibvh_free(RayObject *o) static void RE_rayobject_blibvh_bb(RayObject *o, float *min, float *max) { BVHObject *obj = (BVHObject*)o; - DO_MIN( obj->bb[0], min ); - DO_MAX( obj->bb[1], max ); + DO_MIN(obj->bb[0], min); + DO_MAX(obj->bb[1], max); } + diff --git a/source/blender/render/intern/raytrace/rayobject_empty.cpp b/source/blender/render/intern/raytrace/rayobject_empty.cpp new file mode 100644 index 00000000000..abd54ab9fab --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_empty.cpp @@ -0,0 +1,75 @@ +/** + * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 1990-1998 NeoGeo BV. + * All rights reserved. + * + * Contributors: 2004/2005 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "rayobject.h" + +/* + * Empty raytree + */ + +static int RE_rayobject_empty_intersect(RayObject *o, Isect *is) +{ + return 0; +} + +static void RE_rayobject_empty_free(RayObject *o) +{ +} + +static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max) +{ + return; +} + +static float RE_rayobject_empty_cost(RayObject *o) +{ + return 0.0; +} + +static void RE_rayobject_empty_hint_bb(RayObject *o, RayHint *hint, float *min, float *max) +{} + +static RayObjectAPI empty_api = +{ + RE_rayobject_empty_intersect, + NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob); + NULL, //static void RE_rayobject_instance_done(RayObject *o); + RE_rayobject_empty_free, + RE_rayobject_empty_bb, + RE_rayobject_empty_cost, + RE_rayobject_empty_hint_bb +}; + +static RayObject empty_raytree = { &empty_api, {0, 0} }; + +RayObject *RE_rayobject_empty_create() +{ + return RE_rayobject_unalignRayAPI( &empty_raytree ); +} + diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h index 1ea59d00bac..adb7d652276 100644 --- a/source/blender/render/intern/raytrace/rayobject_hint.h +++ b/source/blender/render/intern/raytrace/rayobject_hint.h @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifndef RE_RAYTRACE_RAYOBJECT_HINT_H #define RE_RAYTRACE_RAYOBJECT_HINT_H @@ -68,3 +69,4 @@ inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax) */ #endif + diff --git a/source/blender/render/intern/source/rayobject_instance.c b/source/blender/render/intern/raytrace/rayobject_instance.cpp index d7b4beb8023..c0adae71c1f 100644 --- a/source/blender/render/intern/source/rayobject_instance.c +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: rayobject_instance.cpp 29542 2010-06-18 09:45:46Z blendix $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -22,19 +22,19 @@ * * The Original Code is: all of this file. * - * Contributor(s): Andr Pinto. + * Contributor(s): André Pinto. * * ***** END GPL LICENSE BLOCK ***** */ + #include <assert.h> #include "MEM_guardedalloc.h" - #include "BLI_math.h" #include "BLI_utildefines.h" -#include "RE_raytrace.h" +#include "rayintersection.h" #include "rayobject.h" #define RE_COST_INSTANCE (1.0f) @@ -44,7 +44,7 @@ static void RE_rayobject_instance_free(RayObject *o); static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max); static float RE_rayobject_instance_cost(RayObject *o); -static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint), float *UNUSED(min), float *UNUSED(max)) +static void RE_rayobject_instance_hint_bb(RayObject *o, RayHint *hint, float *min, float *max) {} static RayObjectAPI instance_api = @@ -90,42 +90,32 @@ RayObject *RE_rayobject_instance_create(RayObject *target, float transform[][4], static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) { - //TODO - // *there is probably a faster way to convert between coordinates - InstanceRayObject *obj = (InstanceRayObject*)o; - int res; - float start[3], vec[3], labda, dist; - int changed = 0, i; + float start[3], dir[3], idot_axis[3], dist; + int changed = 0, i, res; - //TODO - this is disabling self intersection on instances + // TODO - this is disabling self intersection on instances if(isec->orig.ob == obj->ob && obj->ob) { changed = 1; isec->orig.ob = obj->target_ob; } - - VECCOPY( start, isec->start ); - VECCOPY( vec , isec->vec ); - labda = isec->labda; - dist = isec->dist; - - //Transform to target coordinates system - VECADD( isec->vec, isec->vec, isec->start ); + // backup old values + copy_v3_v3(start, isec->start); + copy_v3_v3(dir, isec->dir); + copy_v3_v3(idot_axis, isec->idot_axis); + dist = isec->dist; + // transform to target coordinates system mul_m4_v3(obj->global2target, isec->start); - mul_m4_v3(obj->global2target, isec->vec ); - - isec->dist = len_v3v3( isec->start, isec->vec ); - VECSUB( isec->vec, isec->vec, isec->start ); + mul_mat3_m4_v3(obj->global2target, isec->dir); + isec->dist *= normalize_v3(isec->dir); - isec->labda *= isec->dist / dist; - - //Update idot_axis and bv_index + // update idot_axis and bv_index for(i=0; i<3; i++) { - isec->idot_axis[i] = 1.0f / isec->vec[i]; + isec->idot_axis[i] = 1.0f / isec->dir[i]; isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0; isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i]; @@ -134,17 +124,24 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) isec->bv_index[2*i+1] = i+3*isec->bv_index[2*i+1]; } - //Raycast + // raycast res = RE_rayobject_intersect(obj->target, isec); - //Restore coordinate space coords + // map dist into original coordinate space if(res == 0) { - isec->labda = labda; + isec->dist = dist; } else { - isec->labda *= dist / isec->dist; + // note we don't just multiply dist, because of possible + // non-uniform scaling in the transform matrix + float vec[3]; + + mul_v3_v3fl(vec, isec->dir, isec->dist); + mul_mat3_m4_v3(obj->target2global, vec); + + isec->dist = len_v3(vec); isec->hit.ob = obj->ob; #ifdef RT_USE_LAST_HIT @@ -154,18 +151,18 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) isec->last_hit = RE_rayobject_unalignRayAPI((RayObject*) obj); #endif } - isec->dist = dist; - VECCOPY( isec->start, start ); - VECCOPY( isec->vec, vec ); + + // restore values + copy_v3_v3(isec->start, start); + copy_v3_v3(isec->dir, dir); + copy_v3_v3(isec->idot_axis, idot_axis); if(changed) isec->orig.ob = obj->ob; - //Update idot_axis and bv_index + // restore bv_index for(i=0; i<3; i++) { - isec->idot_axis[i] = 1.0f / isec->vec[i]; - isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0; isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i]; @@ -208,3 +205,4 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max) DO_MINMAX(t, min, max); } } + diff --git a/source/blender/render/intern/raytrace/rayobject_internal.h b/source/blender/render/intern/raytrace/rayobject_internal.h new file mode 100644 index 00000000000..6067be07c50 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_internal.h @@ -0,0 +1,128 @@ + +#ifndef RE_RAYOBJECT_INTERNAL_H +#define RE_RAYOBJECT_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* RayObjectControl + * + * This class is intended as a place holder for control, configuration of the + * rayobject like: + * - stop building (TODO maybe when porting build to threads this could be + * implemented with some thread_cancel function) + * - max number of threads and threads callback to use during build + * ... + */ + +typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data); + +typedef struct RayObjectControl { + void *data; + RE_rayobjectcontrol_test_break_callback test_break; +} RayObjectControl; + +/* Returns true if for some reason a heavy processing function should stop + * (eg.: user asked to stop during a tree a build) + */ + +int RE_rayobjectcontrol_test_break(RayObjectControl *c); + +/* 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 0x03) to define the + type of RayObject. + + This leads to 4 possible types of RayObject: + + addr&3 - type of object + 0 Self (reserved for each structure) + 1 RayFace (tri/quad primitive) + 2 RayObject (generic with API callbacks) + 3 VlakPrimitive + (vlak primitive - to be used when we have a vlak describing the data + eg.: on render code) + + 0 means it's reserved and has it own meaning inside each ray acceleration structure + (this way each structure can use the allign offset to determine if a node represents a + RayObject primitive, which can be used to save memory) + */ + +/* used to test the type of ray object */ +#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0) +#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1) +#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2) +#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3) + +/* used to align a given ray object */ +#define RE_rayobject_align(o) ((RayObject*)(((intptr_t)o)&(~3))) + +/* used to unalign a given ray object */ +#define RE_rayobject_unalignRayFace(o) ((RayObject*)(((intptr_t)o)|1)) +#define RE_rayobject_unalignRayAPI(o) ((RayObject*)(((intptr_t)o)|2)) +#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject*)(((intptr_t)o)|3)) + +/* + * This rayobject represents a generic object. With it's own callbacks for raytrace operations. + * It's suitable to implement things like LOD. + */ + +struct RayObject { + struct RayObjectAPI *api; + struct RayObjectControl control; +}; + +typedef int (*RE_rayobject_raycast_callback)(RayObject *, struct Isect *); +typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject); +typedef void (*RE_rayobject_done_callback)(RayObject *); +typedef void (*RE_rayobject_free_callback)(RayObject *); +typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float *min, float *max); +typedef float (*RE_rayobject_cost_callback)(RayObject *); +typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, struct RayHint *, float *, float *); + +typedef struct RayObjectAPI { + RE_rayobject_raycast_callback raycast; + RE_rayobject_add_callback add; + RE_rayobject_done_callback done; + RE_rayobject_free_callback free; + RE_rayobject_merge_bb_callback bb; + RE_rayobject_cost_callback cost; + RE_rayobject_hint_bb_callback hint_bb; +} RayObjectAPI; + +/* + * Returns the expected cost of raycast on this node, primitives have a cost of 1 + */ +float RE_rayobject_cost(RayObject *r); + +/* + * This function differs from RE_rayobject_raycast + * RE_rayobject_intersect does NOT perform last-hit optimization + * So this is probably a function to call inside raytrace structures + */ +int RE_rayobject_intersect(RayObject *r, struct Isect *i); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/render/intern/source/rayobject_octree.c b/source/blender/render/intern/raytrace/rayobject_octree.cpp index 8a8b102c6fa..0fd43dfe5ef 100644 --- a/source/blender/render/intern/source/rayobject_octree.c +++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: rayobject_octree.cpp 29491 2010-06-16 18:57:23Z blendix $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -41,8 +41,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" - - +#include "rayintersection.h" #include "rayobject.h" /* ********** structs *************** */ @@ -126,8 +125,8 @@ static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, float min[3], max[3]; int ocmin, ocmax; - VECCOPY(min, v1); - VECCOPY(max, v1); + copy_v3_v3(min, v1); + copy_v3_v3(max, v1); DO_MINMAX(v2, min, max); DO_MINMAX(v3, min, max); if(v4) { @@ -192,7 +191,7 @@ static Branch *addbranch(Octree *oc, Branch *br, short ocb) index= oc->branchcount>>12; if(oc->adrbranch[index]==NULL) - oc->adrbranch[index]= MEM_callocN(4096*sizeof(Branch), "new oc branch"); + oc->adrbranch[index]= (Branch*)MEM_callocN(4096*sizeof(Branch), "new oc branch"); if(oc->branchcount>= BRANCH_ARRAY*4096) { printf("error; octree branches full\n"); @@ -210,7 +209,7 @@ static Node *addnode(Octree *oc) index= oc->nodecount>>12; if(oc->adrnode[index]==NULL) - oc->adrnode[index]= MEM_callocN(4096*sizeof(Node),"addnode"); + oc->adrnode[index]= (Node*)MEM_callocN(4096*sizeof(Node),"addnode"); if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) { printf("error; octree nodes full\n"); @@ -465,7 +464,7 @@ static void RE_rayobject_octree_free(RayObject *tree) RayObject *RE_rayobject_octree_create(int ocres, int size) { - Octree *oc= MEM_callocN(sizeof(Octree), "Octree"); + Octree *oc= (Octree*)MEM_callocN(sizeof(Octree), "Octree"); assert( RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */ oc->rayobj.api = &octree_api; @@ -505,11 +504,11 @@ static void octree_fill_rayface(Octree *oc, RayFace *face) ocres2= oc->ocres*oc->ocres; - VECCOPY(co1, face->v1); - VECCOPY(co2, face->v2); - VECCOPY(co3, face->v3); + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); if(face->v4) - VECCOPY(co4, face->v4); + copy_v3_v3(co4, face->v4); for(c=0;c<3;c++) { rtf[0][c]= (co1[c]-oc->min[c])*ocfac[c] ; @@ -621,13 +620,13 @@ static void RE_rayobject_octree_done(RayObject *tree) RE_rayobject_merge_bb( RE_rayobject_unalignRayFace(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= (Branch**)MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches"); + oc->adrnode= (Node**)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"); + oc->ocface= (char*)MEM_callocN( 3*ocres2 + 8, "ocface"); memset(oc->ocface, 0, 3*ocres2); for(c=0;c<3;c++) { /* octree enlarge, still needed? */ @@ -857,20 +856,20 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is) is->userdata= oc->userdata; #endif - VECCOPY( start, is->start ); - VECADDFAC( end, is->start, is->vec, is->labda ); - ldx= is->vec[0]*is->labda; - olabda = is->labda; + copy_v3_v3( start, is->start ); + madd_v3_v3v3fl( end, is->start, is->dir, is->dist ); + ldx= is->dir[0]*is->dist; + olabda = is->dist; u1= 0.0f; u2= 1.0f; /* clip with octree cube */ if(cliptest(-ldx, start[0]-oc->min[0], &u1,&u2)) { if(cliptest(ldx, oc->max[0]-start[0], &u1,&u2)) { - ldy= is->vec[1]*is->labda; + ldy= is->dir[1]*is->dist; if(cliptest(-ldy, start[1]-oc->min[1], &u1,&u2)) { if(cliptest(ldy, oc->max[1]-start[1], &u1,&u2)) { - ldz = is->vec[2]*is->labda; + ldz = is->dir[2]*is->dist; if(cliptest(-ldz, start[2]-oc->min[2], &u1,&u2)) { if(cliptest(ldz, oc->max[2]-start[2], &u1,&u2)) { c1=1; @@ -974,11 +973,10 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is) ldz=0; dz= 0; } - + xo=ocx1; yo=ocy1; zo=ocz1; - ddalabda= MIN3(labdax,labday,labdaz); - /*labdao= ddalabda;*/ /*NEVER READ*/ - + labdao= ddalabda= MIN3(labdax,labday,labdaz); + vec2[0]= ox1; vec2[1]= oy1; vec2[2]= oz1; @@ -992,18 +990,18 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is) if(no) { /* calculate ray intersection with octree node */ - VECCOPY(vec1, vec2); + copy_v3_v3(vec1, vec2); // dox,y,z is negative vec2[0]= ox1-ddalabda*dox; vec2[1]= oy1-ddalabda*doy; vec2[2]= oz1-ddalabda*doz; calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2); - //is->labda = (u1+ddalabda*(u2-u1))*olabda; + //is->dist = (u1+ddalabda*(u2-u1))*olabda; if( testnode(oc, is, no, ocval) ) found = 1; - if(is->labda < (u1+ddalabda*(u2-u1))*olabda) + if(is->dist < (u1+ddalabda*(u2-u1))*olabda) return found; } diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp index c510af540db..e8a118d3349 100644 --- a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp +++ b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp @@ -26,7 +26,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + #include "vbvh.h" #include "svbvh.h" #include "reorganize.h" @@ -60,10 +64,10 @@ void bvh_done<QBVHTree>(QBVHTree *obj) BLI_memarena_use_malloc(arena2); BLI_memarena_use_align(arena2, 16); - //Build and optimize the tree - //TODO do this in 1 pass (half memory usage during building) + //Build and optimize the tree + //TODO do this in 1 pass (half memory usage during building) VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); - + if(RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { BLI_memarena_free(arena1); @@ -71,28 +75,32 @@ void bvh_done<QBVHTree>(QBVHTree *obj) return; } - pushup_simd<VBVHNode,4>(root); + pushup_simd<VBVHNode,4>(root); + obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root); - //Cleanup - BLI_memarena_free(arena1); + //Free data + BLI_memarena_free(arena1); - rtbuild_free( obj->builder ); - obj->builder = NULL; - obj->node_arena = arena2; - obj->cost = 1.0; -} + obj->cost = 1.0; + rtbuild_free(obj->builder); + obj->builder = NULL; +} template<int StackSize> int intersect(QBVHTree *obj, Isect* isec) { //TODO renable hint support - if(RE_rayobject_isAligned(obj->root)) - return bvh_node_stack_raycast<SVBVHNode,StackSize,false>( obj->root, isec); + if(RE_rayobject_isAligned(obj->root)) { + if(isec->mode == RE_RAY_SHADOW) + return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec); + else + return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec); + } else - return RE_rayobject_intersect( (RayObject*) obj->root, isec ); + return RE_rayobject_intersect((RayObject*)obj->root, isec); } template<class Tree> @@ -132,13 +140,11 @@ RayObjectAPI* bvh_get_api(int maxstacksize) return 0; } - RayObject *RE_rayobject_qbvh_create(int size) { return bvh_create_tree<QBVHTree,DFS_STACK_SIZE>(size); } - #else RayObject *RE_rayobject_qbvh_create(int size) diff --git a/source/blender/render/intern/source/rayobject_raycounter.c b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp index 16446bde501..a355d4b5a06 100644 --- a/source/blender/render/intern/source/rayobject_raycounter.c +++ b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: rayobject_raycounter.cpp 29491 2010-06-16 18:57:23Z blendix $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #include "rayobject.h" #include "raycounter.h" diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp index 79bb3b9260f..cdaaebc7f92 100644 --- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp @@ -22,23 +22,23 @@ * * The Original Code is: all of this file. * - * Contributor(s): Andr Pinto. + * Contributor(s): André Pinto. * * ***** END GPL LICENSE BLOCK ***** */ + #include <assert.h> #include <math.h> #include <stdlib.h> #include <algorithm> #include "rayobject_rtbuild.h" + #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BLI_utildefines.h" - - static bool selected_node(RTBuilder::Object *node) { return node->selected; @@ -94,13 +94,22 @@ void rtbuild_free(RTBuilder *b) void rtbuild_add(RTBuilder *b, RayObject *o) { + float bb[6]; + assert( b->primitives.begin + b->primitives.maxsize != b->primitives.end ); + + INIT_MINMAX(bb, bb+3); + RE_rayobject_merge_bb(o, bb, bb+3); + + /* skip objects with zero bounding box, they are of no use, and + will give problems in rtbuild_heuristic_object_split later */ + if(len_squared_v3v3(bb, bb+3) == 0.0f) + return; + copy_v3_v3(b->primitives.end->bb, bb); + copy_v3_v3(b->primitives.end->bb+3, bb+3); b->primitives.end->obj = o; b->primitives.end->cost = RE_rayobject_cost(o); - - INIT_MINMAX(b->primitives.end->bb, b->primitives.end->bb+3); - RE_rayobject_merge_bb(o, b->primitives.end->bb, b->primitives.end->bb+3); for(int i=0; i<3; i++) { @@ -333,8 +342,8 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) { if(i == size-1) { - VECCOPY(sweep[i].bb, obj[i]->bb); - VECCOPY(sweep[i].bb+3, obj[i]->bb+3); + copy_v3_v3(sweep[i].bb, obj[i]->bb); + copy_v3_v3(sweep[i].bb+3, obj[i]->bb+3); sweep[i].cost = obj[i]->cost; } else @@ -365,8 +374,12 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) //Worst case heuristic (cost of each child is linear) float hcost, left_side, right_side; - left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost+logf((float)i)); - right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost+logf((float)size-i)); + // not using log seems to have no impact on raytracing perf, but + // makes tree construction quicker, left out for now to test (brecht) + // left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost+logf((float)i)); + // right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost+logf((float)size-i)); + left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost); + right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost); hcost = left_side+right_side; assert(left_side >= 0); diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp index 647c5771e4f..c10da3ad8c0 100644 --- a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp +++ b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp @@ -26,8 +26,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" + #include "vbvh.h" #include "svbvh.h" #include "reorganize.h" @@ -75,7 +78,8 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj) //Build and optimize the tree if(0) { - VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder); + VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); + if(RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { BLI_memarena_free(arena1); @@ -86,11 +90,11 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj) reorganize(root); remove_useless(root, &root); bvh_refit(root); - + pushup(root); pushdown(root); pushup_simd<VBVHNode,4>(root); - + obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root); } else @@ -98,6 +102,7 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj) //Finds the optimal packing of this tree using a given cost model //TODO this uses quite a lot of memory, find ways to reduce memory usage during building OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder); + if(RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { BLI_memarena_free(arena1); @@ -108,15 +113,13 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj) VBVH_optimalPackSIMD<OVBVHNode,PackCost>(PackCost()).transform(root); obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root); } - //Free data BLI_memarena_free(arena1); obj->node_arena = arena2; obj->cost = 1.0; - - + rtbuild_free( obj->builder ); obj->builder = NULL; } @@ -125,8 +128,12 @@ template<int StackSize> int intersect(SVBVHTree *obj, Isect* isec) { //TODO renable hint support - if(RE_rayobject_isAligned(obj->root)) - return bvh_node_stack_raycast<SVBVHNode,StackSize,false>( obj->root, isec); + if(RE_rayobject_isAligned(obj->root)) { + if(isec->mode == RE_RAY_SHADOW) + return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec); + else + return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec); + } else return RE_rayobject_intersect( (RayObject*) obj->root, isec ); } @@ -172,6 +179,7 @@ RayObject *RE_rayobject_svbvh_create(int size) { return bvh_create_tree<SVBVHTree,DFS_STACK_SIZE>(size); } + #else RayObject *RE_rayobject_svbvh_create(int size) diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp index b2104a2d557..df5842db2bf 100644 --- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp +++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp @@ -22,29 +22,33 @@ * * The Original Code is: all of this file. * - * Contributor(s): Andr Pinto. + * Contributor(s): André Pinto. * * ***** END GPL LICENSE BLOCK ***** */ + int tot_pushup = 0; int tot_pushdown = 0; int tot_hints = 0; - #include <assert.h> -#include "rayobject.h" -#include "rayobject_rtbuild.h" -#include "RE_raytrace.h" -#include "BLI_memarena.h" + #include "MEM_guardedalloc.h" + #include "BKE_global.h" #include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_utildefines.h" + +#include "rayintersection.h" +#include "rayobject.h" +#include "rayobject_rtbuild.h" #include "reorganize.h" #include "bvh.h" #include "vbvh.h" -#include "svbvh.h" + #include <queue> #include <algorithm> @@ -126,8 +130,12 @@ template<int StackSize> int intersect(VBVHTree *obj, Isect* isec) { //TODO renable hint support - if(RE_rayobject_isAligned(obj->root)) - return bvh_node_stack_raycast<VBVHNode,StackSize,false>( obj->root, isec); + if(RE_rayobject_isAligned(obj->root)) { + if(isec->mode == RE_RAY_SHADOW) + return bvh_node_stack_raycast<VBVHNode,StackSize,false,true>( obj->root, isec); + else + return bvh_node_stack_raycast<VBVHNode,StackSize,false,false>( obj->root, isec); + } else return RE_rayobject_intersect( (RayObject*) obj->root, isec ); } diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h index c8fbd1cfe94..4e2dce32136 100644 --- a/source/blender/render/intern/raytrace/reorganize.h +++ b/source/blender/render/intern/raytrace/reorganize.h @@ -26,18 +26,18 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +#include <float.h> +#include <math.h> #include <stdio.h> + #include <algorithm> -#include <math.h> -#include <vector> #include <queue> - -#include "BLI_utildefines.h" +#include <vector> #include "BKE_global.h" #ifdef _WIN32 -#undef INFINITY #define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though. #endif @@ -302,7 +302,7 @@ float bvh_refit(Node *node) * with the purpose to reduce the expected cost (eg.: number of BB tests). */ #include <vector> -#define MAX_CUT_SIZE 16 +#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */ #define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE struct OVBVHNode diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h index 11511fccb89..832058870dd 100644 --- a/source/blender/render/intern/raytrace/svbvh.h +++ b/source/blender/render/intern/raytrace/svbvh.h @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifdef __SSE__ #ifndef RE_RAYTRACE_SVBVH_H @@ -33,56 +34,132 @@ #include "bvh.h" #include "BLI_memarena.h" -#include "BLI_utildefines.h" #include "BKE_global.h" #include <stdio.h> #include <algorithm> struct SVBVHNode { + float child_bb[24]; + SVBVHNode *child[4]; int nchilds; - - //Array of bb, array of childs - float *child_bb; - SVBVHNode **child; }; -template<> -inline int bvh_node_hit_test<SVBVHNode>(SVBVHNode *node, Isect *isec) +static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group) +{ + const __m128 tmin0 = _mm_setzero_ps(); + const __m128 tmax0 = _mm_set_ps1(isec->dist); + + const __m128 start0 = _mm_set_ps1(isec->start[0]); + const __m128 start1 = _mm_set_ps1(isec->start[1]); + const __m128 start2 = _mm_set_ps1(isec->start[2]); + const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0); + const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0); + const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1); + const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1); + const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2); + const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2); + const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]); + const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]); + const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]); + const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0); + const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0); + const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1); + const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1); + const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2); + const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2); + const __m128 tmin1 = _mm_max_ps(tmin0, mul0); + const __m128 tmax1 = _mm_min_ps(tmax0, mul1); + const __m128 tmin2 = _mm_max_ps(tmin1, mul2); + const __m128 tmax2 = _mm_min_ps(tmax1, mul3); + const __m128 tmin3 = _mm_max_ps(tmin2, mul4); + const __m128 tmax3 = _mm_min_ps(tmax2, mul5); + + return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3)); +} + +static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb) { + const float *bb = _bb; + + float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; + float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; + float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; + float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; + float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; + float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; + + RE_RC_COUNT(isec->raycounter->bb.test); + + if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; + if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0; + if(t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0; + + RE_RC_COUNT(isec->raycounter->bb.hit); + return 1; } -template<> -inline void bvh_node_push_childs<SVBVHNode>(SVBVHNode *node, Isect *isec, SVBVHNode **stack, int &stack_pos) +static bool svbvh_node_is_leaf(const SVBVHNode *node) { - int i=0; - while(i+4 <= node->nchilds) - { - int res = test_bb_group4( (__m128*) (node->child_bb+6*i), isec ); - RE_RC_COUNT(isec->raycounter->simd_bb.test); - - if(res & 1) { stack[stack_pos++] = node->child[i+0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } - if(res & 2) { stack[stack_pos++] = node->child[i+1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } - if(res & 4) { stack[stack_pos++] = node->child[i+2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } - if(res & 8) { stack[stack_pos++] = node->child[i+3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } - - i += 4; - } - while(i < node->nchilds) + return !RE_rayobject_isAligned(node); +} + +template<int MAX_STACK_SIZE, bool SHADOW> +static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec) +{ + SVBVHNode *stack[MAX_STACK_SIZE], *node; + int hit = 0, stack_pos = 0; + + stack[stack_pos++] = root; + + while(stack_pos) { - if(RE_rayobject_bb_intersect_test(isec, (const float*)node->child_bb+6*i)) - stack[stack_pos++] = node->child[i]; - i++; + node = stack[--stack_pos]; + + if(!svbvh_node_is_leaf(node)) + { + int nchilds= node->nchilds; + + if(nchilds == 4) { + float *child_bb= node->child_bb; + int res = svbvh_bb_intersect_test_simd4(isec, ((__m128*) (child_bb))); + SVBVHNode **child= node->child; + + RE_RC_COUNT(isec->raycounter->simd_bb.test); + + if(res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if(res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if(res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if(res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + } + else { + float *child_bb= node->child_bb; + SVBVHNode **child= node->child; + int i; + + for(i=0; i<nchilds; i++) + if(svbvh_bb_intersect_test(isec, (float*)child_bb+6*i)) + stack[stack_pos++] = child[i]; + } + } + else + { + hit |= RE_rayobject_intersect((RayObject*)node, isec); + if(SHADOW && hit) break; + } } + + return hit; } + template<> inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float *min, float *max) { if(is_leaf(node)) { - RE_rayobject_merge_bb( (RayObject*)node, min, max); + RE_rayobject_merge_bb((RayObject*)node, min, max); } else { @@ -156,15 +233,13 @@ struct Reorganize_SVBVH { SVBVHNode *node = (SVBVHNode*)BLI_memarena_alloc(arena, sizeof(SVBVHNode)); node->nchilds = nchilds; - node->child_bb = (float*)BLI_memarena_alloc(arena, sizeof(float)*6*nchilds); - node->child= (SVBVHNode**)BLI_memarena_alloc(arena, sizeof(SVBVHNode*)*nchilds); return node; } void copy_bb(float *bb, const float *old_bb) { - std::copy( old_bb, old_bb+6, bb ); + std::copy(old_bb, old_bb+6, bb); } void prepare_for_simd(SVBVHNode *node) @@ -174,7 +249,7 @@ struct Reorganize_SVBVH { float vec_tmp[4*6]; float *res = node->child_bb+6*i; - std::copy( res, res+6*4, vec_tmp); + std::copy(res, res+6*4, vec_tmp); for(int j=0; j<6; j++) { @@ -231,7 +306,7 @@ struct Reorganize_SVBVH { float bb[6]; INIT_MINMAX(bb, bb+3); - RE_rayobject_merge_bb( (RayObject*)o_child, bb, bb+3); + RE_rayobject_merge_bb((RayObject*)o_child, bb, bb+3); copy_bb(node->child_bb+i*6, bb); break; } @@ -240,7 +315,7 @@ struct Reorganize_SVBVH copy_bb(node->child_bb+i*6, o_child->bb); } } - assert( i == 0 ); + assert(i == 0); prepare_for_simd(node); @@ -251,3 +326,4 @@ struct Reorganize_SVBVH #endif #endif //__SSE__ + diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h index a5ca093de2a..06188ede8c6 100644 --- a/source/blender/render/intern/raytrace/vbvh.h +++ b/source/blender/render/intern/raytrace/vbvh.h @@ -26,12 +26,13 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#include <assert.h> +#include <assert.h> #include <algorithm> -#include "rayobject_rtbuild.h" + #include "BLI_memarena.h" -#include "BLI_utildefines.h" + +#include "rayobject_rtbuild.h" /* * VBVHNode represents a BVHNode with support for a variable number of childrens @@ -167,12 +168,11 @@ struct BuildBinaryVBVH Node *node = create_node(); - INIT_MINMAX(node->bb, node->bb+3); - rtbuild_merge_bb(builder, node->bb, node->bb+3); - Node **child = &node->child; int nc = rtbuild_split(builder); + INIT_MINMAX(node->bb, node->bb+3); + assert(nc == 2); for(int i=0; i<nc; i++) { @@ -180,6 +180,8 @@ struct BuildBinaryVBVH rtbuild_get_child(builder, i, &tmp); *child = _transform(&tmp); + DO_MIN((*child)->bb, node->bb); + DO_MAX((*child)->bb+3, node->bb+3); child = &((*child)->sibling); } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index b5c53e8cb39..550a063c298 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3940,30 +3940,35 @@ static void set_phong_threshold(ObjectRen *obr) /* per face check if all samples should be taken. if raytrace or multisample, do always for raytraced material, or when material full_osa set */ -static void set_fullsample_flag(Render *re, ObjectRen *obr) +static void set_fullsample_trace_flag(Render *re, ObjectRen *obr) { VlakRen *vlr; - int a, trace, mode; + int a, trace, mode, osa; - if(re->osa==0) - return; - + osa= re->osa; trace= re->r.mode & R_RAYTRACE; for(a=obr->totvlak-1; a>=0; a--) { vlr= RE_findOrAddVlak(obr, a); mode= vlr->mat->mode; + + if(trace && (mode & MA_TRACEBLE)) + vlr->flag |= R_TRACEBLE; - if(mode & MA_FULL_OSA) - vlr->flag |= R_FULL_OSA; - else if(trace) { - if(mode & MA_SHLESS); - else if(vlr->mat->material_type == MA_TYPE_VOLUME); - else if((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) - /* for blurry reflect/refract, better to take more samples - * inside the raytrace than as OSA samples */ - if ((vlr->mat->gloss_mir == 1.0) && (vlr->mat->gloss_tra == 1.0)) - vlr->flag |= R_FULL_OSA; + if(osa) { + if(mode & MA_FULL_OSA) { + vlr->flag |= R_FULL_OSA; + } + else if(trace) { + if(mode & MA_SHLESS); + else if(vlr->mat->material_type == MA_TYPE_VOLUME); + else if((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) { + /* for blurry reflect/refract, better to take more samples + * inside the raytrace than as OSA samples */ + if ((vlr->mat->gloss_mir == 1.0) && (vlr->mat->gloss_tra == 1.0)) + vlr->flag |= R_FULL_OSA; + } + } } } } @@ -4158,7 +4163,7 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset) check_non_flat_quads(obr); } - set_fullsample_flag(re, obr); + set_fullsample_trace_flag(re, obr); /* compute bounding boxes for clipping */ INIT_MINMAX(min, max); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index a1a06f87722..d1a0860545b 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -60,7 +60,7 @@ #include "texture.h" #include "volumetric.h" -#include "RE_raytrace.h" +#include "rayintersection.h" #include "rayobject.h" #include "raycounter.h" @@ -195,7 +195,7 @@ void freeraytree(Render *re) static int is_raytraceable_vlr(Render *re, VlakRen *vlr) { /* note: volumetric must be tracable, wire must not */ - if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME)) + if((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME)) if(vlr->mat->material_type != MA_TYPE_WIRE) return 1; return 0; @@ -209,12 +209,13 @@ static int is_raytraceable(Render *re, ObjectInstanceRen *obi) if(re->excludeob && obr->ob == re->excludeob) return 0; - for(v=0;v<obr->totvlak;v++) - { + for(v=0;v<obr->totvlak;v++) { VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + if(is_raytraceable_vlr(re, vlr)) return 1; } + return 0; } @@ -444,11 +445,7 @@ void makeraytree(Render *re) if(re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE) re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS); - if(G.f & G_DEBUG) { - BENCH(makeraytree_single(re), tree_build); - } - else - makeraytree_single(re); + makeraytree_single(re); if(test_break(re)) { @@ -522,12 +519,12 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) VlakRen *vlr= (VlakRen*)is->hit.face; /* set up view vector */ - VECCOPY(shi->view, is->vec); + VECCOPY(shi->view, is->dir); /* render co */ - shi->co[0]= is->start[0]+is->labda*(shi->view[0]); - shi->co[1]= is->start[1]+is->labda*(shi->view[1]); - shi->co[2]= is->start[2]+is->labda*(shi->view[2]); + shi->co[0]= is->start[0]+is->dist*(shi->view[0]); + shi->co[1]= is->start[1]+is->dist*(shi->view[1]); + shi->co[2]= is->start[2]+is->dist*(shi->view[2]); normalize_v3(shi->view); @@ -717,15 +714,15 @@ static void ray_fadeout(Isect *is, ShadeInput *shi, float *col, float *blendcol, /* the main recursive tracer itself * note: 'col' must be initialized */ -static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *vec, float *col, ObjectInstanceRen *obi, VlakRen *vlr, int traflag) +static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *dir, float *col, ObjectInstanceRen *obi, VlakRen *vlr, int traflag) { ShadeInput shi= {0}; Isect isec; float dist_mir = origshi->mat->dist_mir; VECCOPY(isec.start, start); - VECCOPY(isec.vec, vec ); - isec.labda = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST; + VECCOPY(isec.dir, dir ); + isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST; isec.mode= RE_RAY_MIRROR; isec.check = RE_CHECK_VLR_RENDER; isec.skip = RE_SKIP_VLR_NEIGHBOUR; @@ -863,7 +860,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo /* max ray distance set, but found an intersection, so fade this color * out towards the sky/material color for a smooth transition */ - ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, vec); + ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir); ray_fadeout(&isec, &shi, col, blendcol, dist_mir); } } @@ -875,7 +872,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo } else { - ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, vec); + ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir); } RE_RC_MERGE(&origshi->raycounter, &shi.raycounter); } @@ -1605,13 +1602,13 @@ static void addAlphaLight(float *shadfac, float *col, float alpha, float filter) shadfac[3]= (1.0f-alpha)*shadfac[3]; } -static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag) +static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4]) { /* ray to lamp, find first face that intersects, check alpha properties, if it has col[3]>0.0f continue. so exit when alpha is full */ ShadeInput shi; ShadeResult shr; - float initial_labda = is->labda; + float initial_dist = is->dist; if(RE_rayobject_raycast(R.raytree, is)) { float d= 1.0f; @@ -1639,26 +1636,26 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int d= shade_by_transmission(is, &shi, &shr); /* mix colors based on shadfac (rgb + amount of light factor) */ - addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter); + addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter); } else if (shi.mat->material_type == MA_TYPE_VOLUME) { - const float a = is->col[3]; + const float a = col[3]; - is->col[0] = a*is->col[0] + shr.alpha*shr.combined[0]; - is->col[1] = a*is->col[1] + shr.alpha*shr.combined[1]; - is->col[2] = a*is->col[2] + shr.alpha*shr.combined[2]; + col[0] = a*col[0] + shr.alpha*shr.combined[0]; + col[1] = a*col[1] + shr.alpha*shr.combined[1]; + col[2] = a*col[2] + shr.alpha*shr.combined[2]; - is->col[3] = (1.0 - shr.alpha)*a; + col[3] = (1.0 - shr.alpha)*a; } - if(depth>0 && is->col[3]>0.0f) { + if(depth>0 && col[3]>0.0f) { /* adapt isect struct */ VECCOPY(is->start, shi.co); - is->labda = initial_labda-is->labda; + is->dist = initial_dist-is->dist; is->orig.ob = shi.obi; is->orig.face = shi.vlr; - ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA); + ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col); } RE_RC_MERGE(&origshi->raycounter, &shi.raycounter); @@ -1705,8 +1702,8 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) vec[2]-= vec[2]; } - VECCOPY(isec.vec, vec ); - isec.labda = RE_RAYTRACE_MAXDIST; + VECCOPY(isec.dir, vec ); + isec.dist = RE_RAYTRACE_MAXDIST; if(RE_rayobject_raycast(R.raytree, &isec)) { float fac; @@ -1717,7 +1714,7 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) /* end warning! - Campbell */ shade_ray(&isec, &shi, &shr_t); - fac= isec.labda*isec.labda; + fac= isec.dist*isec.dist; fac= 1.0f; accum[0]+= fac*(shr_t.diff[0]+shr_t.spec[0]); accum[1]+= fac*(shr_t.diff[1]+shr_t.spec[1]); @@ -1936,7 +1933,7 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env) else { VECCOPY(nrm, shi->facenor); } - + ortho_basis_v3v3_v3( up, side,nrm); /* sampling init */ @@ -1954,7 +1951,6 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env) QMC_initPixel(qsa, shi->thread); - while (samples < max_samples) { /* sampling, returns quasi-random vector in unit hemisphere */ @@ -1966,15 +1962,15 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env) normalize_v3(dir); - isec.vec[0] = -dir[0]; - isec.vec[1] = -dir[1]; - isec.vec[2] = -dir[2]; - isec.labda = maxdist; + isec.dir[0] = -dir[0]; + isec.dir[1] = -dir[1]; + isec.dir[2] = -dir[2]; + isec.dist = maxdist; prev = fac; if(RE_rayobject_raycast(R.raytree, &isec)) { - if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac); + if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.dist*R.wrld.aodistfac); else fac+= 1.0f; } else if(envcolor!=WO_AOPLAIN) { @@ -2102,15 +2098,15 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *ao, float *env) actual++; - /* always set start/vec/labda */ - isec.vec[0] = -vec[0]; - isec.vec[1] = -vec[1]; - isec.vec[2] = -vec[2]; - isec.labda = maxdist; + /* always set start/vec/dist */ + isec.dir[0] = -vec[0]; + isec.dir[1] = -vec[1]; + isec.dir[2] = -vec[2]; + isec.dist = maxdist; /* do the trace */ if(RE_rayobject_raycast(R.raytree, &isec)) { - if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); + if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.dist*R.wrld.aodistfac); else sh+= 1.0f; } else if(envcolor!=WO_AOPLAIN) { @@ -2325,26 +2321,25 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float * } VECCOPY(isec->start, co); - isec->vec[0] = end[0]-isec->start[0]; - isec->vec[1] = end[1]-isec->start[1]; - isec->vec[2] = end[2]-isec->start[2]; - isec->labda = 1.0f; // * normalize_v3(isec->vec); + isec->dir[0] = end[0]-isec->start[0]; + isec->dir[1] = end[1]-isec->start[1]; + isec->dir[2] = end[2]-isec->start[2]; + isec->dist = normalize_v3(isec->dir); /* trace the ray */ if(isec->mode==RE_RAY_SHADOW_TRA) { - isec->col[0]= isec->col[1]= isec->col[2]= 1.0f; - isec->col[3]= 1.0f; + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0); - shadfac[0] += isec->col[0]; - shadfac[1] += isec->col[1]; - shadfac[2] += isec->col[2]; - shadfac[3] += isec->col[3]; + ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col); + shadfac[0] += col[0]; + shadfac[1] += col[1]; + shadfac[2] += col[2]; + shadfac[3] += col[3]; /* for variance calc */ - colsq[0] += isec->col[0]*isec->col[0]; - colsq[1] += isec->col[1]*isec->col[1]; - colsq[2] += isec->col[2]*isec->col[2]; + colsq[0] += col[0]*col[0]; + colsq[1] += col[1]*col[1]; + colsq[2] += col[2]*col[2]; } else { if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f; @@ -2427,23 +2422,22 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa mul_m3_v3(lar->mat, vec); /* set start and vec */ - isec->vec[0] = vec[0]+lampco[0]-isec->start[0]; - isec->vec[1] = vec[1]+lampco[1]-isec->start[1]; - isec->vec[2] = vec[2]+lampco[2]-isec->start[2]; - isec->labda = 1.0f; + isec->dir[0] = vec[0]+lampco[0]-isec->start[0]; + isec->dir[1] = vec[1]+lampco[1]-isec->start[1]; + isec->dir[2] = vec[2]+lampco[2]-isec->start[2]; + isec->dist = 1.0f; isec->check = RE_CHECK_VLR_RENDER; isec->skip = RE_SKIP_VLR_NEIGHBOUR; if(isec->mode==RE_RAY_SHADOW_TRA) { /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ - isec->col[0]= isec->col[1]= isec->col[2]= 1.0f; - isec->col[3]= 1.0f; + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0); - shadfac[0] += isec->col[0]; - shadfac[1] += isec->col[1]; - shadfac[2] += isec->col[2]; - shadfac[3] += isec->col[3]; + ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col); + shadfac[0] += col[0]; + shadfac[1] += col[1]; + shadfac[2] += col[2]; + shadfac[3] += col[3]; } else if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f; @@ -2524,18 +2518,17 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) shadfac[3]= 1.0f; // 1.0=full light - /* set up isec vec */ + /* set up isec.dir */ VECCOPY(isec.start, shi->co); - VECSUB(isec.vec, lampco, isec.start); - isec.labda = 1.0f; + VECSUB(isec.dir, lampco, isec.start); + isec.dist = normalize_v3(isec.dir); if(isec.mode==RE_RAY_SHADOW_TRA) { /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ - isec.col[0]= isec.col[1]= isec.col[2]= 1.0f; - isec.col[3]= 1.0f; + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0); - QUATCOPY(shadfac, isec.col); + ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col); + QUATCOPY(shadfac, col); } else if(RE_rayobject_raycast(R.raytree, &isec)) shadfac[3]= 0.0f; @@ -2580,7 +2573,7 @@ static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float isec.orig.ob = shi->obi; isec.orig.face = shi->vlr; - /* set up isec vec */ + /* set up isec.dir */ VECCOPY(isec.start, shi->co); VECCOPY(isec.end, lampco); @@ -2588,11 +2581,11 @@ static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float /* we got a face */ /* render co */ - co[0]= isec.start[0]+isec.labda*(isec.vec[0]); - co[1]= isec.start[1]+isec.labda*(isec.vec[1]); - co[2]= isec.start[2]+isec.labda*(isec.vec[2]); + co[0]= isec.start[0]+isec.dist*(isec.dir[0]); + co[1]= isec.start[1]+isec.dist*(isec.dir[1]); + co[2]= isec.start[2]+isec.dist*(isec.dir[2]); - *distfac= len_v3(isec.vec); + *distfac= len_v3(isec.dir); } else *distfac= 0.0f; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index d955043b1f1..83e9abc0906 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -61,6 +61,8 @@ #include "IMB_imbuf.h" /* local include */ +#include "rayintersection.h" +#include "rayobject.h" #include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" @@ -71,7 +73,6 @@ #include "shading.h" #include "sss.h" #include "zbuf.h" -#include "RE_raytrace.h" #include "PIL_time.h" @@ -2287,19 +2288,19 @@ static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, f /* 'dir' is always normalized */ VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist); - isect->vec[0] = dir[0]*maxdist*sign; - isect->vec[1] = dir[1]*maxdist*sign; - isect->vec[2] = dir[2]*maxdist*sign; + isect->dir[0] = dir[0]*sign; + isect->dir[1] = dir[1]*sign; + isect->dir[2] = dir[2]*sign; - isect->labda = maxdist; + isect->dist = maxdist; hit = RE_rayobject_raycast(raytree, isect); if(hit) { - hitco[0] = isect->start[0] + isect->labda*isect->vec[0]; - hitco[1] = isect->start[1] + isect->labda*isect->vec[1]; - hitco[2] = isect->start[2] + isect->labda*isect->vec[2]; + hitco[0] = isect->start[0] + isect->dist*isect->dir[0]; + hitco[1] = isect->start[1] + isect->dist*isect->dir[1]; + hitco[2] = isect->start[2] + isect->dist*isect->dir[2]; - *dist= len_v3v3(start, hitco); + *dist= isect->dist; } return hit; diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index b917c1ddc92..c1a3b989c1f 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -76,8 +76,8 @@ #include "BKE_DerivedMesh.h" #include "RE_render_ext.h" /* externtex */ -#include "RE_raytrace.h" +#include "rayobject.h" #include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 2813df3744f..609e647637f 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -42,10 +42,11 @@ #include "PIL_time.h" #include "RE_shader_ext.h" -#include "RE_raytrace.h" #include "DNA_material_types.h" +#include "rayintersection.h" +#include "rayobject.h" #include "render_types.h" #include "rendercore.h" #include "renderdatabase.h" @@ -74,11 +75,11 @@ int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int l if (RE_rayobject_raycast(tree, isect)) { - isect->start[0] = isect->start[0] + isect->labda*isect->vec[0]; - isect->start[1] = isect->start[1] + isect->labda*isect->vec[1]; - isect->start[2] = isect->start[2] + isect->labda*isect->vec[2]; + isect->start[0] = isect->start[0] + isect->dist*isect->dir[0]; + isect->start[1] = isect->start[1] + isect->dist*isect->dir[1]; + isect->start[2] = isect->start[2] + isect->dist*isect->dir[2]; - isect->labda = FLT_MAX; + isect->dist = FLT_MAX; isect->skip = RE_SKIP_VLR_NEIGHBOUR; isect->orig.face= isect->hit.face; isect->orig.ob= isect->hit.ob; @@ -93,21 +94,21 @@ int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int l int point_inside_obi(RayObject *tree, ObjectInstanceRen *UNUSED(obi), float *co) { Isect isect= {{0}}; - float vec[3] = {0.0f,0.0f,1.0f}; + float dir[3] = {0.0f,0.0f,1.0f}; int final_depth=0, depth=0, limit=20; /* set up the isect */ VECCOPY(isect.start, co); - VECCOPY(isect.vec, vec); + VECCOPY(isect.dir, dir); isect.mode= RE_RAY_MIRROR; isect.last_hit= NULL; isect.lay= -1; - isect.labda = FLT_MAX; + isect.dist = FLT_MAX; isect.orig.face= NULL; isect.orig.ob = NULL; - final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth); + final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth); /* even number of intersections: point is outside * odd number: point is inside */ diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index b0aca038e72..dc016a161b5 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -40,7 +40,6 @@ #include "BLI_utildefines.h" #include "RE_shader_ext.h" -#include "RE_raytrace.h" #include "DNA_material_types.h" #include "DNA_group_types.h" @@ -51,6 +50,8 @@ #include "render_types.h" #include "pixelshading.h" +#include "rayintersection.h" +#include "rayobject.h" #include "shading.h" #include "shadbuf.h" #include "texture.h" @@ -84,13 +85,13 @@ static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co) copy_v3_v3(is.start, co); if(lar->type==LA_SUN || lar->type==LA_HEMI) { - is.vec[0] = -lar->vec[0]; - is.vec[1] = -lar->vec[1]; - is.vec[2] = -lar->vec[2]; - is.labda = R.maxdist; + is.dir[0] = -lar->vec[0]; + is.dir[1] = -lar->vec[1]; + is.dir[2] = -lar->vec[2]; + is.dist = R.maxdist; } else { - VECSUB( is.vec, lar->co, is.start ); - is.labda = len_v3( is.vec ); + VECSUB( is.dir, lar->co, is.start ); + is.dist = normalize_v3( is.dir ); } is.mode = RE_RAY_MIRROR; @@ -119,8 +120,8 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, { VECCOPY(isect->start, co); - VECCOPY(isect->vec, vec ); - isect->labda = FLT_MAX; + VECCOPY(isect->dir, vec ); + isect->dist = FLT_MAX; isect->mode= RE_RAY_MIRROR; isect->last_hit = NULL; isect->lay= -1; @@ -138,9 +139,9 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, if(RE_rayobject_raycast(R.raytree, isect)) { - hitco[0] = isect->start[0] + isect->labda*isect->vec[0]; - hitco[1] = isect->start[1] + isect->labda*isect->vec[1]; - hitco[2] = isect->start[2] + isect->labda*isect->vec[2]; + hitco[0] = isect->start[0] + isect->dist*isect->dir[0]; + hitco[1] = isect->start[1] + isect->dist*isect->dir[1]; + hitco[2] = isect->start[2] + isect->dist*isect->dir[2]; return 1; } else { return 0; @@ -185,8 +186,8 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co Isect isect; VECCOPY(isect.start, co); - VECCOPY(isect.vec, shi->view); - isect.labda = FLT_MAX; + VECCOPY(isect.dir, shi->view); + isect.dist = FLT_MAX; isect.mode= RE_RAY_MIRROR; isect.check = RE_CHECK_VLR_NONE; @@ -772,7 +773,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct /* due to idiosyncracy in ray_trace_shadow_tra() */ if (is.hit.ob == shi->obi) { copy_v3_v3(shi->co, hitco); - last_is->labda -= is.labda; + last_is->dist -= is.dist; shi->vlr = (VlakRen *)is.hit.face; } |