This commit is contained in:
Major Cooke 2022-05-21 12:54:43 -05:00
parent c630fd9b25
commit b6f0bc0da3
27 changed files with 226 additions and 5 deletions

View file

@ -1629,3 +1629,8 @@ FSerializer& Serialize(FSerializer& arc, const char* key, FRenderStyle& style, F
}
SaveRecords saveRecords;
FSerializer &Serialize(FSerializer &arc, const char *key, FVector4 &value, FVector4 *defval)
{
return arc.Array<float>(key, &value[0], defval ? &(*defval)[0] : nullptr, 4, true);
}

View file

@ -234,6 +234,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def);
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def);
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
FSerializer &Serialize(FSerializer &arc, const char *key, FVector4 &value, FVector4 *defval);
template <typename T/*, typename = std::enable_if_t<std::is_base_of_v<DObject, T>>*/>
FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **)

View file

@ -17,7 +17,7 @@ public:
virtual VSMatrix GetViewToWorldMatrix() = 0;
virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0;
virtual void BeginDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0;
virtual void EndDrawHUDModel(FRenderStyle style) = 0;
virtual void SetInterpolation(double interpolation) = 0;

View file

@ -140,6 +140,7 @@ bool FGLRenderState::ApplyShader()
activeShader->muTextureModulateColor.Set(mStreamData.uTextureModulateColor);
activeShader->muTextureBlendColor.Set(mStreamData.uTextureBlendColor);
activeShader->muDetailParms.Set(&mStreamData.uDetailParms.X);
activeShader->muDirectionalLight.Set(&mStreamData.uDirectionalLight.X);
#ifdef NPOT_EMULATION
activeShader->muNpotEmulation.Set(&mStreamData.uNpotEmulation.X);
#endif

View file

@ -284,6 +284,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
uniform mat4 NormalModelMatrix;
uniform mat4 TextureMatrix;
// directional light
uniform vec4 uDirectionalLight;
// light buffers
#ifdef SHADER_STORAGE_LIGHTS
layout(std430, binding = 1) buffer LightBufferSSO
@ -600,6 +603,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
muTextureModulateColor.Init(hShader, "uTextureModulateColor");
muTextureBlendColor.Init(hShader, "uTextureBlendColor");
muTimer.Init(hShader, "timer");
muDirectionalLight.Init(hShader, "uDirectionalLight");
lights_index = glGetUniformLocation(hShader, "lights");
modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix");

View file

@ -266,6 +266,7 @@ class FShader
FBufferedUniform2f muNpotEmulation;
#endif
FUniform4f muDirectionalLight;
int lights_index;
int modelmatrix_index;
int normalmodelmatrix_index;

View file

