forked from bartvdbraak/blender
Cycles: Use dedicated BVH for subsurface ray casting
This commit makes it so casting subsurface rays will totally ignore all the BVH nodes and primitives which do not belong to a current object, making it much simpler traversal code and reduces number of intersection tests. Reviewers: brecht, juicyfruit, dingto, lukasstockner97 Differential Revision: https://developer.blender.org/D1823
This commit is contained in:
parent
712a257994
commit
0e47e0cc9e
@ -233,7 +233,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
|
|||||||
Mesh *mesh = ob->mesh;
|
Mesh *mesh = ob->mesh;
|
||||||
BVH *bvh = mesh->bvh;
|
BVH *bvh = mesh->bvh;
|
||||||
|
|
||||||
if(!mesh->transform_applied) {
|
if(mesh->need_build_bvh()) {
|
||||||
if(mesh_map.find(mesh) == mesh_map.end()) {
|
if(mesh_map.find(mesh) == mesh_map.end()) {
|
||||||
prim_index_size += bvh->pack.prim_index.size();
|
prim_index_size += bvh->pack.prim_index.size();
|
||||||
tri_woop_size += bvh->pack.tri_woop.size();
|
tri_woop_size += bvh->pack.tri_woop.size();
|
||||||
@ -268,9 +268,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
|
|||||||
foreach(Object *ob, objects) {
|
foreach(Object *ob, objects) {
|
||||||
Mesh *mesh = ob->mesh;
|
Mesh *mesh = ob->mesh;
|
||||||
|
|
||||||
/* if mesh transform is applied, that means it's already in the top
|
/* We assume that if mesh doesn't need own BVH it was already included
|
||||||
* level BVH, and we don't need to merge it in */
|
* into a top-level BVH and no packing here is needed.
|
||||||
if(mesh->transform_applied) {
|
*/
|
||||||
|
if(!mesh->need_build_bvh()) {
|
||||||
pack.object_node[object_offset++] = 0;
|
pack.object_node[object_offset++] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ void BVHBuild::add_references(BVHRange& root)
|
|||||||
|
|
||||||
foreach(Object *ob, objects) {
|
foreach(Object *ob, objects) {
|
||||||
if(params.top_level) {
|
if(params.top_level) {
|
||||||
if(ob->mesh->transform_applied) {
|
if(!ob->mesh->is_instanced()) {
|
||||||
num_alloc_references += ob->mesh->triangles.size();
|
num_alloc_references += ob->mesh->triangles.size();
|
||||||
num_alloc_references += count_curve_segments(ob->mesh);
|
num_alloc_references += count_curve_segments(ob->mesh);
|
||||||
}
|
}
|
||||||
@ -201,7 +201,7 @@ void BVHBuild::add_references(BVHRange& root)
|
|||||||
|
|
||||||
foreach(Object *ob, objects) {
|
foreach(Object *ob, objects) {
|
||||||
if(params.top_level) {
|
if(params.top_level) {
|
||||||
if(ob->mesh->transform_applied)
|
if(!ob->mesh->is_instanced())
|
||||||
add_reference_mesh(bounds, center, ob->mesh, i);
|
add_reference_mesh(bounds, center, ob->mesh, i);
|
||||||
else
|
else
|
||||||
add_reference_object(bounds, center, ob, i);
|
add_reference_object(bounds, center, ob, i);
|
||||||
|
@ -91,27 +91,9 @@ CCL_NAMESPACE_BEGIN
|
|||||||
#include "geom_bvh_subsurface.h"
|
#include "geom_bvh_subsurface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__SUBSURFACE__) && defined(__INSTANCING__)
|
|
||||||
#define BVH_FUNCTION_NAME bvh_intersect_subsurface_instancing
|
|
||||||
#define BVH_FUNCTION_FEATURES BVH_INSTANCING
|
|
||||||
#include "geom_bvh_subsurface.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__SUBSURFACE__) && defined(__HAIR__)
|
|
||||||
#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair
|
|
||||||
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
|
|
||||||
#include "geom_bvh_subsurface.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
|
#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
|
||||||
#define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
|
#define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
|
||||||
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
|
#define BVH_FUNCTION_FEATURES BVH_MOTION
|
||||||
#include "geom_bvh_subsurface.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__SUBSURFACE__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
|
||||||
#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair_motion
|
|
||||||
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
|
|
||||||
#include "geom_bvh_subsurface.h"
|
#include "geom_bvh_subsurface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -269,17 +251,6 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg,
|
|||||||
{
|
{
|
||||||
#ifdef __OBJECT_MOTION__
|
#ifdef __OBJECT_MOTION__
|
||||||
if(kernel_data.bvh.have_motion) {
|
if(kernel_data.bvh.have_motion) {
|
||||||
#ifdef __HAIR__
|
|
||||||
if(kernel_data.bvh.have_curves) {
|
|
||||||
return bvh_intersect_subsurface_hair_motion(kg,
|
|
||||||
ray,
|
|
||||||
ss_isect,
|
|
||||||
subsurface_object,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
#endif /* __HAIR__ */
|
|
||||||
|
|
||||||
return bvh_intersect_subsurface_motion(kg,
|
return bvh_intersect_subsurface_motion(kg,
|
||||||
ray,
|
ray,
|
||||||
ss_isect,
|
ss_isect,
|
||||||
@ -288,56 +259,12 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg,
|
|||||||
max_hits);
|
max_hits);
|
||||||
}
|
}
|
||||||
#endif /* __OBJECT_MOTION__ */
|
#endif /* __OBJECT_MOTION__ */
|
||||||
|
|
||||||
#ifdef __HAIR__
|
|
||||||
if(kernel_data.bvh.have_curves) {
|
|
||||||
return bvh_intersect_subsurface_hair(kg,
|
|
||||||
ray,
|
|
||||||
ss_isect,
|
|
||||||
subsurface_object,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
#endif /* __HAIR__ */
|
|
||||||
|
|
||||||
#ifdef __KERNEL_CPU__
|
|
||||||
|
|
||||||
#ifdef __INSTANCING__
|
|
||||||
if(kernel_data.bvh.have_instancing) {
|
|
||||||
return bvh_intersect_subsurface_instancing(kg,
|
|
||||||
ray,
|
|
||||||
ss_isect,
|
|
||||||
subsurface_object,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
#endif /* __INSTANCING__ */
|
|
||||||
|
|
||||||
return bvh_intersect_subsurface(kg,
|
return bvh_intersect_subsurface(kg,
|
||||||
ray,
|
ray,
|
||||||
ss_isect,
|
ss_isect,
|
||||||
subsurface_object,
|
subsurface_object,
|
||||||
lcg_state,
|
lcg_state,
|
||||||
max_hits);
|
max_hits);
|
||||||
#else /* __KERNEL_CPU__ */
|
|
||||||
|
|
||||||
#ifdef __INSTANCING__
|
|
||||||
return bvh_intersect_subsurface_instancing(kg,
|
|
||||||
ray,
|
|
||||||
ss_isect,
|
|
||||||
subsurface_object,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
#else
|
|
||||||
return bvh_intersect_subsurface(kg,
|
|
||||||
ray,
|
|
||||||
ss_isect,
|
|
||||||
subsurface_object,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
#endif /* __INSTANCING__ */
|
|
||||||
|
|
||||||
#endif /* __KERNEL_CPU__ */
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
* various features can be enabled/disabled. This way we can compile optimized
|
* various features can be enabled/disabled. This way we can compile optimized
|
||||||
* versions for each case without new features slowing things down.
|
* versions for each case without new features slowing things down.
|
||||||
*
|
*
|
||||||
* BVH_INSTANCING: object instancing
|
|
||||||
* BVH_MOTION: motion blur rendering
|
* BVH_MOTION: motion blur rendering
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -41,7 +40,6 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
|||||||
* - test if pushing distance on the stack helps (for non shadow rays)
|
* - test if pushing distance on the stack helps (for non shadow rays)
|
||||||
* - separate version for shadow rays
|
* - separate version for shadow rays
|
||||||
* - likely and unlikely for if() statements
|
* - likely and unlikely for if() statements
|
||||||
* - SSE for hair
|
|
||||||
* - test restrict attribute for pointers
|
* - test restrict attribute for pointers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -51,7 +49,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* traversal variables in registers */
|
/* traversal variables in registers */
|
||||||
int stackPtr = 0;
|
int stackPtr = 0;
|
||||||
int nodeAddr = kernel_data.bvh.root;
|
int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
|
||||||
|
|
||||||
/* ray parameters in registers */
|
/* ray parameters in registers */
|
||||||
float3 P = ray->P;
|
float3 P = ray->P;
|
||||||
@ -62,9 +60,23 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
|||||||
|
|
||||||
ss_isect->num_hits = 0;
|
ss_isect->num_hits = 0;
|
||||||
|
|
||||||
|
const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
|
||||||
|
if(!(object_flag & SD_TRANSFORM_APPLIED)) {
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
#if BVH_FEATURE(BVH_MOTION)
|
||||||
Transform ob_itfm;
|
Transform ob_itfm;
|
||||||
|
bvh_instance_motion_push(kg,
|
||||||
|
subsurface_object,
|
||||||
|
ray,
|
||||||
|
&P,
|
||||||
|
&dir,
|
||||||
|
&idir,
|
||||||
|
&isect_t,
|
||||||
|
&ob_itfm);
|
||||||
|
#else
|
||||||
|
bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, &isect_t);
|
||||||
#endif
|
#endif
|
||||||
|
object = subsurface_object;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__KERNEL_SSE2__)
|
#if defined(__KERNEL_SSE2__)
|
||||||
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
|
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
|
||||||
@ -190,133 +202,56 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
|||||||
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
|
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
|
||||||
int primAddr = __float_as_int(leaf.x);
|
int primAddr = __float_as_int(leaf.x);
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
const int primAddr2 = __float_as_int(leaf.y);
|
||||||
if(primAddr >= 0) {
|
const uint type = __float_as_int(leaf.w);
|
||||||
#endif
|
|
||||||
const int primAddr2 = __float_as_int(leaf.y);
|
|
||||||
const uint type = __float_as_int(leaf.w);
|
|
||||||
|
|
||||||
/* pop */
|
/* pop */
|
||||||
nodeAddr = traversalStack[stackPtr];
|
nodeAddr = traversalStack[stackPtr];
|
||||||
--stackPtr;
|
--stackPtr;
|
||||||
|
|
||||||
/* primitive intersection */
|
/* primitive intersection */
|
||||||
switch(type & PRIMITIVE_ALL) {
|
switch(type & PRIMITIVE_ALL) {
|
||||||
case PRIMITIVE_TRIANGLE: {
|
case PRIMITIVE_TRIANGLE: {
|
||||||
/* intersect ray against primitive */
|
/* intersect ray against primitive */
|
||||||
for(; primAddr < primAddr2; primAddr++) {
|
for(; primAddr < primAddr2; primAddr++) {
|
||||||
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
||||||
/* only primitives from the same object */
|
triangle_intersect_subsurface(kg,
|
||||||
uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
|
&isect_precalc,
|
||||||
if(tri_object != subsurface_object)
|
ss_isect,
|
||||||
continue;
|
P,
|
||||||
triangle_intersect_subsurface(kg,
|
object,
|
||||||
&isect_precalc,
|
primAddr,
|
||||||
ss_isect,
|
isect_t,
|
||||||
P,
|
lcg_state,
|
||||||
object,
|
max_hits);
|
||||||
primAddr,
|
|
||||||
isect_t,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
|
||||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
|
||||||
/* intersect ray against primitive */
|
|
||||||
for(; primAddr < primAddr2; primAddr++) {
|
|
||||||
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
|
||||||
/* only primitives from the same object */
|
|
||||||
uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
|
|
||||||
if(tri_object != subsurface_object)
|
|
||||||
continue;
|
|
||||||
motion_triangle_intersect_subsurface(kg,
|
|
||||||
ss_isect,
|
|
||||||
P,
|
|
||||||
dir,
|
|
||||||
ray->time,
|
|
||||||
object,
|
|
||||||
primAddr,
|
|
||||||
isect_t,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
|
||||||
else {
|
|
||||||
/* instance push */
|
|
||||||
if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
|
|
||||||
object = subsurface_object;
|
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
#if BVH_FEATURE(BVH_MOTION)
|
||||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
|
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||||
#else
|
/* intersect ray against primitive */
|
||||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
|
for(; primAddr < primAddr2; primAddr++) {
|
||||||
#endif
|
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
||||||
triangle_intersect_precalc(dir, &isect_precalc);
|
motion_triangle_intersect_subsurface(kg,
|
||||||
|
ss_isect,
|
||||||
#if defined(__KERNEL_SSE2__)
|
P,
|
||||||
Psplat[0] = ssef(P.x);
|
dir,
|
||||||
Psplat[1] = ssef(P.y);
|
ray->time,
|
||||||
Psplat[2] = ssef(P.z);
|
object,
|
||||||
|
primAddr,
|
||||||
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
|
isect_t,
|
||||||
|
lcg_state,
|
||||||
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
|
max_hits);
|
||||||
#endif
|
}
|
||||||
|
break;
|
||||||
++stackPtr;
|
|
||||||
kernel_assert(stackPtr < BVH_STACK_SIZE);
|
|
||||||
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
|
|
||||||
|
|
||||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
|
||||||
}
|
}
|
||||||
else {
|
#endif
|
||||||
/* pop */
|
default: {
|
||||||
nodeAddr = traversalStack[stackPtr];
|
break;
|
||||||
--stackPtr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* FEATURE(BVH_INSTANCING) */
|
|
||||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
|
||||||
if(stackPtr >= 0) {
|
|
||||||
kernel_assert(object != OBJECT_NONE);
|
|
||||||
|
|
||||||
/* instance pop */
|
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
|
||||||
bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
|
|
||||||
#else
|
|
||||||
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect_t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
triangle_intersect_precalc(dir, &isect_precalc);
|
|
||||||
|
|
||||||
#if defined(__KERNEL_SSE2__)
|
|
||||||
Psplat[0] = ssef(P.x);
|
|
||||||
Psplat[1] = ssef(P.y);
|
|
||||||
Psplat[2] = ssef(P.z);
|
|
||||||
|
|
||||||
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
|
|
||||||
|
|
||||||
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
object = OBJECT_NONE;
|
|
||||||
nodeAddr = traversalStack[stackPtr];
|
|
||||||
--stackPtr;
|
|
||||||
}
|
|
||||||
#endif /* FEATURE(BVH_INSTANCING) */
|
|
||||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
* various features can be enabled/disabled. This way we can compile optimized
|
* various features can be enabled/disabled. This way we can compile optimized
|
||||||
* versions for each case without new features slowing things down.
|
* versions for each case without new features slowing things down.
|
||||||
*
|
*
|
||||||
* BVH_INSTANCING: object instancing
|
|
||||||
* BVH_MOTION: motion blur rendering
|
* BVH_MOTION: motion blur rendering
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -47,7 +46,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* Traversal variables in registers. */
|
/* Traversal variables in registers. */
|
||||||
int stackPtr = 0;
|
int stackPtr = 0;
|
||||||
int nodeAddr = kernel_data.bvh.root;
|
int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
|
||||||
|
|
||||||
/* Ray parameters in registers. */
|
/* Ray parameters in registers. */
|
||||||
float3 P = ray->P;
|
float3 P = ray->P;
|
||||||
@ -58,9 +57,23 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
|||||||
|
|
||||||
ss_isect->num_hits = 0;
|
ss_isect->num_hits = 0;
|
||||||
|
|
||||||
|
const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
|
||||||
|
if(!(object_flag & SD_TRANSFORM_APPLIED)) {
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
#if BVH_FEATURE(BVH_MOTION)
|
||||||
Transform ob_itfm;
|
Transform ob_itfm;
|
||||||
|
bvh_instance_motion_push(kg,
|
||||||
|
subsurface_object,
|
||||||
|
ray,
|
||||||
|
&P,
|
||||||
|
&dir,
|
||||||
|
&idir,
|
||||||
|
&isect_t,
|
||||||
|
&ob_itfm);
|
||||||
|
#else
|
||||||
|
bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, &isect_t);
|
||||||
#endif
|
#endif
|
||||||
|
object = subsurface_object;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __KERNEL_SSE41__
|
#ifndef __KERNEL_SSE41__
|
||||||
if(!isfinite(P.x)) {
|
if(!isfinite(P.x)) {
|
||||||
@ -206,137 +219,54 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
|||||||
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
|
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
|
||||||
int primAddr = __float_as_int(leaf.x);
|
int primAddr = __float_as_int(leaf.x);
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
int primAddr2 = __float_as_int(leaf.y);
|
||||||
if(primAddr >= 0) {
|
const uint type = __float_as_int(leaf.w);
|
||||||
#endif
|
|
||||||
int primAddr2 = __float_as_int(leaf.y);
|
|
||||||
const uint type = __float_as_int(leaf.w);
|
|
||||||
|
|
||||||
/* Pop. */
|
/* Pop. */
|
||||||
nodeAddr = traversalStack[stackPtr].addr;
|
nodeAddr = traversalStack[stackPtr].addr;
|
||||||
--stackPtr;
|
--stackPtr;
|
||||||
|
|
||||||
/* Primitive intersection. */
|
/* Primitive intersection. */
|
||||||
switch(type & PRIMITIVE_ALL) {
|
switch(type & PRIMITIVE_ALL) {
|
||||||
case PRIMITIVE_TRIANGLE: {
|
case PRIMITIVE_TRIANGLE: {
|
||||||
/* Intersect ray against primitive, */
|
/* Intersect ray against primitive, */
|
||||||
for(; primAddr < primAddr2; primAddr++) {
|
for(; primAddr < primAddr2; primAddr++) {
|
||||||
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
||||||
/* Only primitives from the same object. */
|
triangle_intersect_subsurface(kg,
|
||||||
uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
|
&isect_precalc,
|
||||||
if(tri_object != subsurface_object) {
|
ss_isect,
|
||||||
continue;
|
P,
|
||||||
}
|
object,
|
||||||
triangle_intersect_subsurface(kg,
|
primAddr,
|
||||||
&isect_precalc,
|
isect_t,
|
||||||
ss_isect,
|
lcg_state,
|
||||||
P,
|
max_hits);
|
||||||
object,
|
|
||||||
primAddr,
|
|
||||||
isect_t,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
#if BVH_FEATURE(BVH_MOTION)
|
||||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||||
/* Intersect ray against primitive. */
|
/* Intersect ray against primitive. */
|
||||||
for(; primAddr < primAddr2; primAddr++) {
|
for(; primAddr < primAddr2; primAddr++) {
|
||||||
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
|
||||||
/* Only primitives from the same object. */
|
motion_triangle_intersect_subsurface(kg,
|
||||||
uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
|
ss_isect,
|
||||||
if(tri_object != subsurface_object) {
|
P,
|
||||||
continue;
|
dir,
|
||||||
}
|
ray->time,
|
||||||
motion_triangle_intersect_subsurface(kg,
|
object,
|
||||||
ss_isect,
|
primAddr,
|
||||||
P,
|
isect_t,
|
||||||
dir,
|
lcg_state,
|
||||||
ray->time,
|
max_hits);
|
||||||
object,
|
|
||||||
primAddr,
|
|
||||||
isect_t,
|
|
||||||
lcg_state,
|
|
||||||
max_hits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#endif
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
|
||||||
else {
|
|
||||||
/* Instance push. */
|
|
||||||
if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
|
|
||||||
object = subsurface_object;
|
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
|
||||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
|
|
||||||
#else
|
|
||||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
|
|
||||||
#endif
|
#endif
|
||||||
|
default:
|
||||||
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
|
break;
|
||||||
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
|
|
||||||
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
|
|
||||||
tfar = ssef(isect_t);
|
|
||||||
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
|
|
||||||
#ifdef __KERNEL_AVX2__
|
|
||||||
P_idir = P*idir;
|
|
||||||
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
|
|
||||||
#else
|
|
||||||
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
|
|
||||||
#endif
|
|
||||||
triangle_intersect_precalc(dir, &isect_precalc);
|
|
||||||
|
|
||||||
++stackPtr;
|
|
||||||
kernel_assert(stackPtr < BVH_QSTACK_SIZE);
|
|
||||||
traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
|
|
||||||
|
|
||||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Pop. */
|
|
||||||
nodeAddr = traversalStack[stackPtr].addr;
|
|
||||||
--stackPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* FEATURE(BVH_INSTANCING) */
|
|
||||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
|
|
||||||
#if BVH_FEATURE(BVH_INSTANCING)
|
|
||||||
if(stackPtr >= 0) {
|
|
||||||
kernel_assert(object != OBJECT_NONE);
|
|
||||||
|
|
||||||
/* Instance pop. */
|
|
||||||
#if BVH_FEATURE(BVH_MOTION)
|
|
||||||
bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
|
|
||||||
#else
|
|
||||||
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect_t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
|
|
||||||
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
|
|
||||||
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
|
|
||||||
tfar = ssef(isect_t);
|
|
||||||
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
|
|
||||||
#ifdef __KERNEL_AVX2__
|
|
||||||
P_idir = P*idir;
|
|
||||||
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
|
|
||||||
#else
|
|
||||||
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
|
|
||||||
#endif
|
|
||||||
triangle_intersect_precalc(dir, &isect_precalc);
|
|
||||||
|
|
||||||
object = OBJECT_NONE;
|
|
||||||
nodeAddr = traversalStack[stackPtr].addr;
|
|
||||||
--stackPtr;
|
|
||||||
}
|
|
||||||
#endif /* FEATURE(BVH_INSTANCING) */
|
|
||||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ Mesh::Mesh()
|
|||||||
curve_attributes.curve_mesh = this;
|
curve_attributes.curve_mesh = this;
|
||||||
|
|
||||||
has_volume = false;
|
has_volume = false;
|
||||||
|
has_surface_bssrdf = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::~Mesh()
|
Mesh::~Mesh()
|
||||||
@ -490,7 +491,7 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
|
|||||||
|
|
||||||
compute_bounds();
|
compute_bounds();
|
||||||
|
|
||||||
if(!transform_applied) {
|
if(need_build_bvh()) {
|
||||||
string msg = "Updating Mesh BVH ";
|
string msg = "Updating Mesh BVH ";
|
||||||
if(name == "")
|
if(name == "")
|
||||||
msg += string_printf("%u/%u", (uint)(n+1), (uint)total);
|
msg += string_printf("%u/%u", (uint)(n+1), (uint)total);
|
||||||
@ -550,6 +551,21 @@ bool Mesh::has_motion_blur() const
|
|||||||
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
|
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mesh::need_build_bvh() const
|
||||||
|
{
|
||||||
|
return !transform_applied || has_surface_bssrdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh::is_instanced() const
|
||||||
|
{
|
||||||
|
/* Currently we treat subsurface objects as instanced.
|
||||||
|
*
|
||||||
|
* While it might be not very optimal for ray traversal, it avoids having
|
||||||
|
* duplicated BVH in the memory, saving quite some space.
|
||||||
|
*/
|
||||||
|
return !transform_applied || has_surface_bssrdf;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mesh Manager */
|
/* Mesh Manager */
|
||||||
|
|
||||||
MeshManager::MeshManager()
|
MeshManager::MeshManager()
|
||||||
@ -1142,10 +1158,14 @@ void MeshManager::device_update_flags(Device * /*device*/,
|
|||||||
/* update flags */
|
/* update flags */
|
||||||
foreach(Mesh *mesh, scene->meshes) {
|
foreach(Mesh *mesh, scene->meshes) {
|
||||||
mesh->has_volume = false;
|
mesh->has_volume = false;
|
||||||
foreach(uint shader, mesh->used_shaders) {
|
foreach(uint shader_index, mesh->used_shaders) {
|
||||||
if(scene->shaders[shader]->has_volume) {
|
const Shader *shader = scene->shaders[shader_index];
|
||||||
|
if(shader->has_volume) {
|
||||||
mesh->has_volume = true;
|
mesh->has_volume = true;
|
||||||
}
|
}
|
||||||
|
if(shader->has_surface_bssrdf) {
|
||||||
|
mesh->has_surface_bssrdf = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
need_flags_update = false;
|
need_flags_update = false;
|
||||||
@ -1278,7 +1298,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
|
|||||||
size_t i = 0, num_bvh = 0;
|
size_t i = 0, num_bvh = 0;
|
||||||
|
|
||||||
foreach(Mesh *mesh, scene->meshes)
|
foreach(Mesh *mesh, scene->meshes)
|
||||||
if(mesh->need_update && !mesh->transform_applied)
|
if(mesh->need_update && mesh->need_build_bvh())
|
||||||
num_bvh++;
|
num_bvh++;
|
||||||
|
|
||||||
TaskPool pool;
|
TaskPool pool;
|
||||||
@ -1291,7 +1311,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
|
|||||||
&progress,
|
&progress,
|
||||||
i,
|
i,
|
||||||
num_bvh));
|
num_bvh));
|
||||||
if(!mesh->transform_applied) {
|
if(mesh->need_build_bvh()) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ public:
|
|||||||
vector<bool> smooth;
|
vector<bool> smooth;
|
||||||
|
|
||||||
bool has_volume; /* Set in the device_update_flags(). */
|
bool has_volume; /* Set in the device_update_flags(). */
|
||||||
|
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
|
||||||
|
|
||||||
vector<float4> curve_keys; /* co + radius */
|
vector<float4> curve_keys; /* co + radius */
|
||||||
vector<Curve> curves;
|
vector<Curve> curves;
|
||||||
@ -143,6 +144,19 @@ public:
|
|||||||
void tag_update(Scene *scene, bool rebuild);
|
void tag_update(Scene *scene, bool rebuild);
|
||||||
|
|
||||||
bool has_motion_blur() const;
|
bool has_motion_blur() const;
|
||||||
|
|
||||||
|
/* Check whether the mesh should have own BVH built separately. Briefly,
|
||||||
|
* own BVH is needed for mesh, if:
|
||||||
|
*
|
||||||
|
* - It is instanced multiple times, so each instance object should share the
|
||||||
|
* same BVH tree.
|
||||||
|
* - Special ray intersection is needed, for example to limit subsurface rays
|
||||||
|
* to only the mesh itself.
|
||||||
|
*/
|
||||||
|
bool need_build_bvh() const;
|
||||||
|
|
||||||
|
/* Check if the mesh should be treated as instanced. */
|
||||||
|
bool is_instanced() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mesh Manager */
|
/* Mesh Manager */
|
||||||
|
@ -512,7 +512,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
|
|||||||
|
|
||||||
/* apply transforms for objects with single user meshes */
|
/* apply transforms for objects with single user meshes */
|
||||||
foreach(Object *object, scene->objects) {
|
foreach(Object *object, scene->objects) {
|
||||||
if(mesh_users[object->mesh] == 1 &&
|
if((mesh_users[object->mesh] == 1 && !object->mesh->is_instanced()) &&
|
||||||
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
|
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
|
||||||
{
|
{
|
||||||
if(!(motion_blur && object->use_motion)) {
|
if(!(motion_blur && object->use_motion)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user