light: support embree4 in addition to 3

This commit is contained in:
Eric Wasylishen 2023-11-19 14:00:10 -07:00
parent d5ffbd9d33
commit db0951dc40
6 changed files with 88 additions and 18 deletions

View File

@ -145,6 +145,11 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
find_package(TBB REQUIRED)
find_package(embree REQUIRED)
if (embree_VERSION_MAJOR EQUAL 4)
add_compile_definitions(HAVE_EMBREE4)
endif()
set(TEST_QUAKE_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Quake maps to this directory (useful for testing in game)")
set(TEST_QUAKE2_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Quake 2 maps to this directory (useful for testing in game)")
set(TEST_HEXEN2_MAP_EXPORT_DIR "" CACHE PATH "When running unit tests, export Hexen 2 maps to this directory (useful for testing in game)")

View File

@ -100,8 +100,13 @@ public:
inline void clearPushedRays() { _numrays = 0; }
};
#ifdef HAVE_EMBREE4
#include <embree4/rtcore.h>
#include <embree4/rtcore_ray.h>
#else
#include <embree3/rtcore.h>
#include <embree3/rtcore_ray.h>
#endif
extern RTCScene scene;
@ -139,13 +144,22 @@ inline RTCRayHit SetupRay(unsigned rayindex, const qvec3d &start, const qvec3d &
class light_t;
struct ray_source_info : public RTCIntersectContext
struct ray_source_info : public
#ifdef HAVE_EMBREE4
RTCRayQueryContext
#else
RTCIntersectContext
#endif
{
raystream_embree_common_t *raystream; // may be null if this ray is not from a ray stream
const modelinfo_t *self;
int shadowmask;
ray_source_info(raystream_embree_common_t *raystream_, const modelinfo_t *self_, int shadowmask_);
#ifdef HAVE_EMBREE4
RTCIntersectArguments setup_intersection_arguments();
RTCOccludedArguments setup_occluded_arguments();
#endif
};
struct triinfo
@ -238,7 +252,14 @@ public:
return;
ray_source_info ctx2(this, self, shadowmask);
#ifdef HAVE_EMBREE4
RTCIntersectArguments embree4_args = ctx2.setup_intersection_arguments();
for (int i = 0; i < _numrays; ++i)
rtcIntersect1(scene, &_rays[i], &embree4_args);
#else
rtcIntersect1M(scene, &ctx2, _rays.data(), _numrays, sizeof(_rays[0]));
#endif
}
inline qvec3d getPushedRayDir(size_t j) { return {_rays[j].ray.dir_x, _rays[j].ray.dir_y, _rays[j].ray.dir_z}; }
@ -312,7 +333,13 @@ public:
return;
ray_source_info ctx2(this, self, shadowmask);
#ifdef HAVE_EMBREE4
RTCOccludedArguments embree4_args = ctx2.setup_occluded_arguments();
for (int i = 0; i < _numrays; ++i)
rtcOccluded1(scene, &_rays[i], &embree4_args);
#else
rtcOccluded1M(scene, &ctx2, _rays.data(), _numrays, sizeof(_rays[0]));
#endif
}
inline bool getPushedRayOccluded(size_t j) { return (_rays[j].tfar < 0.0f); }

View File

@ -24,8 +24,6 @@ set(LIGHT_SOURCES
surflight.cc
${LIGHT_INCLUDES})
FIND_PACKAGE(embree 3.0 REQUIRED)
if (embree_FOUND)
MESSAGE(STATUS "Embree library found: ${EMBREE_LIBRARY}")
INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS})

View File

