light: experimental support for switchable bmodel shadows:
Current specs/limitations: - only supported for sunlight and regular lights - enabled with "_dynamicshadow" "1" - writes the lightstyle to a "dynshadowstyle" entity key, hardcoded - only handles one dynamic occluder for a given lightmap sample - styled lights passing through a dynamic occluder turn non-styled
This commit is contained in:
parent
7236e47ef4
commit
b71f769c0a
|
|
@ -167,6 +167,7 @@ extern byte thepalette[768];
|
|||
/* tracelist is a std::vector of pointers to modelinfo_t to use for LOS tests */
|
||||
extern std::vector<const modelinfo_t *> tracelist;
|
||||
extern std::vector<const modelinfo_t *> selfshadowlist;
|
||||
extern std::vector<const modelinfo_t *> dynamicshadowlist;
|
||||
|
||||
extern int numDirtVectors;
|
||||
|
||||
|
|
@ -196,7 +197,7 @@ public:
|
|||
vec3_t offset;
|
||||
|
||||
public:
|
||||
lockable_vec_t minlight, shadow, shadowself, dirt, phong, phong_angle, alpha;
|
||||
lockable_vec_t minlight, shadow, shadowself, dynamicshadow, dynshadowstyle, dirt, phong, phong_angle, alpha;
|
||||
lockable_string_t minlight_exclude;
|
||||
lockable_vec3_t minlight_color;
|
||||
lockable_bool_t lightignore;
|
||||
|
|
@ -219,6 +220,8 @@ public:
|
|||
minlight { "minlight", 0 },
|
||||
shadow { "shadow", 0 },
|
||||
shadowself { "shadowself", 0 },
|
||||
dynamicshadow { "dynamicshadow", 0 },
|
||||
dynshadowstyle { "dynshadowstyle", 0},
|
||||
dirt { "dirt", 0 },
|
||||
phong { "phong", 0 },
|
||||
phong_angle { "phong_angle", 0 },
|
||||
|
|
@ -232,7 +235,7 @@ public:
|
|||
|
||||
settingsdict_t settings() {
|
||||
return {{
|
||||
&minlight, &shadow, &shadowself, &dirt, &phong, &phong_angle, &alpha,
|
||||
&minlight, &shadow, &shadowself, &dynamicshadow, &dynshadowstyle, &dirt, &phong, &phong_angle, &alpha,
|
||||
&minlight_exclude, &minlight_color, &lightignore
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
virtual int getPushedRayPointIndex(size_t j) = 0;
|
||||
virtual void getPushedRayColor(size_t j, vec3_t out) = 0;
|
||||
virtual void getPushedRayNormalContrib(size_t j, vec3_t out) = 0;
|
||||
virtual int getPushedRayDynamicStyle(size_t j) = 0;
|
||||
virtual void clearPushedRays() = 0;
|
||||
virtual ~raystream_t() {};
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ const char * light_t::classname() const {
|
|||
* ============================================================================
|
||||
*/
|
||||
|
||||
static std::map<std::string, int> lightstyleForTargetname;
|
||||
static std::vector<std::pair<std::string, int>> lightstyleForTargetname;
|
||||
|
||||
static bool IsSwitchableLightstyle(int style) {
|
||||
return style >= LIGHT_TARGETS_START
|
||||
|
|
@ -85,16 +85,17 @@ std::string WorldValueForKey(const std::string &key)
|
|||
/**
|
||||
* Assigns a lightstyle number for the given non-empty targetname string
|
||||
* Reuses the existing lightstyle if this targetname was already assigned.
|
||||
*
|
||||
* Pass an empty string to generate a new unique lightstyle.
|
||||
*/
|
||||
static int
|
||||
LightStyleForTargetname(const std::string &targetname)
|
||||
{
|
||||
Q_assert(targetname.size() > 0);
|
||||
|
||||
// check if already assigned
|
||||
auto it = lightstyleForTargetname.find(targetname);
|
||||
if (it != lightstyleForTargetname.end()) {
|
||||
return it->second;
|
||||
for (const auto &pr : lightstyleForTargetname) {
|
||||
if (pr.first == targetname && targetname.size() > 0) {
|
||||
return pr.second;
|
||||
}
|
||||
}
|
||||
|
||||
// check if full
|
||||
|
|
@ -104,7 +105,7 @@ LightStyleForTargetname(const std::string &targetname)
|
|||
|
||||
// generate a new style number and return it
|
||||
const int newStylenum = LIGHT_TARGETS_START + lightstyleForTargetname.size();
|
||||
lightstyleForTargetname[targetname] = newStylenum;
|
||||
lightstyleForTargetname.push_back(std::make_pair(targetname, newStylenum));
|
||||
|
||||
if (verbose_log) {
|
||||
logprint("%s: Allocated lightstyle %d for targetname '%s'\n", __func__, newStylenum, targetname.c_str());
|
||||
|
|
@ -1008,6 +1009,15 @@ LoadEntities(const globalconfig_t &cfg, const bsp2_t *bsp)
|
|||
}
|
||||
}
|
||||
|
||||
// setup light styles for dynamic shadow entities
|
||||
if (EntDict_StringForKey(entdict, "_dynamicshadow") == "1") {
|
||||
std::string targetname = EntDict_StringForKey(entdict, "targetname");
|
||||
// if targetname is "", generates a new unique lightstyle
|
||||
const int style = LightStyleForTargetname(targetname);
|
||||
// TODO: Configurable key?
|
||||
entdict["dynshadowstyle"] = std::to_string(style);
|
||||
}
|
||||
|
||||
// parse escape sequences
|
||||
for (auto &epair : entdict) {
|
||||
epair.second = ParseEscapeSequences(epair.second);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static byte *lux_file_end; // end of space for luxfile data
|
|||
std::vector<modelinfo_t *> modelinfo;
|
||||
std::vector<const modelinfo_t *> tracelist;
|
||||
std::vector<const modelinfo_t *> selfshadowlist;
|
||||
std::vector<const modelinfo_t *> dynamicshadowlist;
|
||||
|
||||
int oversample = 1;
|
||||
int write_litfile = 0; /* 0 for none, 1 for .lit, 2 for bspx, 3 for both */
|
||||
|
|
@ -274,6 +275,7 @@ FindModelInfo(const bsp2_t *bsp, const char *lmscaleoverride)
|
|||
Q_assert(modelinfo.size() == 0);
|
||||
Q_assert(tracelist.size() == 0);
|
||||
Q_assert(selfshadowlist.size() == 0);
|
||||
Q_assert(dynamicshadowlist.size() == 0);
|
||||
|
||||
if (!bsp->nummodels) {
|
||||
Error("Corrupt .BSP: bsp->nummodels is 0!");
|
||||
|
|
@ -324,7 +326,12 @@ FindModelInfo(const bsp2_t *bsp, const char *lmscaleoverride)
|
|||
info->settings().setSettings(*entdict, false);
|
||||
|
||||
/* Check if this model will cast shadows (shadow => shadowself) */
|
||||
if (info->shadow.boolValue()) {
|
||||
if (info->dynamicshadow.boolValue()) {
|
||||
Q_assert(info->dynshadowstyle.intValue() != 0);
|
||||
logprint("Found a bmodel using dynamic shadow lightstyle: %d\n", info->dynshadowstyle.intValue());
|
||||
|
||||
dynamicshadowlist.push_back(info);
|
||||
} else if (info->shadow.boolValue()) {
|
||||
tracelist.push_back(info);
|
||||
} else if (info->shadowself.boolValue()){
|
||||
selfshadowlist.push_back(info);
|
||||
|
|
|
|||
|
|
@ -1328,8 +1328,6 @@ LightFace_Entity(const bsp2_t *bsp,
|
|||
/*
|
||||
* Check it for real
|
||||
*/
|
||||
bool hit = false;
|
||||
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, entity->style.intValue(), lightsurf);
|
||||
const dmodel_t *shadowself = modelinfo->shadowself.boolValue() ? modelinfo->model : NULL;
|
||||
|
||||
raystream_t *rs = lightsurf->stream;
|
||||
|
|
@ -1362,6 +1360,8 @@ LightFace_Entity(const bsp2_t *bsp,
|
|||
rs->tracePushedRaysOcclusion();
|
||||
total_light_rays += rs->numPushedRays();
|
||||
|
||||
lightmap_t *lightmap_world = Lightmap_ForStyle(lightmaps, entity->style.intValue(), lightsurf);
|
||||
|
||||
const int N = rs->numPushedRays();
|
||||
for (int j = 0; j < N; j++) {
|
||||
if (rs->getPushedRayOccluded(j)) {
|
||||
|
|
@ -1371,6 +1371,19 @@ LightFace_Entity(const bsp2_t *bsp,
|
|||
total_light_ray_hits++;
|
||||
|
||||
int i = rs->getPushedRayPointIndex(j);
|
||||
|
||||
// check if we hit a dynamic shadow caster
|
||||
lightmap_t *lightmap;
|
||||
int style;
|
||||
if (rs->getPushedRayDynamicStyle(j) != 0) {
|
||||
style = rs->getPushedRayDynamicStyle(j);
|
||||
lightmap = Lightmap_ForStyle(lightmaps, style, lightsurf);
|
||||
} else {
|
||||
// regular case
|
||||
style = entity->style.intValue();
|
||||
lightmap = lightmap_world;
|
||||
}
|
||||
|
||||
lightsample_t *sample = &lightmap->samples[i];
|
||||
|
||||
vec3_t color, normalcontrib;
|
||||
|
|
@ -1380,11 +1393,8 @@ LightFace_Entity(const bsp2_t *bsp,
|
|||
VectorAdd(sample->color, color, sample->color);
|
||||
VectorAdd(sample->direction, normalcontrib, sample->direction);
|
||||
|
||||
hit = true;
|
||||
Lightmap_Save(lightmaps, lightsurf, lightmap, style);
|
||||
}
|
||||
|
||||
if (hit)
|
||||
Lightmap_Save(lightmaps, lightsurf, lightmap, entity->style.intValue());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1405,15 +1415,11 @@ LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightmapdict_t *li
|
|||
return;
|
||||
}
|
||||
|
||||
/* if sunlight is set, use a style 0 light map */
|
||||
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf);
|
||||
|
||||
vec3_t incoming;
|
||||
VectorCopy(sun->sunvec, incoming);
|
||||
VectorNormalize(incoming);
|
||||
|
||||
/* Check each point... */
|
||||
bool hit = false;
|
||||
const dmodel_t *shadowself = modelinfo->shadowself.boolValue() ? modelinfo->model : NULL;
|
||||
|
||||
raystream_t *rs = lightsurf->stream;
|
||||
|
|
@ -1457,6 +1463,9 @@ LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightmapdict_t *li
|
|||
|
||||
rs->tracePushedRaysIntersection();
|
||||
|
||||
/* if sunlight is set, use a style 0 light map */
|
||||
lightmap_t *lightmap_world = Lightmap_ForStyle(lightmaps, 0, lightsurf);
|
||||
|
||||
const int N = rs->numPushedRays();
|
||||
for (int j = 0; j < N; j++) {
|
||||
if (rs->getPushedRayHitType(j) != hittype_t::SKY) {
|
||||
|
|
@ -1464,6 +1473,17 @@ LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightmapdict_t *li
|
|||
}
|
||||
|
||||
const int i = rs->getPushedRayPointIndex(j);
|
||||
|
||||
// check if we hit a dynamic shadow caster
|
||||
lightmap_t *lightmap;
|
||||
const int style = rs->getPushedRayDynamicStyle(j);
|
||||
if (style != 0) {
|
||||
lightmap = Lightmap_ForStyle(lightmaps, style, lightsurf);
|
||||
} else {
|
||||
// regular case
|
||||
lightmap = lightmap_world;
|
||||
}
|
||||
|
||||
lightsample_t *sample = &lightmap->samples[i];
|
||||
|
||||
vec3_t color, normalcontrib;
|
||||
|
|
@ -1473,11 +1493,8 @@ LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightmapdict_t *li
|
|||
VectorAdd(sample->color, color, sample->color);
|
||||
VectorAdd(sample->direction, normalcontrib, sample->direction);
|
||||
|
||||
hit = true;
|
||||
Lightmap_Save(lightmaps, lightsurf, lightmap, style);
|
||||
}
|
||||
|
||||
if (hit)
|
||||
Lightmap_Save(lightmaps, lightsurf, lightmap, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -888,6 +888,10 @@ public:
|
|||
VectorCopy(_rays.at(j)._normalcontrib, out);
|
||||
}
|
||||
|
||||
virtual int getPushedRayDynamicStyle(size_t j) {
|
||||
return 0; // not supported
|
||||
}
|
||||
|
||||
virtual void clearPushedRays() {
|
||||
_rays.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ CreateGeometryFromWindings(RTCScene scene, const std::vector<winding_t *> &windi
|
|||
RTCDevice device;
|
||||
RTCScene scene;
|
||||
/* global shadow casters */
|
||||
sceneinfo skygeom, solidgeom, fencegeom, selfshadowgeom;
|
||||
sceneinfo skygeom, solidgeom, fencegeom, selfshadowgeom, dynamicshadowgeom;
|
||||
|
||||
static const bsp2_t *bsp_static;
|
||||
|
||||
|
|
@ -179,6 +179,8 @@ Embree_SceneinfoForGeomID(unsigned int geomID)
|
|||
return fencegeom;
|
||||
} else if (geomID == selfshadowgeom.geomID) {
|
||||
return selfshadowgeom;
|
||||
} else if (geomID == dynamicshadowgeom.geomID) {
|
||||
return dynamicshadowgeom;
|
||||
} else {
|
||||
Error("unexpected geomID");
|
||||
}
|
||||
|
|
@ -223,6 +225,8 @@ enum class filtertype_t {
|
|||
|
||||
void AddGlassToRay(const RTCIntersectContext* context, unsigned rayIndex, float opacity, const vec3_t glasscolor);
|
||||
|
||||
void AddDynamicOccluderToRay(const RTCIntersectContext* context, unsigned rayIndex, int style);
|
||||
|
||||
// called to evaluate transparency
|
||||
template<filtertype_t filtertype>
|
||||
static void
|
||||
|
|
@ -257,6 +261,17 @@ Embree_FilterFuncN(int* valid,
|
|||
valid[i] = INVALID;
|
||||
continue;
|
||||
}
|
||||
} else if (geomID == dynamicshadowgeom.geomID) {
|
||||
// we hit a dynamic shadow caster. reject the hit, but store the
|
||||
// info about what we hit.
|
||||
const modelinfo_t *modelinfo = Embree_LookupModelinfo(geomID, primID);
|
||||
int style = modelinfo->dynshadowstyle.intValue();
|
||||
|
||||
AddDynamicOccluderToRay(context, rayIndex, style);
|
||||
|
||||
// reject hit
|
||||
valid[i] = INVALID;
|
||||
continue;
|
||||
} else {
|
||||
// test fence textures and glass
|
||||
const bsp2_dface_t *face = Embree_LookupFace(geomID, primID);
|
||||
|
|
@ -511,7 +526,7 @@ Embree_TraceInit(const bsp2_t *bsp)
|
|||
bsp_static = bsp;
|
||||
Q_assert(device == nullptr);
|
||||
|
||||
std::vector<const bsp2_dface_t *> skyfaces, solidfaces, fencefaces, selfshadowfaces;
|
||||
std::vector<const bsp2_dface_t *> skyfaces, solidfaces, fencefaces, selfshadowfaces, dynamicshadowfaces;
|
||||
|
||||
/* Check against the list of global shadow casters */
|
||||
for (const modelinfo_t *model : tracelist) {
|
||||
|
|
@ -553,6 +568,14 @@ Embree_TraceInit(const bsp2_t *bsp)
|
|||
}
|
||||
}
|
||||
|
||||
/* Dynamic-shadow models */
|
||||
for (const modelinfo_t *model : dynamicshadowlist) {
|
||||
for (int i=0; i<model->model->numfaces; i++) {
|
||||
const bsp2_dface_t *face = BSP_GetFace(bsp, model->model->firstface + i);
|
||||
dynamicshadowfaces.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
/* Special handling of skip-textured bmodels */
|
||||
std::vector<winding_t *> skipwindings;
|
||||
for (const modelinfo_t *model : tracelist) {
|
||||
|
|
@ -584,6 +607,7 @@ Embree_TraceInit(const bsp2_t *bsp)
|
|||
solidgeom = CreateGeometry(bsp, scene, solidfaces);
|
||||
fencegeom = CreateGeometry(bsp, scene, fencefaces);
|
||||
selfshadowgeom = CreateGeometry(bsp, scene, selfshadowfaces);
|
||||
dynamicshadowgeom = CreateGeometry(bsp, scene, dynamicshadowfaces);
|
||||
CreateGeometryFromWindings(scene, skipwindings);
|
||||
|
||||
rtcSetIntersectionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
||||
|
|
@ -592,13 +616,17 @@ Embree_TraceInit(const bsp2_t *bsp)
|
|||
rtcSetIntersectionFilterFunctionN(scene, selfshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
||||
rtcSetOcclusionFilterFunctionN(scene, selfshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
||||
|
||||
rtcSetIntersectionFilterFunctionN(scene, dynamicshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
||||
rtcSetOcclusionFilterFunctionN(scene, dynamicshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
||||
|
||||
rtcCommit (scene);
|
||||
|
||||
logprint("Embree_TraceInit: %d skyfaces %d solidfaces %d fencefaces %d selfshadowfaces %d skipwindings\n",
|
||||
logprint("Embree_TraceInit: %d skyfaces %d solidfaces %d fencefaces %d selfshadowfaces %d dynamicshadowfaces %d skipwindings\n",
|
||||
(int)skyfaces.size(),
|
||||
(int)solidfaces.size(),
|
||||
(int)fencefaces.size(),
|
||||
(int)selfshadowfaces.size(),
|
||||
(int)dynamicshadowfaces.size(),
|
||||
(int)skipwindings.size());
|
||||
|
||||
FreeWindings(skipwindings);
|
||||
|
|
@ -732,6 +760,13 @@ public:
|
|||
int *_point_indices;
|
||||
vec3_t *_ray_colors;
|
||||
vec3_t *_ray_normalcontribs;
|
||||
|
||||
// This is set to the modelinfo's dynshadowstyle if the ray hit
|
||||
// a dynamic shadow caster. (note that for rays that hit dynamic
|
||||
// shadow casters, all of the other hit data is assuming the ray went
|
||||
// straight through).
|
||||
int *_ray_dynamic_styles;
|
||||
|
||||
int _numrays;
|
||||
int _maxrays;
|
||||
// streamstate_t _state;
|
||||
|
|
@ -743,6 +778,7 @@ public:
|
|||
_point_indices { new int[maxRays] },
|
||||
_ray_colors { static_cast<vec3_t *>(calloc(maxRays, sizeof(vec3_t))) },
|
||||
_ray_normalcontribs { static_cast<vec3_t *>(calloc(maxRays, sizeof(vec3_t))) },
|
||||
_ray_dynamic_styles { new int[maxRays] },
|
||||
_numrays { 0 },
|
||||
_maxrays { maxRays } {}
|
||||
//,
|
||||
|
|
@ -754,6 +790,7 @@ public:
|
|||
delete[] _point_indices;
|
||||
free(_ray_colors);
|
||||
free(_ray_normalcontribs);
|
||||
delete[] _ray_dynamic_styles;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -767,6 +804,7 @@ public:
|
|||
if (normalcontrib) {
|
||||
VectorCopy(normalcontrib, _ray_normalcontribs[_numrays]);
|
||||
}
|
||||
_ray_dynamic_styles[_numrays] = 0;
|
||||
_numrays++;
|
||||
}
|
||||
|
||||
|
|
@ -865,6 +903,11 @@ public:
|
|||
VectorCopy(_ray_normalcontribs[j], out);
|
||||
}
|
||||
|
||||
virtual int getPushedRayDynamicStyle(size_t j) {
|
||||
Q_assert(j < _maxrays);
|
||||
return _ray_dynamic_styles[j];
|
||||
}
|
||||
|
||||
virtual void clearPushedRays() {
|
||||
_numrays = 0;
|
||||
//_state = streamstate_t::READY;
|
||||
|
|
@ -911,3 +954,9 @@ void AddGlassToRay(const RTCIntersectContext* context, unsigned rayIndex, float
|
|||
// use the lerped color
|
||||
VectorCopy(lerped, rs->_ray_colors[rayIndex]);
|
||||
}
|
||||
|
||||
void AddDynamicOccluderToRay(const RTCIntersectContext* context, unsigned rayIndex, int style)
|
||||
{
|
||||
raystream_embree_t *rs = static_cast<raystream_embree_t *>(context->userRayExt);
|
||||
rs->_ray_dynamic_styles[rayIndex] = style;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue