light: make sky faces not occlude lights

This commit is contained in:
Eric Wasylishen 2016-10-17 18:23:56 -06:00
parent a6468984bf
commit 7f525d2441
5 changed files with 75 additions and 34 deletions

View File

@ -57,9 +57,14 @@ hittype_t DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const dmo
// used for CalcPoints // used for CalcPoints
bool IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out); bool IntersectSingleModel(const vec3_t start, const vec3_t dir, vec_t dist, const dmodel_t *self, vec_t *hitdist_out);
enum class tracetype_t {
NORMAL,
TEST_SKY
};
class raystream_t { class raystream_t {
public: 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, const vec_t *normalcontrib = nullptr) = 0; virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, tracetype_t type, const vec_t *color = nullptr, const vec_t *normalcontrib = nullptr) = 0;
virtual size_t numPushedRays() = 0; virtual size_t numPushedRays() = 0;
virtual void tracePushedRaysOcclusion() = 0; virtual void tracePushedRaysOcclusion() = 0;
virtual void tracePushedRaysIntersection() = 0; virtual void tracePushedRaysIntersection() = 0;

View File

@ -1157,7 +1157,7 @@ void EstimateVisibleBoundsAtPoint(const vec3_t point, vec3_t mins, vec3_t maxs)
vec3_t dir; vec3_t dir;
UniformPointOnSphere(dir, u1, u2); UniformPointOnSphere(dir, u1, u2);
rs->pushRay(0, point, dir, 65536.0f, nullptr); rs->pushRay(0, point, dir, 65536.0f, nullptr, tracetype_t::NORMAL);
} }
} }

View File

@ -1354,7 +1354,7 @@ LightFace_Entity(const bsp2_t *bsp,
continue; continue;
} }
rs->pushRay(i, surfpoint, surfpointToLightDir, surfpointToLightDist, shadowself, color, normalcontrib); rs->pushRay(i, surfpoint, surfpointToLightDir, surfpointToLightDist, shadowself, tracetype_t::NORMAL, color, normalcontrib);
} }
rs->tracePushedRaysOcclusion(); rs->tracePushedRaysOcclusion();
@ -1432,7 +1432,7 @@ LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightmapdict_t *li
continue; continue;
} }
rs->pushRay(i, surfpoint, incoming, MAX_SKY_DIST, shadowself); rs->pushRay(i, surfpoint, incoming, MAX_SKY_DIST, shadowself, tracetype_t::TEST_SKY);
} }
rs->tracePushedRaysIntersection(); rs->tracePushedRaysIntersection();
@ -1540,7 +1540,7 @@ LightFace_Min(const bsp2_t *bsp, const bsp2_dface_t *face,
vec3_t surfpointToLightDir; vec3_t surfpointToLightDir;
vec_t surfpointToLightDist = GetDir(surfpoint, *entity.origin.vec3Value(), surfpointToLightDir); vec_t surfpointToLightDist = GetDir(surfpoint, *entity.origin.vec3Value(), surfpointToLightDir);
rs->pushRay(i, surfpoint, surfpointToLightDir, surfpointToLightDist, shadowself); rs->pushRay(i, surfpoint, surfpointToLightDir, surfpointToLightDist, shadowself, tracetype_t::NORMAL);
} }
} }
@ -1760,7 +1760,7 @@ LightFace_Bounce(const bsp2_t *bsp, const bsp2_dface_t *face, const lightsurf_t
if (LightSample_Brightness(indirect) < 0.25) if (LightSample_Brightness(indirect) < 0.25)
continue; continue;
rs->pushRay(i, vpl.pos, dir, dist, /*shadowself*/ nullptr, indirect); rs->pushRay(i, vpl.pos, dir, dist, /*shadowself*/ nullptr, tracetype_t::NORMAL, indirect);
} }
total_bounce_rays += rs->numPushedRays(); total_bounce_rays += rs->numPushedRays();
@ -1968,7 +1968,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons
vec3_t dir; vec3_t dir;
TransformToTangentSpace(normal, myUp, myRt, dirtvec, dir); TransformToTangentSpace(normal, myUp, myRt, dirtvec, dir);
rs->pushRay(j, point, dir, cfg.dirtDepth.floatValue(), selfshadow); rs->pushRay(j, point, dir, cfg.dirtDepth.floatValue(), selfshadow, tracetype_t::NORMAL);
} }
Q_assert(rs->numPushedRays() == numDirtVectors); Q_assert(rs->numPushedRays() == numDirtVectors);
@ -2035,7 +2035,7 @@ LightFace_CalculateDirt(lightsurf_t *lightsurf)
vec3_t dir; vec3_t dir;
TransformToTangentSpace(lightsurf->normals[i], myUps[i], myRts[i], dirtvec, dir); TransformToTangentSpace(lightsurf->normals[i], myUps[i], myRts[i], dirtvec, dir);
rs->pushRay(i, lightsurf->points[i], dir, cfg.dirtDepth.floatValue(), selfshadow); rs->pushRay(i, lightsurf->points[i], dir, cfg.dirtDepth.floatValue(), selfshadow, tracetype_t::NORMAL);
} }
Q_assert(rs->numPushedRays() == lightsurf->numpoints); Q_assert(rs->numPushedRays() == lightsurf->numpoints);

