cache anything related to triangle-face info in a single struct that we access per ray

This commit is contained in:
Jonathan 2022-06-25 22:22:24 -04:00
parent 8fe525f5b2
commit 033a84cac8
7 changed files with 78 additions and 58 deletions

View File

@ -74,6 +74,7 @@ public:
float anglescale;
int style;
std::string suntexture;
const img::texture *suntexture_value;
};
/* for vanilla this would be 18. some engines allow higher limits though, which will be needed if we're scaling lightmap

View File

@ -25,6 +25,7 @@
#include <common/log.hh>
#include <common/threads.hh>
#include <common/polylib.hh>
#include <common/imglib.hh>
#include <vector>
#include <map>
@ -42,7 +43,7 @@ enum class hittype_t : uint8_t
};
uint32_t clamp_texcoord(vec_t in, uint32_t width);
qvec4b SampleTexture(const mface_t *face, const mbsp_t *bsp, const qvec3d &point); // mxd. Palette index -> RGBA
qvec4b SampleTexture(const mface_t *face, const mtexinfo_t *tex, const img::texture *texture, const mbsp_t *bsp, const qvec3d &point); // mxd. Palette index -> RGBA
class modelinfo_t;

View File

@ -142,13 +142,27 @@ struct ray_source_info : public RTCIntersectContext
}
};
class sceneinfo
struct triinfo
{
const modelinfo_t *modelinfo;
const mface_t *face;
const mtexinfo_t *texinfo;
const img::texture *texture;
float alpha;
bool is_fence, is_glass;
bool shadowworldonly;
bool shadowself;
bool switchableshadow;
int32_t switchshadstyle;
};
struct sceneinfo
{
public:
unsigned geomID;
std::vector<const mface_t *> triToFace;
std::vector<const modelinfo_t *> triToModelinfo;
std::vector<triinfo> triInfo;
};
extern sceneinfo skygeom; // sky. always occludes.
@ -240,17 +254,18 @@ public:
}
}
inline const mface_t *getPushedRayHitFace(size_t j)
inline const triinfo *getPushedRayHitFaceInfo(size_t j)
{
Q_assert(j < _maxrays);
const RTCRayHit &ray = _rays[j];
if (ray.hit.geomID == RTC_INVALID_GEOMETRY_ID)
if (ray.hit.geomID == RTC_INVALID_GEOMETRY_ID) {
return nullptr;
}
const sceneinfo &si = Embree_SceneinfoForGeomID(ray.hit.geomID);
const mface_t *face = si.triToFace.at(ray.hit.primID);
const triinfo *face = &si.triInfo.at(ray.hit.primID);
Q_assert(face != nullptr);
return face;

View File

@ -276,6 +276,7 @@ static void AddSun(const settings::worldspawn_keys &cfg, const qvec3d &sunvec, v
sun.dirt = Dirt_ResolveFlag(cfg, dirtInt);
sun.style = style;
sun.suntexture = suntexture;
sun.suntexture_value = img::find(suntexture);
// fmt::print( "sun is using vector {} {} {} light {} color {} {} {} anglescale {} dirt {} resolved to {}\n",
// sun->sunvec[0], sun->sunvec[1], sun->sunvec[2], sun->sunlight.light,

View File

@ -1620,11 +1620,9 @@ static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict
}
// check if we hit the wrong texture
// TODO: this could be faster!
if (!sun->suntexture.empty()) {
const mface_t *face = rs.getPushedRayHitFace(j);
const char *facetex = Face_TextureName(lightsurf->bsp, face);
if (sun->suntexture != facetex) {
if (sun->suntexture_value) {
const triinfo *face = rs.getPushedRayHitFaceInfo(j);
if (sun->suntexture_value != face->texture) {
continue;
}
}

View File

@ -76,16 +76,12 @@ uint32_t clamp_texcoord(vec_t in, uint32_t width)
}
}
qvec4b SampleTexture(const mface_t *face, const mbsp_t *bsp, const qvec3d &point)
qvec4b SampleTexture(const mface_t *face, const mtexinfo_t *tex, const img::texture *texture, const mbsp_t *bsp, const qvec3d &point)
{
const auto *texture = Face_Texture(bsp, face);
if (texture == nullptr || !texture->meta.width) {
return {};
}
const mtexinfo_t *tex = &bsp->texinfo[face->texinfo];
qvec2d texcoord = WorldToTexCoord(point, tex);
const uint32_t x = clamp_texcoord(texcoord[0], texture->meta.width);

View File

@ -116,8 +116,37 @@ sceneinfo CreateGeometry(
tri->v2 = Face_VertexAtIndex(bsp, face, 0);
tri_index++;
s.triToFace.push_back(face);
s.triToModelinfo.push_back(modelinfo);
triinfo info;
info.face = face;
info.modelinfo = modelinfo;
info.texinfo = &bsp->texinfo[face->texinfo];
info.texture = Face_Texture(bsp, face);
info.shadowworldonly = modelinfo->shadowworldonly.boolValue();
info.shadowself = modelinfo->shadowself.boolValue();
info.switchableshadow = modelinfo->switchableshadow.boolValue();
info.switchshadstyle = modelinfo->switchshadstyle.value();
info.alpha = Face_Alpha(modelinfo, face);
// mxd
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
const int surf_flags = Face_ContentsOrSurfaceFlags(bsp, face);
info.is_fence = ((surf_flags & Q2_SURF_TRANSLUCENT) ==
Q2_SURF_TRANSLUCENT); // KMQuake 2-specific. Use texture alpha chanel when both flags are set.
info.is_glass = !info.is_fence && (surf_flags & Q2_SURF_TRANSLUCENT);
if (info.is_glass) {
info.alpha = (surf_flags & Q2_SURF_TRANS33 ? 0.33f : 0.66f);
}
} else {
const char *name = Face_TextureName(bsp, face);
info.is_fence = (name[0] == '{');
info.is_glass = (info.alpha < 1.0f);
}
s.triInfo.push_back(info);
}
}
@ -202,16 +231,10 @@ void ErrorCallback(void *userptr, const RTCError code, const char *str)
fmt::print("RTC Error {}: {}\n", code, str);
}
const mface_t *Embree_LookupFace(unsigned int geomID, unsigned int primID)
const triinfo &Embree_LookupTriangleInfo(unsigned int geomID, unsigned int primID)
{
const sceneinfo &info = Embree_SceneinfoForGeomID(geomID);
return info.triToFace.at(primID);
}
const modelinfo_t *Embree_LookupModelinfo(unsigned int geomID, unsigned int primID)
{
const sceneinfo &info = Embree_SceneinfoForGeomID(geomID);
return info.triToModelinfo.at(primID);
return info.triInfo.at(primID);
}
inline qvec3f Embree_RayEndpoint(RTCRayN *ray, const qvec3f &dir, size_t N, size_t i)
@ -260,15 +283,16 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
const unsigned rayIndex = rayID;
const modelinfo_t *source_modelinfo = rsi->self;
const modelinfo_t *hit_modelinfo = Embree_LookupModelinfo(geomID, primID);
if (!hit_modelinfo) {
const triinfo &hit_triinfo = Embree_LookupTriangleInfo(geomID, primID);
if (!hit_triinfo.modelinfo) {
// we hit a "skip" face with no associated model
// reject hit (???)
valid[i] = INVALID;
continue;
}
if (hit_modelinfo->shadowworldonly.boolValue()) {
if (hit_triinfo.shadowworldonly) {
// we hit "_shadowworldonly" "1" geometry. Ignore the hit unless we are from world.
if (!source_modelinfo || !source_modelinfo->isWorld()) {
// reject hit
@ -277,20 +301,20 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
}
}
if (hit_modelinfo->shadowself.boolValue()) {
if (hit_triinfo.shadowself) {
// only casts shadows on itself
if (source_modelinfo != hit_modelinfo) {
if (source_modelinfo != hit_triinfo.modelinfo) {
// reject hit
valid[i] = INVALID;
continue;
}
}
if (hit_modelinfo->switchableshadow.boolValue()) {
if (hit_triinfo.switchableshadow) {
// we hit a dynamic shadow caster. reject the hit, but store the
// info about what we hit.
const int style = hit_modelinfo->switchshadstyle.value();
const int style = hit_triinfo.switchshadstyle;
AddDynamicOccluderToRay(context, rayIndex, style);
@ -299,32 +323,16 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
continue;
}
float alpha = hit_triinfo.alpha;
// test fence textures and glass
const mface_t *face = Embree_LookupFace(geomID, primID);
float alpha = Face_Alpha(hit_modelinfo, face);
// mxd
bool isFence, isGlass;
if (bsp_static->loadversion->game->id == GAME_QUAKE_II) {
const int surf_flags = Face_ContentsOrSurfaceFlags(bsp_static, face);
isFence = ((surf_flags & Q2_SURF_TRANSLUCENT) ==
Q2_SURF_TRANSLUCENT); // KMQuake 2-specific. Use texture alpha chanel when both flags are set.
isGlass = !isFence && (surf_flags & Q2_SURF_TRANSLUCENT);
if (isGlass)
alpha = (surf_flags & Q2_SURF_TRANS33 ? 0.33f : 0.66f);
} else {
const char *name = Face_TextureName(bsp_static, face);
isFence = (name[0] == '{');
isGlass = (alpha < 1.0f);
}
if (isFence || isGlass) {
if (hit_triinfo.is_fence || hit_triinfo.is_glass) {
qvec3f rayDir =
qv::normalize(qvec3f{RTCRayN_dir_x(ray, N, i), RTCRayN_dir_y(ray, N, i), RTCRayN_dir_z(ray, N, i)});
qvec3f hitpoint = Embree_RayEndpoint(ray, rayDir, N, i);
const qvec4b sample = SampleTexture(face, bsp_static, hitpoint); // mxd. Palette index -> color_rgba
const qvec4b sample = SampleTexture(hit_triinfo.face, hit_triinfo.texinfo, hit_triinfo.texture, bsp_static, hitpoint); // mxd. Palette index -> color_rgba
if (isGlass) {
if (hit_triinfo.is_glass) {
// hit glass...
// mxd. Adjust alpha by texture alpha?
@ -347,7 +355,7 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
continue;
}
if (isFence) {
if (hit_triinfo.is_fence) {
if (sample[3] < 255) {
// reject hit
valid[i] = INVALID;
@ -620,7 +628,7 @@ hitresult_t TestSky(const qvec3d &start, const qvec3d &dirn, const modelinfo_t *
if (face_out) {
if (hit_sky) {
const sceneinfo &si = Embree_SceneinfoForGeomID(ray.hit.geomID);
*face_out = si.triToFace.at(ray.hit.primID);
*face_out = si.triInfo.at(ray.hit.primID).face;
} else {
*face_out = nullptr;
}