@ -202,6 +202,8 @@ struct StreamData
FVector4 uDetailParms;
FVector4 uNpotEmulation;
FVector4 padding1, padding2, padding3;
FVector4 uDirectionalLight;
};
class FRenderState
@ -305,6 +307,7 @@ public:
#ifdef NPOT_EMULATION
mStreamData.uNpotEmulation = { 0,0,0,0 };
#endif
mStreamData.uDirectionalLight = { 0.0f, 0.0f, 0.0f, 0.0f };
mModelMatrix.loadIdentity();
mTextureMatrix.loadIdentity();
ClearClipSplit();
@ -488,6 +491,11 @@ public:
mStreamData.uDynLightColor.Z = b;
}
void SetDirectionalLight(FVector4 dl)
{
mStreamData.uDirectionalLight = { dl.X, dl.Y, dl.Z, dl.W };
}
void SetScreenFade(float f)
{
// This component is otherwise unused.

View file

@ -208,6 +208,8 @@ static const char *shaderBindings = R"(
vec4 uDetailParms;
vec4 uNpotEmulation;
vec4 padding1, padding2, padding3;
vec4 uDirectionalLight;
};
layout(set = 0, binding = 3, std140) uniform StreamUBO {
@ -299,6 +301,7 @@ static const char *shaderBindings = R"(
#define uSplitBottomPlane data[uDataIndex].uSplitBottomPlane
#define uDetailParms data[uDataIndex].uDetailParms
#define uNpotEmulation data[uDataIndex].uNpotEmulation
#define uDirectionalLight data[uDataIndex].uDirectionalLight
#define SUPPORTS_SHADOWMAPS
#define VULKAN_COORDINATE_SYSTEM

View file

@ -1757,6 +1757,9 @@ void FLevelLocals::Init()
pixelstretch = info->pixelstretch;
DirectionalLightMode = info->DirectionalLightMode;
DirectionalLight = info->DirectionalLight;
compatflags.Callback();
compatflags2.Callback();

View file

@ -685,6 +685,8 @@ public:
bool lightadditivesurfaces;
bool notexturefill;
int ImpactDecalCount;
int8_t DirectionalLightMode;
FVector4 DirectionalLight;
FDynamicLight *lights;

View file

@ -290,6 +290,8 @@ void level_info_t::Reset()
outsidefogdensity = 0;
skyfog = 0;
pixelstretch = 1.2f;
DirectionalLightMode = 0;
DirectionalLight = FVector4(0, 0, 0, 0);
specialactions.Clear();
DefaultEnvironment = 0;
@ -1436,6 +1438,29 @@ DEFINE_MAP_OPTION(pixelratio, false)
info->pixelstretch = (float)parse.sc.Float;
}
DEFINE_MAP_OPTION(DirectionalLightMode, false)
{
parse.ParseAssign();
parse.sc.MustGetNumber();
info->DirectionalLightMode = (int8_t)clamp(parse.sc.Number, 0, 2);
}
DEFINE_MAP_OPTION(DirectionalLight, true)
{
parse.ParseAssign();
parse.sc.MustGetFloat();
info->DirectionalLight.X = (float)parse.sc.Float;
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
parse.sc.MustGetFloat();
info->DirectionalLight.Y = (float)parse.sc.Float;
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
parse.sc.MustGetFloat();
info->DirectionalLight.Z = (float)parse.sc.Float;
info->DirectionalLight.MakeUnit();
if (parse.format_type == FMapInfoParser::FMT_New) parse.sc.MustGetStringName(",");
parse.sc.MustGetFloat();
info->DirectionalLight.W = (float)parse.sc.Float;
}
DEFINE_MAP_OPTION(brightfog, false)
{

View file

@ -364,6 +364,8 @@ struct level_info_t
int outsidefogdensity;
int skyfog;
float pixelstretch;
int8_t DirectionalLightMode;
FVector4 DirectionalLight;
// Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one.

View file

@ -996,7 +996,8 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
("scrolls", Scrolls)
("automap", automap)
("interpolator", interpolator)
("frozenstate", frozenstate);
("frozenstate", frozenstate)
("directionallight", DirectionalLight);
// Hub transitions must keep the current total time

View file

@ -221,7 +221,7 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float o
float orientation = smf->xscale * smf->yscale * smf->zscale;
renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0);
renderer->BeginDrawHUDModel(playermo->RenderStyle, smf, objectToWorldMatrix, orientation < 0);
uint32_t trans = psp->GetTranslation() != 0 ? psp->GetTranslation() : 0;
if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation;
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), psp->Caller->GetClass(), trans);
@ -783,6 +783,10 @@ static void ParseModelDefLump(int Lump)
smf.rotationCenterY = 0.;
smf.rotationCenterZ = 0.;
}
else if (sc.Compare("nodirectionallight"))
{
smf.flags |= MDL_NODIRECTIONALLIGHT;
}
else
{
sc.ScriptMessage("Unrecognized string \"%s\"", sc.String);

View file

@ -57,6 +57,7 @@ enum
MDL_USEROTATIONCENTER = 512,
MDL_NOPERPIXELLIGHTING = 1024, // forces a model to not use per-pixel lighting. useful for voxel-converted-to-model objects.
MDL_SCALEWEAPONFOV = 2048, // scale weapon view model with higher user FOVs
MDL_NODIRECTIONALLIGHT = 4096, // disables directional light shading
};
FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped);

View file

@ -67,17 +67,23 @@ void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf
state.mModelMatrix = objectToWorldMatrix;
state.EnableModelMatrix(true);
if (level.info->DirectionalLightMode >= 1 && !(smf->flags & MDL_NODIRECTIONALLIGHT))
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
}
void FHWModelRenderer::EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf)
{
state.SetDirectionalLight(FVector4(0.f, 0.f, 0.f, 0.f));
state.EnableModelMatrix(false);
state.SetDepthFunc(DF_Less);
if (!(style == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES))
state.SetCulling(Cull_None);
}
void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored)
void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored)
{
state.SetDepthFunc(DF_LEqual);
@ -91,10 +97,16 @@ void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &obj
state.mModelMatrix = objectToWorldMatrix;
state.EnableModelMatrix(true);
if (level.info->DirectionalLightMode >= 1 && !(smf->flags & MDL_NODIRECTIONALLIGHT))
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
}
void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style)
{
state.SetDirectionalLight(FVector4(0.f, 0.f, 0.f, 0.f));
state.EnableModelMatrix(false);
state.SetDepthFunc(DF_Less);

View file

@ -49,7 +49,7 @@ public:
void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) override;
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
VSMatrix GetViewToWorldMatrix() override;
void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
void BeginDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
void EndDrawHUDModel(FRenderStyle style) override;
void SetInterpolation(double interpolation) override;
void SetMaterial(FGameTexture *skin, bool clampNoFilter, int translation) override;