@ -289,14 +289,13 @@ inline qvec3f Embree_RayEndpoint(RTCRayN *ray, const qvec3f &dir, size_t N, size
return org + (dir * tfar);
}
static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor);
static void AddDynamicOccluderToRay(RTCIntersectContext *context, unsigned rayIndex, int style);
static void AddGlassToRay(ray_source_info *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor);
static void AddDynamicOccluderToRay(ray_source_info *context, unsigned rayIndex, int style);
// called to evaluate transparency
static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
{
int *const valid = args->valid;
RTCIntersectContext *const context = args->context;
struct RTCRayN *const ray = args->ray;
struct RTCHitN *const potentialHit = args->hit;
const unsigned int N = args->N;
@ -304,7 +303,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
const int VALID = -1;
const int INVALID = 0;
const ray_source_info *rsi = static_cast<const ray_source_info *>(context);
ray_source_info *rsi = static_cast<ray_source_info *>(args->context);
for (size_t i = 0; i < N; i++) {
if (valid[i] != VALID) {
@ -359,7 +358,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
const int style = hit_triinfo.switchshadstyle;
AddDynamicOccluderToRay(context, rayIndex, style);
AddDynamicOccluderToRay(rsi, rayIndex, style);
// reject hit
valid[i] = INVALID;
@ -391,7 +390,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
// only pick up the color of the glass on the _exiting_ side of the glass.
// (we currently trace "backwards", from surface point --> light source)
if (raySurfaceCosAngle < 0) {
AddGlassToRay(context, rayIndex, alpha, sample.xyz() * (1.0 / 255.0));
AddGlassToRay(rsi, rayIndex, alpha, sample.xyz() * (1.0 / 255.0));
}
// reject hit
@ -419,14 +418,13 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
static void PerRay_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
{
int *const valid = args->valid;
RTCIntersectContext *const context = args->context;
struct RTCHitN *const potentialHit = args->hit;
const unsigned int N = args->N;
const int VALID = -1;
const int INVALID = 0;
auto *rsi = static_cast<const ray_source_info *>(context);
auto *rsi = static_cast<ray_source_info *>(args->context);
for (size_t i = 0; i < N; i++) {
if (valid[i] != VALID) {
@ -656,9 +654,16 @@ void Embree_TraceInit(const mbsp_t *bsp)
logging::funcprint("Embree version: {}.{}.{}\n", ver_maj, ver_min, ver_pat);
scene = rtcNewScene(device);
#ifdef HAVE_EMBREE4
// necessary for RTCOccludedArguments::filter and RTCIntersectArguments::filter
// to work, which we use (see: ray_source_info::setup_intersection_arguments() and
// ray_source_info::setup_occluded_arguments())
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS);
#else
// we're using RTCIntersectContext::filter so it's required that we set
// RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION
rtcSetSceneFlags(scene, RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION);
#endif
rtcSetSceneBuildQuality(scene, RTC_BUILD_QUALITY_HIGH);
skygeom = CreateGeometry(bsp, device, scene, skyfaces);
solidgeom = CreateGeometry(bsp, device, scene, solidfaces);
@ -677,9 +682,8 @@ void Embree_TraceInit(const mbsp_t *bsp)
logging::print("\t{} shadow-casting skip faces\n", skipwindings.size());
}
static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float opacity, const qvec3d &glasscolor)
static void AddGlassToRay(ray_source_info *ctx, unsigned rayIndex, float opacity, const qvec3d &glasscolor)
{
ray_source_info *ctx = static_cast<ray_source_info *>(context);
raystream_embree_common_t *rs = ctx->raystream;
if (rs == nullptr) {
@ -698,9 +702,8 @@ static void AddGlassToRay(RTCIntersectContext *context, unsigned rayIndex, float
rs->_ray_glass_opacity[rayIndex] = opacity;
}
static void AddDynamicOccluderToRay(RTCIntersectContext *context, unsigned rayIndex, int style)
static void AddDynamicOccluderToRay(ray_source_info *ctx, unsigned rayIndex, int style)
{
ray_source_info *ctx = static_cast<ray_source_info *>(context);
raystream_embree_common_t *rs = ctx->raystream;
if (rs != nullptr) {
@ -713,12 +716,51 @@ ray_source_info::ray_source_info(raystream_embree_common_t *raystream_, const mo
self(self_),
shadowmask(shadowmask_)
{
#ifdef HAVE_EMBREE4
rtcInitRayQueryContext(this);
#else
rtcInitIntersectContext(this);
flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT;
if (shadowmask != CHANNEL_MASK_DEFAULT) {
// non-default shadow mask means we have to use the slow path
filter = PerRay_FilterFuncN;
}
#endif
}
#ifdef HAVE_EMBREE4
RTCIntersectArguments ray_source_info::setup_intersection_arguments()
{
RTCIntersectArguments result;
rtcInitIntersectArguments(&result);
if (shadowmask != CHANNEL_MASK_DEFAULT) {
// non-default shadow mask means we have to use the slow path
result.filter = PerRay_FilterFuncN;
result.flags = static_cast<RTCRayQueryFlags>(result.flags |
RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER);
}
result.context = this;
return result;
}
RTCOccludedArguments ray_source_info::setup_occluded_arguments()
{
RTCOccludedArguments result;
rtcInitOccludedArguments(&result);
if (shadowmask != CHANNEL_MASK_DEFAULT) {
// non-default shadow mask means we have to use the slow path
result.filter = PerRay_FilterFuncN;
result.flags = static_cast<RTCRayQueryFlags>(result.flags |
RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER);
}
result.context = this;
return result;
}
#endif

View File

@ -19,7 +19,6 @@ add_executable(lightpreview
set_target_properties(lightpreview PROPERTIES WIN32_EXECUTABLE YES)
find_package(embree 3.0 REQUIRED)
INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS})
# HACK: Windows embree .dll's from https://github.com/embree/embree/releases ship with a tbb12.dll

View File

@ -17,7 +17,6 @@ add_executable(tests
benchmark.cc
test_bsputil.cc)
find_package(embree 3.0 REQUIRED)
INCLUDE_DIRECTORIES(${EMBREE_INCLUDE_DIRS})
# HACK: Windows embree .dll's from https://github.com/embree/embree/releases ship with a tbb12.dll