diff --git a/include/light/light.hh b/include/light/light.hh index 95af71a5..c76c7eb5 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -54,6 +54,9 @@ qboolean TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self); qboolean TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self); hittype_t DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const dmodel_t *self, vec_t *hitdist_out, plane_t *hitplane_out, const bsp2_dface_t **face_out); +// used for CalcPoints +bool IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out); + class raystream_t { public: virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, const vec_t *color = nullptr) = 0; @@ -77,6 +80,7 @@ void Embree_TraceInit(const bsp2_t *bsp); qboolean Embree_TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self); qboolean Embree_TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self); hittype_t Embree_DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const dmodel_t *self, vec_t *hitdist_out, plane_t *hitplane_out, const bsp2_dface_t **face_out); +bool Embree_IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out); raystream_t *Embree_MakeRayStream(int maxrays); diff --git a/light/ltface.cc b/light/ltface.cc index 5aeca1ca..ab9bbcac 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -591,10 +591,6 @@ CheckObstructed(const lightsurf_t *surf, const vec3_t offset, const vec_t us, co TexCoordToWorld(us + (x/10.0), ut + (y/10.0), &surf->texorg, testpoint); VectorAdd(testpoint, offset, testpoint); - plane_t hitplane = {0}; - - const dmodel_t *selfshadow = (surf->modelinfo->shadowself.boolValue()) ? surf->modelinfo->model : NULL; - vec3_t dirn; VectorSubtract(testpoint, surf->midpoint, dirn); vec_t dist = VectorNormalize(dirn); @@ -604,7 +600,7 @@ CheckObstructed(const lightsurf_t *surf, const vec3_t offset, const vec_t us, co // trace from surf->midpoint to testpoint vec_t hitdist = 0; - if (hittype_t::SOLID == DirtTrace(surf->midpoint, dirn, dist, selfshadow, &hitdist, &hitplane, NULL)) { + if (IntersectSingleModel(surf->midpoint, dirn, dist, surf->modelinfo->model, &hitdist)) { // make a corrected point VectorMA(surf->midpoint, qmax(0.0f, hitdist - 0.25f), dirn, corrected); return true; diff --git a/light/trace.cc b/light/trace.cc index 9c5379ec..b0cae030 100644 --- a/light/trace.cc +++ b/light/trace.cc @@ -694,6 +694,24 @@ BSP_DirtTrace(const vec3_t start, const vec3_t dirn, const vec_t dist, const dmo return hittype_t::NONE; } +bool BSP_IntersectSingleModel(const vec3_t start, const vec3_t dirn, vec_t dist, const dmodel_t *self, vec_t *hitdist_out) +{ + vec3_t stop; + VectorMA(start, dist, dirn, stop); + + traceinfo_t ti = {0}; + VectorCopy(dirn, ti.dir); + + if (TraceFaces (&ti, self->headnode[0], start, stop)) { + if (hitdist_out) { + vec3_t delta; + VectorSubtract(ti.point, start, delta); + *hitdist_out = VectorLength(delta); + } + return true; + } + return false; +} /* ============= @@ -822,6 +840,19 @@ hittype_t DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const dmo Error("no backend available"); } +bool IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out) +{ +#ifdef HAVE_EMBREE + if (rtbackend == backend_embree) { + return Embree_IntersectSingleModel(start, dir, dist, self, hitdist_out); + } +#endif + if (rtbackend == backend_bsp) { + return BSP_IntersectSingleModel(start, dir, dist, self, hitdist_out); + } + Error("no backend available"); +} + class bsp_ray_t { public: int _pointindex; diff --git a/light/trace_embree.cc b/light/trace_embree.cc index cbfe04de..5a34772f 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -29,6 +29,8 @@ #include #endif +using namespace std; + static constexpr float MAX_SKY_RAY_DEPTH = 8192.0f; /** @@ -101,6 +103,29 @@ CreateGeometry(const bsp2_t *bsp, RTCScene scene, const std::vector faces; + + for (int i=0; inumfaces; i++) { + const bsp2_dface_t *face = &bsp->dfaces[model->firstface + i]; + + const char *texname = Face_TextureName(bsp, face); + if (texname[0] == '*') { + // ignore liquids + } else { + faces.push_back(face); + } + } + + RTCScene scene = rtcDeviceNewScene(device, RTC_SCENE_STATIC | RTC_SCENE_COHERENT, RTC_INTERSECT1); + sceneinfo geom = CreateGeometry(bsp, scene, faces); + rtcCommit(scene); + return scene; +} + RTCDevice device; RTCScene scene; /* global shadow casters */ @@ -225,6 +250,8 @@ Embree_FilterFuncN(int* valid, } } +vector perModelScenes; + void Embree_TraceInit(const bsp2_t *bsp) { @@ -267,6 +294,12 @@ Embree_TraceInit(const bsp2_t *bsp) Error("embree must be built with ray masks disabled"); } + // set up per-model scenes, used for CalcPoints + for (int i=0; inummodels; i++) { + perModelScenes.push_back(CreatePerModelScene(device, bsp, &bsp->dmodels[i])); + } + assert(perModelScenes.size() == bsp->nummodels); + scene = rtcDeviceNewScene(device, RTC_SCENE_STATIC | RTC_SCENE_COHERENT, RTC_INTERSECT1 | RTC_INTERSECT_STREAM); skygeom = CreateGeometry(bsp, scene, skyfaces); solidgeom = CreateGeometry(bsp, scene, solidfaces); @@ -380,6 +413,24 @@ hittype_t Embree_DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, co } } +// used for CalcPoints +bool Embree_IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out) +{ + const int modelnum = self - bsp_static->dmodels; + RTCScene singleModelScene = perModelScenes.at(modelnum); + + RTCRay ray = SetupRay(start, dir, dist, nullptr); + rtcIntersect(singleModelScene, ray); + + if (ray.geomID == RTC_INVALID_GEOMETRY_ID) + return false; // no obstruction + + if (hitdist_out) { + *hitdist_out = ray.tfar; + } + return true; +} + //enum class streamstate_t { // READY, DID_OCCLUDE, DID_INTERSECT //};