View file

@ -78,6 +78,13 @@ void HWDecal::DrawDecal(HWDrawInfo *di, FRenderState &state)
state.SetRenderStyle(decal->RenderStyle);
state.SetMaterial(texture, UF_Sprite, 0, CLAMP_XY, decal->Translation, -1);
// only enable directional lighting if the DL mode is enabled for the entire map.
// IMO it doesn't make sense to enable DL on decals if the DL mode is set to "models only".
if (level.info->DirectionalLightMode == 2)
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
// If srcalpha is one it looks better with a higher alpha threshold
if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
@ -131,6 +138,7 @@ void HWDecal::DrawDecal(HWDrawInfo *di, FRenderState &state)
state.SetObjectColor(0xffffffff);
state.SetFog(fc, -1);
state.SetDynLight(0, 0, 0);
state.SetDirectionalLight(FVector4(0.f, 0.f, 0.f, 0.f));
}
//==========================================================================

View file

@ -212,6 +212,7 @@ private:
PalEntry CalcLightColor(int light, PalEntry pe, int blendfactor);
float GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor);
bool CheckFog(sector_t *frontsector, sector_t *backsector);
FVector4 GetDirectionalLight(void);
WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &pos, int cm, area_t in_area, const DVector3 &playerpos);
public:

View file

@ -334,6 +334,10 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
{
if (sector->special != GLSector_Skybox)
{
if (level.info->DirectionalLightMode == 2)
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, 0, -1);
SetPlaneTextureRotation(state, &plane, texture);
DrawSubsectors(di, state);
@ -362,6 +366,10 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
{
if (!texture->GetTranslucency()) state.AlphaFunc(Alpha_GEqual, gl_mask_threshold);
else state.AlphaFunc(Alpha_GEqual, 0.f);
if (level.info->DirectionalLightMode == 2)
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
state.SetMaterial(texture, UF_Texture, 0, CLAMP_NONE, 0, -1);
SetPlaneTextureRotation(state, &plane, texture);
DrawSubsectors(di, state);
@ -369,6 +377,7 @@ void HWFlat::DrawFlat(HWDrawInfo *di, FRenderState &state, bool translucent)
}
state.SetRenderStyle(DefaultRenderStyle());
}
state.SetDirectionalLight(FVector4(0.f, 0.f, 0.f, 0.f));
state.SetObjectColor(0xffffffff);
state.SetAddColor(0);
state.ApplyTextureManipulation(nullptr);

View file

@ -280,3 +280,7 @@ bool HWDrawInfo::CheckFog(sector_t *frontsector, sector_t *backsector)
backsector->GetTexture(sector_t::ceiling)!=skyflatnum));
}
FVector4 HWDrawInfo::GetDirectionalLight(void)
{
return Level->DirectionalLight;
}

View file

@ -231,6 +231,10 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
state.SetObjectColor2((color1 != color2) ? color2 : PalEntry(0));
state.SetAddColor(side->GetAdditiveColor(tierndx, frontsector));
state.ApplyTextureManipulation(&tier.TextureFx);
if (level.info->DirectionalLightMode == 2)
{
state.SetDirectionalLight(di->GetDirectionalLight());
}
if (color1 != color2)
{
@ -304,6 +308,7 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
state.EnableGlow(false);
state.EnableGradient(false);
state.ApplyTextureManipulation(nullptr);
state.SetDirectionalLight(FVector4(0.f, 0.f, 0.f, 0.f));
}
//==========================================================================

View file