View File

@ -875,7 +875,8 @@ public:
raystream_bsp_t() {} raystream_bsp_t() {}
virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, const vec_t *color = nullptr, const vec_t *normalcontrib = nullptr) { virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, tracetype_t type, const vec_t *color = nullptr, const vec_t *normalcontrib = nullptr) {
// FIXME: `type` not implemeted (sky test)
bsp_ray_t r { i, origin, dir, dist, selfshadow, color, normalcontrib }; bsp_ray_t r { i, origin, dir, dist, selfshadow, color, normalcontrib };
_rays.push_back(r); _rays.push_back(r);
Q_assert(_rays.size() <= _maxrays); Q_assert(_rays.size() <= _maxrays);

View File

@ -151,7 +151,7 @@ CreateGeometryFromWindings(RTCScene scene, const std::vector<winding_t *> &windi
// Creates a scene with just the faces in this model, // Creates a scene with just the faces in this model,
// used by CalcPoints. // used by CalcPoints.
// Liquids are left out but sky faces are included // Liquids are left out, as are sky faces
RTCScene CreatePerModelScene(RTCDevice device, const bsp2_t *bsp, const dmodel_t *model) { RTCScene CreatePerModelScene(RTCDevice device, const bsp2_t *bsp, const dmodel_t *model) {
std::vector<const bsp2_dface_t *> faces; std::vector<const bsp2_dface_t *> faces;
@ -159,9 +159,9 @@ RTCScene CreatePerModelScene(RTCDevice device, const bsp2_t *bsp, const dmodel_t
const bsp2_dface_t *face = &bsp->dfaces[model->firstface + i]; const bsp2_dface_t *face = &bsp->dfaces[model->firstface + i];
const char *texname = Face_TextureName(bsp, face); const char *texname = Face_TextureName(bsp, face);
if (texname[0] == '*') { const int contents = TextureName_Contents(texname);
// ignore liquids
} else { if (contents == CONTENTS_SOLID) {
faces.push_back(face); faces.push_back(face);
} }
} }
@ -231,6 +231,16 @@ enum class filtertype_t {
INTERSECTION, OCCLUSION INTERSECTION, OCCLUSION
}; };
/**
* Set this bit if the ray is coming from a selfshadow model
*/
static const unsigned RAYMASK_FROM_SELFSHADOWGEOM = 1;
/**
* Set this bit if the ray should hit sky faces. This only happens when we
* are testing sunlight; normal lights pass through sky faces
*/
static const unsigned RAYMASK_TEST_SKY_FACES = 2;
// called to evaluate transparency // called to evaluate transparency
template<filtertype_t filtertype> template<filtertype_t filtertype>
static void static void
@ -254,27 +264,37 @@ Embree_FilterFuncN(int* valid,
const unsigned &geomID = RTCHitN_geomID(potentialHit, N, i); const unsigned &geomID = RTCHitN_geomID(potentialHit, N, i);
const unsigned &primID = RTCHitN_primID(potentialHit, N, i); const unsigned &primID = RTCHitN_primID(potentialHit, N, i);
// bail if we hit a selfshadow face, but the ray is not coming from within that model if (geomID == skygeom.geomID) {
if (mask == 0 && geomID == selfshadowgeom.geomID) { if (!(mask & RAYMASK_TEST_SKY_FACES)) {
// reject hit
valid[i] = INVALID;
continue;
}
// test fence texture
const bsp2_dface_t *face = Embree_LookupFace(geomID, primID);
const char *name = Face_TextureName(bsp_static, face);
if (name[0] == '{') {
vec3_t hitpoint;
Embree_RayEndpoint(ray, potentialHit, N, i, hitpoint);
const int sample = SampleTexture(face, bsp_static, hitpoint);
if (sample == 255) {
// reject hit // reject hit
valid[i] = INVALID; valid[i] = INVALID;
continue; continue;
} }
} else if (geomID == selfshadowgeom.geomID) {
// bail if we hit a selfshadow face, but the ray is not coming from within that model
if (!(mask & RAYMASK_FROM_SELFSHADOWGEOM)) {
// reject hit
valid[i] = INVALID;
continue;
}
} else if (geomID == fencegeom.geomID) {
// test fence texture
const bsp2_dface_t *face = Embree_LookupFace(geomID, primID);
const char *name = Face_TextureName(bsp_static, face);
if (name[0] == '{') {
vec3_t hitpoint;
Embree_RayEndpoint(ray, potentialHit, N, i, hitpoint);
const int sample = SampleTexture(face, bsp_static, hitpoint);
if (sample == 255) {
// reject hit
valid[i] = INVALID;
continue;
}
}
} else {
Q_assert_unreachable();
} }
// accept hit // accept hit
@ -543,6 +563,9 @@ Embree_TraceInit(const bsp2_t *bsp)
selfshadowgeom = CreateGeometry(bsp, scene, selfshadowfaces); selfshadowgeom = CreateGeometry(bsp, scene, selfshadowfaces);
CreateGeometryFromWindings(scene, skipwindings); CreateGeometryFromWindings(scene, skipwindings);
rtcSetIntersectionFilterFunctionN(scene, skygeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
rtcSetOcclusionFilterFunctionN(scene, skygeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
rtcSetIntersectionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>); rtcSetIntersectionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
rtcSetOcclusionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>); rtcSetOcclusionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
@ -573,8 +596,14 @@ static RTCRay SetupRay(const vec3_t start, const vec3_t dir, vec_t dist, const d
ray.instID = RTC_INVALID_GEOMETRY_ID; ray.instID = RTC_INVALID_GEOMETRY_ID;
// NOTE: we are not using the ray masking feature of embree, but just using // NOTE: we are not using the ray masking feature of embree, but just using
// this field to store whether the ray is coming from self-shadow geometry // this field to store whether the ray is coming from self-shadow geometry.
ray.mask = (self == nullptr) ? 0 : 1; // and also whether we want to hit sky faces.
unsigned mask = 0;
if (self != nullptr) {
mask |= RAYMASK_FROM_SELFSHADOWGEOM;
}
ray.mask = mask;
ray.time = 0.f; ray.time = 0.f;
return ray; return ray;
} }
@ -612,6 +641,7 @@ qboolean Embree_TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *s
VectorNormalize(dir_normalized); VectorNormalize(dir_normalized);
RTCRay ray = SetupRay(start, dir_normalized, MAX_SKY_RAY_DEPTH, self); RTCRay ray = SetupRay(start, dir_normalized, MAX_SKY_RAY_DEPTH, self);
ray.mask |= RAYMASK_TEST_SKY_FACES;
rtcIntersect(scene, ray); rtcIntersect(scene, ray);
qboolean hit_sky = (ray.geomID == skygeom.geomID); qboolean hit_sky = (ray.geomID == skygeom.geomID);
@ -728,9 +758,14 @@ public:
free(_ray_normalcontribs); free(_ray_normalcontribs);
} }
virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, const vec_t *color = nullptr, const vec_t *normalcontrib = nullptr) { virtual void pushRay(int i, const vec_t *origin, const vec3_t dir, float dist, const dmodel_t *selfshadow, tracetype_t type, const vec_t *color = nullptr, const vec_t *normalcontrib = nullptr) {
Q_assert(_numrays<_maxrays); Q_assert(_numrays<_maxrays);
_rays[_numrays] = SetupRay(origin, dir, dist, selfshadow); _rays[_numrays] = SetupRay(origin, dir, dist, selfshadow);
if (type == tracetype_t::TEST_SKY) {
_rays[_numrays].mask |= RAYMASK_TEST_SKY_FACES;
}
_rays_maxdist[_numrays] = dist; _rays_maxdist[_numrays] = dist;
_point_indices[_numrays] = i; _point_indices[_numrays] = i;
if (color) { if (color) {