This add support for rendering of the point cloud object in Blender, as a native geometry type in Cycles that is more memory and time efficient than instancing sphere meshes. This can be useful for rendering sand, water splashes, particles, motion graphics, etc. Points are currently always rendered as spheres, with backface culling. More shapes are likely to be added later, but this is the most important one and can be customized with shaders. For CPU rendering the Embree primitive is used, for GPU there is our own intersection code. Motion blur is suppored. Volumes inside points are not currently supported. Implemented with help from: * Kévin Dietrich: Alembic procedural integration * Patrick Mourse: OptiX integration * Josh Whelchel: update for cycles-x changes Ref T92573 Differential Revision: https://developer.blender.org/D9887
842 lines
25 KiB
C
842 lines
25 KiB
C
/*
|
|
* Copyright 2011-2013 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* BVH
|
|
*
|
|
* Bounding volume hierarchy for ray tracing. We compile different variations
|
|
* of the same BVH traversal function for faster rendering when some types of
|
|
* primitives are not needed, using #includes to work around the lack of
|
|
* C++ templates in OpenCL.
|
|
*
|
|
* Originally based on "Understanding the Efficiency of Ray Traversal on GPUs",
|
|
* the code has been extended and modified to support more primitives and work
|
|
* with CPU/CUDA/OpenCL. */
|
|
|
|
#pragma once
|
|
|
|
#ifdef __EMBREE__
|
|
# include "kernel/bvh/embree.h"
|
|
#endif
|
|
|
|
#ifdef __METALRT__
|
|
# include "kernel/bvh/metal.h"
|
|
#endif
|
|
|
|
#include "kernel/bvh/types.h"
|
|
#include "kernel/bvh/util.h"
|
|
|
|
#include "kernel/integrator/state_util.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
#if !defined(__KERNEL_GPU_RAYTRACING__)
|
|
|
|
/* Regular BVH traversal */
|
|
|
|
# include "kernel/bvh/nodes.h"
|
|
|
|
# define BVH_FUNCTION_NAME bvh_intersect
|
|
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
|
# include "kernel/bvh/traversal.h"
|
|
|
|
# if defined(__HAIR__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_hair
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
|
# include "kernel/bvh/traversal.h"
|
|
# endif
|
|
|
|
# if defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
|
# include "kernel/bvh/traversal.h"
|
|
# endif
|
|
|
|
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
|
# include "kernel/bvh/traversal.h"
|
|
# endif
|
|
|
|
/* Subsurface scattering BVH traversal */
|
|
|
|
# if defined(__BVH_LOCAL__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_local
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
|
# include "kernel/bvh/local.h"
|
|
|
|
# if defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_local_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
|
# include "kernel/bvh/local.h"
|
|
# endif
|
|
# endif /* __BVH_LOCAL__ */
|
|
|
|
/* Volume BVH traversal */
|
|
|
|
# if defined(__VOLUME__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_volume
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
|
# include "kernel/bvh/volume.h"
|
|
|
|
# if defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
|
# include "kernel/bvh/volume.h"
|
|
# endif
|
|
# endif /* __VOLUME__ */
|
|
|
|
/* Record all intersections - Shadow BVH traversal */
|
|
|
|
# if defined(__SHADOW_RECORD_ALL__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
|
|
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
|
# include "kernel/bvh/shadow_all.h"
|
|
|
|
# if defined(__HAIR__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
|
# include "kernel/bvh/shadow_all.h"
|
|
# endif
|
|
|
|
# if defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
|
# include "kernel/bvh/shadow_all.h"
|
|
# endif
|
|
|
|
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
|
# include "kernel/bvh/shadow_all.h"
|
|
# endif
|
|
|
|
# endif /* __SHADOW_RECORD_ALL__ */
|
|
|
|
/* Record all intersections - Volume BVH traversal. */
|
|
|
|
# if defined(__VOLUME_RECORD_ALL__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_volume_all
|
|
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
|
# include "kernel/bvh/volume_all.h"
|
|
|
|
# if defined(__OBJECT_MOTION__)
|
|
# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
|
|
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
|
# include "kernel/bvh/volume_all.h"
|
|
# endif
|
|
# endif /* __VOLUME_RECORD_ALL__ */
|
|
|
|
# undef BVH_FEATURE
|
|
# undef BVH_NAME_JOIN
|
|
# undef BVH_NAME_EVAL
|
|
# undef BVH_FUNCTION_FULL_NAME
|
|
|
|
#endif /* !defined(__KERNEL_GPU_RAYTRACING__) */
|
|
|
|
ccl_device_inline bool scene_intersect_valid(ccl_private const Ray *ray)
|
|
{
|
|
/* NOTE: Due to some vectorization code non-finite origin point might
|
|
* cause lots of false-positive intersections which will overflow traversal
|
|
* stack.
|
|
* This code is a quick way to perform early output, to avoid crashes in
|
|
* such cases.
|
|
* From production scenes so far it seems it's enough to test first element
|
|
* only.
|
|
* Scene intersection may also called with empty rays for conditional trace
|
|
* calls that evaluate to false, so filter those out.
|
|
*/
|
|
return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f;
|
|
}
|
|
|
|
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
|
ccl_private const Ray *ray,
|
|
const uint visibility,
|
|
ccl_private Intersection *isect)
|
|
{
|
|
#ifdef __KERNEL_OPTIX__
|
|
uint p0 = 0;
|
|
uint p1 = 0;
|
|
uint p2 = 0;
|
|
uint p3 = 0;
|
|
uint p4 = visibility;
|
|
uint p5 = PRIMITIVE_NONE;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
uint ray_flags = OPTIX_RAY_FLAG_NONE;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
|
|
}
|
|
else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
|
ray_flags = OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
|
|
}
|
|
|
|
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
|
|
ray->P,
|
|
ray->D,
|
|
0.0f,
|
|
ray->t,
|
|
ray->time,
|
|
ray_mask,
|
|
ray_flags,
|
|
0, /* SBT offset for PG_HITD */
|
|
0,
|
|
0,
|
|
p0,
|
|
p1,
|
|
p2,
|
|
p3,
|
|
p4,
|
|
p5);
|
|
|
|
isect->t = __uint_as_float(p0);
|
|
isect->u = __uint_as_float(p1);
|
|
isect->v = __uint_as_float(p2);
|
|
isect->prim = p3;
|
|
isect->object = p4;
|
|
isect->type = p5;
|
|
|
|
return p5 != PRIMITIVE_NONE;
|
|
#elif defined(__METALRT__)
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
isect->t = ray->t;
|
|
isect->type = PRIMITIVE_NONE;
|
|
return false;
|
|
}
|
|
|
|
# if defined(__KERNEL_DEBUG__)
|
|
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
|
isect->t = ray->t;
|
|
isect->type = PRIMITIVE_NONE;
|
|
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
|
return false;
|
|
}
|
|
|
|
if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
|
|
isect->t = ray->t;
|
|
isect->type = PRIMITIVE_NONE;
|
|
kernel_assert(!"Invalid ift_default");
|
|
return false;
|
|
}
|
|
# endif
|
|
|
|
metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
|
|
metalrt_intersector_type metalrt_intersect;
|
|
|
|
if (!kernel_data.bvh.have_curves) {
|
|
metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
|
|
}
|
|
|
|
MetalRTIntersectionPayload payload;
|
|
payload.u = 0.0f;
|
|
payload.v = 0.0f;
|
|
payload.visibility = visibility;
|
|
|
|
typename metalrt_intersector_type::result_type intersection;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
/* No further intersector setup required: Default MetalRT behavior is any-hit. */
|
|
}
|
|
else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
|
/* No further intersector setup required: Shadow ray early termination is controlled by the
|
|
* intersection handler */
|
|
}
|
|
|
|
# if defined(__METALRT_MOTION__)
|
|
payload.time = ray->time;
|
|
intersection = metalrt_intersect.intersect(r,
|
|
metal_ancillaries->accel_struct,
|
|
ray_mask,
|
|
ray->time,
|
|
metal_ancillaries->ift_default,
|
|
payload);
|
|
# else
|
|
intersection = metalrt_intersect.intersect(
|
|
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
|
|
# endif
|
|
|
|
if (intersection.type == intersection_type::none) {
|
|
isect->t = ray->t;
|
|
isect->type = PRIMITIVE_NONE;
|
|
|
|
return false;
|
|
}
|
|
|
|
isect->t = intersection.distance;
|
|
|
|
isect->prim = payload.prim;
|
|
isect->type = payload.type;
|
|
isect->object = intersection.user_instance_id;
|
|
|
|
isect->t = intersection.distance;
|
|
if (intersection.type == intersection_type::triangle) {
|
|
isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
|
|
intersection.triangle_barycentric_coord.x;
|
|
isect->v = intersection.triangle_barycentric_coord.x;
|
|
}
|
|
else {
|
|
isect->u = payload.u;
|
|
isect->v = payload.v;
|
|
}
|
|
|
|
return isect->type != PRIMITIVE_NONE;
|
|
|
|
#else
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
# ifdef __EMBREE__
|
|
if (kernel_data.bvh.scene) {
|
|
isect->t = ray->t;
|
|
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
|
|
IntersectContext rtc_ctx(&ctx);
|
|
RTCRayHit ray_hit;
|
|
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
|
|
rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit);
|
|
if (ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID &&
|
|
ray_hit.hit.primID != RTC_INVALID_GEOMETRY_ID) {
|
|
kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
# endif /* __EMBREE__ */
|
|
|
|
# ifdef __OBJECT_MOTION__
|
|
if (kernel_data.bvh.have_motion) {
|
|
# ifdef __HAIR__
|
|
if (kernel_data.bvh.have_curves) {
|
|
return bvh_intersect_hair_motion(kg, ray, isect, visibility);
|
|
}
|
|
# endif /* __HAIR__ */
|
|
|
|
return bvh_intersect_motion(kg, ray, isect, visibility);
|
|
}
|
|
# endif /* __OBJECT_MOTION__ */
|
|
|
|
# ifdef __HAIR__
|
|
if (kernel_data.bvh.have_curves) {
|
|
return bvh_intersect_hair(kg, ray, isect, visibility);
|
|
}
|
|
# endif /* __HAIR__ */
|
|
|
|
return bvh_intersect(kg, ray, isect, visibility);
|
|
#endif /* __KERNEL_OPTIX__ */
|
|
}
|
|
|
|
#ifdef __BVH_LOCAL__
|
|
ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
|
ccl_private const Ray *ray,
|
|
ccl_private LocalIntersection *local_isect,
|
|
int local_object,
|
|
ccl_private uint *lcg_state,
|
|
int max_hits)
|
|
{
|
|
# ifdef __KERNEL_OPTIX__
|
|
uint p0 = pointer_pack_to_uint_0(lcg_state);
|
|
uint p1 = pointer_pack_to_uint_1(lcg_state);
|
|
uint p2 = pointer_pack_to_uint_0(local_isect);
|
|
uint p3 = pointer_pack_to_uint_1(local_isect);
|
|
uint p4 = local_object;
|
|
/* Is set to zero on miss or if ray is aborted, so can be used as return value. */
|
|
uint p5 = max_hits;
|
|
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0; /* Initialize hit count to zero. */
|
|
}
|
|
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
|
|
ray->P,
|
|
ray->D,
|
|
0.0f,
|
|
ray->t,
|
|
ray->time,
|
|
0xFF,
|
|
/* Need to always call into __anyhit__kernel_optix_local_hit. */
|
|
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
|
2, /* SBT offset for PG_HITL */
|
|
0,
|
|
0,
|
|
p0,
|
|
p1,
|
|
p2,
|
|
p3,
|
|
p4,
|
|
p5);
|
|
|
|
return p5;
|
|
# elif defined(__METALRT__)
|
|
if (!scene_intersect_valid(ray)) {
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
# if defined(__KERNEL_DEBUG__)
|
|
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
|
return false;
|
|
}
|
|
|
|
if (is_null_intersection_function_table(metal_ancillaries->ift_local)) {
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
kernel_assert(!"Invalid ift_local");
|
|
return false;
|
|
}
|
|
# endif
|
|
|
|
metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
|
|
metalrt_intersector_type metalrt_intersect;
|
|
|
|
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
|
if (!kernel_data.bvh.have_curves) {
|
|
metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
|
|
}
|
|
|
|
MetalRTIntersectionLocalPayload payload;
|
|
payload.local_object = local_object;
|
|
payload.max_hits = max_hits;
|
|
payload.local_isect.num_hits = 0;
|
|
if (lcg_state) {
|
|
payload.has_lcg_state = true;
|
|
payload.lcg_state = *lcg_state;
|
|
}
|
|
payload.result = false;
|
|
|
|
typename metalrt_intersector_type::result_type intersection;
|
|
|
|
# if defined(__METALRT_MOTION__)
|
|
intersection = metalrt_intersect.intersect(
|
|
r, metal_ancillaries->accel_struct, 0xFF, ray->time, metal_ancillaries->ift_local, payload);
|
|
# else
|
|
intersection = metalrt_intersect.intersect(
|
|
r, metal_ancillaries->accel_struct, 0xFF, metal_ancillaries->ift_local, payload);
|
|
# endif
|
|
|
|
if (lcg_state) {
|
|
*lcg_state = payload.lcg_state;
|
|
}
|
|
*local_isect = payload.local_isect;
|
|
|
|
return payload.result;
|
|
|
|
# else
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
# ifdef __EMBREE__
|
|
if (kernel_data.bvh.scene) {
|
|
const bool has_bvh = !(kernel_tex_fetch(__object_flag, local_object) &
|
|
SD_OBJECT_TRANSFORM_APPLIED);
|
|
CCLIntersectContext ctx(
|
|
kg, has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
|
|
ctx.lcg_state = lcg_state;
|
|
ctx.max_hits = max_hits;
|
|
ctx.local_isect = local_isect;
|
|
if (local_isect) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
ctx.local_object_id = local_object;
|
|
IntersectContext rtc_ctx(&ctx);
|
|
RTCRay rtc_ray;
|
|
kernel_embree_setup_ray(*ray, rtc_ray, PATH_RAY_ALL_VISIBILITY);
|
|
|
|
/* If this object has its own BVH, use it. */
|
|
if (has_bvh) {
|
|
RTCGeometry geom = rtcGetGeometry(kernel_data.bvh.scene, local_object * 2);
|
|
if (geom) {
|
|
float3 P = ray->P;
|
|
float3 dir = ray->D;
|
|
float3 idir = ray->D;
|
|
Transform ob_itfm;
|
|
rtc_ray.tfar = ray->t *
|
|
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
|
|
/* bvh_instance_motion_push() returns the inverse transform but
|
|
* it's not needed here. */
|
|
(void)ob_itfm;
|
|
|
|
rtc_ray.org_x = P.x;
|
|
rtc_ray.org_y = P.y;
|
|
rtc_ray.org_z = P.z;
|
|
rtc_ray.dir_x = dir.x;
|
|
rtc_ray.dir_y = dir.y;
|
|
rtc_ray.dir_z = dir.z;
|
|
RTCScene scene = (RTCScene)rtcGetGeometryUserData(geom);
|
|
kernel_assert(scene);
|
|
if (scene) {
|
|
rtcOccluded1(scene, &rtc_ctx.context, &rtc_ray);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
|
|
}
|
|
|
|
/* rtcOccluded1 sets tfar to -inf if a hit was found. */
|
|
return (local_isect && local_isect->num_hits > 0) || (rtc_ray.tfar < 0);
|
|
;
|
|
}
|
|
# endif /* __EMBREE__ */
|
|
|
|
# ifdef __OBJECT_MOTION__
|
|
if (kernel_data.bvh.have_motion) {
|
|
return bvh_intersect_local_motion(kg, ray, local_isect, local_object, lcg_state, max_hits);
|
|
}
|
|
# endif /* __OBJECT_MOTION__ */
|
|
return bvh_intersect_local(kg, ray, local_isect, local_object, lcg_state, max_hits);
|
|
# endif /* __KERNEL_OPTIX__ */
|
|
}
|
|
#endif
|
|
|
|
#ifdef __SHADOW_RECORD_ALL__
|
|
ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
|
IntegratorShadowState state,
|
|
ccl_private const Ray *ray,
|
|
uint visibility,
|
|
uint max_hits,
|
|
ccl_private uint *num_recorded_hits,
|
|
ccl_private float *throughput)
|
|
{
|
|
# ifdef __KERNEL_OPTIX__
|
|
uint p0 = state;
|
|
uint p1 = __float_as_uint(1.0f); /* Throughput. */
|
|
uint p2 = 0; /* Number of hits. */
|
|
uint p3 = max_hits;
|
|
uint p4 = visibility;
|
|
uint p5 = false;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
}
|
|
|
|
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
|
|
ray->P,
|
|
ray->D,
|
|
0.0f,
|
|
ray->t,
|
|
ray->time,
|
|
ray_mask,
|
|
/* Need to always call into __anyhit__kernel_optix_shadow_all_hit. */
|
|
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
|
1, /* SBT offset for PG_HITS */
|
|
0,
|
|
0,
|
|
p0,
|
|
p1,
|
|
p2,
|
|
p3,
|
|
p4,
|
|
p5);
|
|
|
|
*num_recorded_hits = uint16_unpack_from_uint_0(p2);
|
|
*throughput = __uint_as_float(p1);
|
|
|
|
return p5;
|
|
# elif defined(__METALRT__)
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
# if defined(__KERNEL_DEBUG__)
|
|
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
|
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
|
return false;
|
|
}
|
|
|
|
if (is_null_intersection_function_table(metal_ancillaries->ift_shadow)) {
|
|
kernel_assert(!"Invalid ift_shadow");
|
|
return false;
|
|
}
|
|
# endif
|
|
|
|
metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
|
|
metalrt_intersector_type metalrt_intersect;
|
|
|
|
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
|
if (!kernel_data.bvh.have_curves) {
|
|
metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
|
|
}
|
|
|
|
MetalRTIntersectionShadowPayload payload;
|
|
payload.visibility = visibility;
|
|
payload.max_hits = max_hits;
|
|
payload.num_hits = 0;
|
|
payload.num_recorded_hits = 0;
|
|
payload.throughput = 1.0f;
|
|
payload.result = false;
|
|
payload.state = state;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
}
|
|
|
|
typename metalrt_intersector_type::result_type intersection;
|
|
|
|
# if defined(__METALRT_MOTION__)
|
|
payload.time = ray->time;
|
|
intersection = metalrt_intersect.intersect(r,
|
|
metal_ancillaries->accel_struct,
|
|
ray_mask,
|
|
ray->time,
|
|
metal_ancillaries->ift_shadow,
|
|
payload);
|
|
# else
|
|
intersection = metalrt_intersect.intersect(
|
|
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_shadow, payload);
|
|
# endif
|
|
|
|
*num_recorded_hits = payload.num_recorded_hits;
|
|
*throughput = payload.throughput;
|
|
|
|
return payload.result;
|
|
|
|
# else
|
|
if (!scene_intersect_valid(ray)) {
|
|
*num_recorded_hits = 0;
|
|
*throughput = 1.0f;
|
|
return false;
|
|
}
|
|
|
|
# ifdef __EMBREE__
|
|
if (kernel_data.bvh.scene) {
|
|
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
|
|
Intersection *isect_array = (Intersection *)state->shadow_isect;
|
|
ctx.isect_s = isect_array;
|
|
ctx.max_hits = max_hits;
|
|
IntersectContext rtc_ctx(&ctx);
|
|
RTCRay rtc_ray;
|
|
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
|
|
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
|
|
|
|
*num_recorded_hits = ctx.num_recorded_hits;
|
|
*throughput = ctx.throughput;
|
|
return ctx.opaque_hit;
|
|
}
|
|
# endif /* __EMBREE__ */
|
|
|
|
# ifdef __OBJECT_MOTION__
|
|
if (kernel_data.bvh.have_motion) {
|
|
# ifdef __HAIR__
|
|
if (kernel_data.bvh.have_curves) {
|
|
return bvh_intersect_shadow_all_hair_motion(
|
|
kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
|
|
}
|
|
# endif /* __HAIR__ */
|
|
|
|
return bvh_intersect_shadow_all_motion(
|
|
kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
|
|
}
|
|
# endif /* __OBJECT_MOTION__ */
|
|
|
|
# ifdef __HAIR__
|
|
if (kernel_data.bvh.have_curves) {
|
|
return bvh_intersect_shadow_all_hair(
|
|
kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
|
|
}
|
|
# endif /* __HAIR__ */
|
|
|
|
return bvh_intersect_shadow_all(
|
|
kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
|
|
# endif /* __KERNEL_OPTIX__ */
|
|
}
|
|
#endif /* __SHADOW_RECORD_ALL__ */
|
|
|
|
#ifdef __VOLUME__
|
|
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
|
ccl_private const Ray *ray,
|
|
ccl_private Intersection *isect,
|
|
const uint visibility)
|
|
{
|
|
# ifdef __KERNEL_OPTIX__
|
|
uint p0 = 0;
|
|
uint p1 = 0;
|
|
uint p2 = 0;
|
|
uint p3 = 0;
|
|
uint p4 = visibility;
|
|
uint p5 = PRIMITIVE_NONE;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
}
|
|
|
|
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
|
|
ray->P,
|
|
ray->D,
|
|
0.0f,
|
|
ray->t,
|
|
ray->time,
|
|
ray_mask,
|
|
/* Need to always call into __anyhit__kernel_optix_volume_test. */
|
|
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
|
3, /* SBT offset for PG_HITV */
|
|
0,
|
|
0,
|
|
p0,
|
|
p1,
|
|
p2,
|
|
p3,
|
|
p4,
|
|
p5);
|
|
|
|
isect->t = __uint_as_float(p0);
|
|
isect->u = __uint_as_float(p1);
|
|
isect->v = __uint_as_float(p2);
|
|
isect->prim = p3;
|
|
isect->object = p4;
|
|
isect->type = p5;
|
|
|
|
return p5 != PRIMITIVE_NONE;
|
|
# elif defined(__METALRT__)
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
# if defined(__KERNEL_DEBUG__)
|
|
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
|
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
|
return false;
|
|
}
|
|
|
|
if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
|
|
kernel_assert(!"Invalid ift_default");
|
|
return false;
|
|
}
|
|
# endif
|
|
|
|
metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
|
|
metalrt_intersector_type metalrt_intersect;
|
|
|
|
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
|
if (!kernel_data.bvh.have_curves) {
|
|
metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
|
|
}
|
|
|
|
MetalRTIntersectionPayload payload;
|
|
payload.visibility = visibility;
|
|
|
|
typename metalrt_intersector_type::result_type intersection;
|
|
|
|
uint ray_mask = visibility & 0xFF;
|
|
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
|
ray_mask = 0xFF;
|
|
}
|
|
|
|
# if defined(__METALRT_MOTION__)
|
|
payload.time = ray->time;
|
|
intersection = metalrt_intersect.intersect(r,
|
|
metal_ancillaries->accel_struct,
|
|
ray_mask,
|
|
ray->time,
|
|
metal_ancillaries->ift_default,
|
|
payload);
|
|
# else
|
|
intersection = metalrt_intersect.intersect(
|
|
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
|
|
# endif
|
|
|
|
if (intersection.type == intersection_type::none) {
|
|
return false;
|
|
}
|
|
|
|
isect->prim = payload.prim;
|
|
isect->type = payload.type;
|
|
isect->object = intersection.user_instance_id;
|
|
|
|
isect->t = intersection.distance;
|
|
if (intersection.type == intersection_type::triangle) {
|
|
isect->u = 1.0f - intersection.triangle_barycentric_coord.y -
|
|
intersection.triangle_barycentric_coord.x;
|
|
isect->v = intersection.triangle_barycentric_coord.x;
|
|
}
|
|
else {
|
|
isect->u = payload.u;
|
|
isect->v = payload.v;
|
|
}
|
|
|
|
return isect->type != PRIMITIVE_NONE;
|
|
|
|
# else
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
# ifdef __OBJECT_MOTION__
|
|
if (kernel_data.bvh.have_motion) {
|
|
return bvh_intersect_volume_motion(kg, ray, isect, visibility);
|
|
}
|
|
# endif /* __OBJECT_MOTION__ */
|
|
|
|
return bvh_intersect_volume(kg, ray, isect, visibility);
|
|
# endif /* __KERNEL_OPTIX__ */
|
|
}
|
|
#endif /* __VOLUME__ */
|
|
|
|
#ifdef __VOLUME_RECORD_ALL__
|
|
ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg,
|
|
ccl_private const Ray *ray,
|
|
ccl_private Intersection *isect,
|
|
const uint max_hits,
|
|
const uint visibility)
|
|
{
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
# ifdef __EMBREE__
|
|
if (kernel_data.bvh.scene) {
|
|
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
|
|
ctx.isect_s = isect;
|
|
ctx.max_hits = max_hits;
|
|
ctx.num_hits = 0;
|
|
IntersectContext rtc_ctx(&ctx);
|
|
RTCRay rtc_ray;
|
|
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
|
|
rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
|
|
return ctx.num_hits;
|
|
}
|
|
# endif /* __EMBREE__ */
|
|
|
|
# ifdef __OBJECT_MOTION__
|
|
if (kernel_data.bvh.have_motion) {
|
|
return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility);
|
|
}
|
|
# endif /* __OBJECT_MOTION__ */
|
|
|
|
return bvh_intersect_volume_all(kg, ray, isect, max_hits, visibility);
|
|
}
|
|
#endif /* __VOLUME_RECORD_ALL__ */
|
|
|
|
CCL_NAMESPACE_END
|