@ -2481,6 +2481,55 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, setFrozen, setFrozen)
//
//=====================================================================================
static void SetDirectionalLight(FLevelLocals *self, double x, double y, double z, double strength)
{
// normalize the vector
DVector3 dlv = DVector3(x, y, z);
dlv.MakeUnit();
self->DirectionalLight = FVector4(static_cast<float>(dlv.X), static_cast<float>(dlv.Y), static_cast<float>(dlv.Z), static_cast<float>(strength));
}
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SetDirectionalLight, SetDirectionalLight)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_FLOAT(strength);
SetDirectionalLight(self, x, y, z, strength);
return 0;
}
static void GetDirectionalLightVector(FLevelLocals *self, DVector3 *result)
{
*result = DVector3(self->DirectionalLight.X, self->DirectionalLight.Y, self->DirectionalLight.Z);
}
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetDirectionalLightVector, GetDirectionalLightVector)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
DVector3 result;
GetDirectionalLightVector(self, &result);
ACTION_RETURN_VEC3(result);
}
static double GetDirectionalLightStrength(FLevelLocals *self)
{
return self->DirectionalLight.W;
}
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetDirectionalLightStrength, GetDirectionalLightStrength)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
ACTION_RETURN_FLOAT(GetDirectionalLightStrength(self));
}
//=====================================================================================
//
//
//
//=====================================================================================
DEFINE_ACTION_FUNCTION_NATIVE(_AltHUD, GetLatency, Net_GetLatency)
{
PARAM_PROLOGUE;
@ -2721,6 +2770,7 @@ DEFINE_FIELD(FLevelLocals, fogdensity)
DEFINE_FIELD(FLevelLocals, outsidefogdensity)
DEFINE_FIELD(FLevelLocals, skyfog)
DEFINE_FIELD(FLevelLocals, pixelstretch)
DEFINE_FIELD(FLevelLocals, DirectionalLightMode)
DEFINE_FIELD(FLevelLocals, MusicVolume)
DEFINE_FIELD(FLevelLocals, deathsequence)
DEFINE_FIELD_BIT(FLevelLocals, frozenstate, frozen, 1) // still needed for backwards compatibility.

View file

@ -35,11 +35,24 @@ vec3 lightContribution(int i, vec3 normal)
}
}
float lightDirectionalAttenuation(vec3 normal)
{
vec3 lightDirectionalDir = uDirectionalLight.xyz;
return clamp(dot(lightDirectionalDir, normal), 0.0, 1.0);
}
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
vec3 normal = material.Normal;
if (uDirectionalLight.w != 0 && normal != vec3(0.0))
{
float lightDirectionalStrength = uDirectionalLight.w;
dynlight.rgb += color * lightDirectionalAttenuation(normal) * lightDirectionalStrength;
color *= 1.0 - lightDirectionalStrength;
}
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);

View file

@ -80,6 +80,36 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
vec3 Lo = uDynLightColor.rgb;
if (uDirectionalLight.w != 0 && N != vec3(0.0))
{
float lightDirectionalStrength = uDirectionalLight.w;
vec3 lightDirectionalDir = uDirectionalLight.xyz;
float attenuation = clamp(dot(N, lightDirectionalDir), 0.0, 1.0);
if (attenuation > 0.0)
{
vec3 H = normalize(V + lightDirectionalDir);
vec3 radiance = ambientLight.rgb * attenuation * lightDirectionalStrength;
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, lightDirectionalDir, roughness);
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
vec3 kS = F;
vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic);
vec3 nominator = NDF * G * F;
float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, lightDirectionalDir), 0.0, 1.0);
vec3 specular = nominator / max(denominator, 0.001);
Lo += (kD * albedo / PI + specular) * radiance;
}
ambientLight *= 1.0 - lightDirectionalStrength;
}
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);

View file

@ -34,6 +34,20 @@ vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA)
return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp));
}
vec2 lightDirectionalAttenuation(vec3 normal, vec3 viewdir)
{
vec3 lightDirectionalDir = uDirectionalLight.xyz;
float attenuation = clamp(dot(lightDirectionalDir, normal), 0.0, 1.0);
float glossiness = uSpecularMaterial.x;
float specularLevel = uSpecularMaterial.y;
vec3 halfdir = normalize(viewdir + lightDirectionalDir);
float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f);
float phExp = glossiness * 4.0f;
return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp));
}
vec3 ProcessMaterialLight(Material material, vec3 color)
{
vec4 dynlight = uDynLightColor;
@ -42,6 +56,15 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
vec3 normal = material.Normal;
vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz);
if (uDirectionalLight.w != 0 && normal != vec3(0.0))
{
float lightDirectionalStrength = uDirectionalLight.w;
vec2 lightLevelAttenuation = lightDirectionalAttenuation(normal, viewdir) * lightDirectionalStrength;
dynlight.rgb += color * lightLevelAttenuation.x;
specular.rgb += color * lightLevelAttenuation.y;
color *= 1.0 - lightDirectionalStrength;
}
if (uLightIndex >= 0)
{
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);

View file

@ -442,12 +442,17 @@ struct LevelLocals native
native readonly int outsidefogdensity;
native readonly int skyfog;
native readonly float pixelstretch;
native readonly int8 DirectionalLightMode;
native readonly float MusicVolume;
native name deathsequence;
native readonly int compatflags;
native readonly int compatflags2;
native readonly LevelInfo info;
native void SetDirectionalLight(double x, double y, double z, double strength);
native Vector3 GetDirectionalLightVector(void);
native double GetDirectionalLightStrength(void);
native String GetUDMFString(int type, int index, Name key);
native int GetUDMFInt(int type, int index, Name key);
native double GetUDMFFloat(int type, int index, Name key);