From b6f0bc0da323515a544de14563930358b78dac27 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 21 May 2022 12:54:43 -0500 Subject: [PATCH] Merged https://github.com/coelckers/gzdoom/pull/1554 --- src/common/engine/serializer.cpp | 5 ++ src/common/engine/serializer.h | 1 + src/common/models/modelrenderer.h | 2 +- src/common/rendering/gl/gl_renderstate.cpp | 1 + src/common/rendering/gl/gl_shader.cpp | 4 ++ src/common/rendering/gl/gl_shader.h | 1 + .../hwrenderer/data/hw_renderstate.h | 8 +++ .../rendering/vulkan/shaders/vk_shader.cpp | 3 ++ src/g_level.cpp | 3 ++ src/g_levellocals.h | 2 + src/gamedata/g_mapinfo.cpp | 25 ++++++++++ src/gamedata/g_mapinfo.h | 2 + src/p_saveg.cpp | 3 +- src/r_data/models.cpp | 6 ++- src/r_data/models.h | 1 + src/rendering/hwrenderer/hw_models.cpp | 14 +++++- src/rendering/hwrenderer/hw_models.h | 2 +- src/rendering/hwrenderer/scene/hw_decal.cpp | 8 +++ src/rendering/hwrenderer/scene/hw_drawinfo.h | 1 + src/rendering/hwrenderer/scene/hw_flats.cpp | 9 ++++ .../hwrenderer/scene/hw_lighting.cpp | 4 ++ src/rendering/hwrenderer/scene/hw_walls.cpp | 5 ++ src/scripting/vmthunks.cpp | 50 +++++++++++++++++++ wadsrc/static/shaders/glsl/material_normal.fp | 13 +++++ wadsrc/static/shaders/glsl/material_pbr.fp | 30 +++++++++++ .../static/shaders/glsl/material_specular.fp | 23 +++++++++ wadsrc/static/zscript/doombase.zs | 5 ++ 27 files changed, 226 insertions(+), 5 deletions(-) diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index f42289573..9fb3f8432 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -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(key, &value[0], defval ? &(*defval)[0] : nullptr, 4, true); +} diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index b114923df..194cbe901 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -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 >*/> FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) diff --git a/src/common/models/modelrenderer.h b/src/common/models/modelrenderer.h index 38786afe6..ed99c4744 100644 --- a/src/common/models/modelrenderer.h +++ b/src/common/models/modelrenderer.h @@ -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; diff --git a/src/common/rendering/gl/gl_renderstate.cpp b/src/common/rendering/gl/gl_renderstate.cpp index 688e46904..674029c8d 100644 --- a/src/common/rendering/gl/gl_renderstate.cpp +++ b/src/common/rendering/gl/gl_renderstate.cpp @@ -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 diff --git a/src/common/rendering/gl/gl_shader.cpp b/src/common/rendering/gl/gl_shader.cpp index 80e6a0e8a..e22fb35b3 100644 --- a/src/common/rendering/gl/gl_shader.cpp +++ b/src/common/rendering/gl/gl_shader.cpp @@ -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"); diff --git a/src/common/rendering/gl/gl_shader.h b/src/common/rendering/gl/gl_shader.h index 33381b6dc..49c108535 100644 --- a/src/common/rendering/gl/gl_shader.h +++ b/src/common/rendering/gl/gl_shader.h @@ -266,6 +266,7 @@ class FShader FBufferedUniform2f muNpotEmulation; #endif + FUniform4f muDirectionalLight; int lights_index; int modelmatrix_index; int normalmodelmatrix_index; diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index bd8fd4d9e..43a3a83d2 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -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. diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index dd8d442e3..d895b8f9e 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -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 diff --git a/src/g_level.cpp b/src/g_level.cpp index 8f0652d56..56523656f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1757,6 +1757,9 @@ void FLevelLocals::Init() pixelstretch = info->pixelstretch; + DirectionalLightMode = info->DirectionalLightMode; + DirectionalLight = info->DirectionalLight; + compatflags.Callback(); compatflags2.Callback(); diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 265997f5c..e8b49aad3 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -685,6 +685,8 @@ public: bool lightadditivesurfaces; bool notexturefill; int ImpactDecalCount; + int8_t DirectionalLightMode; + FVector4 DirectionalLight; FDynamicLight *lights; diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index e8cb532a5..5c7b01ed9 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -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) { diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index 4ed13e5ba..5a8438f96 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -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. diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 49d479b5a..fd8b905ff 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -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 diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index f6f9d4aa0..d1939af20 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -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); diff --git a/src/r_data/models.h b/src/r_data/models.h index 6a2623027..5f3c11840 100644 --- a/src/r_data/models.h +++ b/src/r_data/models.h @@ -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); diff --git a/src/rendering/hwrenderer/hw_models.cpp b/src/rendering/hwrenderer/hw_models.cpp index ff99702f0..ee6bcca66 100644 --- a/src/rendering/hwrenderer/hw_models.cpp +++ b/src/rendering/hwrenderer/hw_models.cpp @@ -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); diff --git a/src/rendering/hwrenderer/hw_models.h b/src/rendering/hwrenderer/hw_models.h index 28026905e..e2726adba 100644 --- a/src/rendering/hwrenderer/hw_models.h +++ b/src/rendering/hwrenderer/hw_models.h @@ -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; diff --git a/src/rendering/hwrenderer/scene/hw_decal.cpp b/src/rendering/hwrenderer/scene/hw_decal.cpp index 980fc52a5..2692f2967 100644 --- a/src/rendering/hwrenderer/scene/hw_decal.cpp +++ b/src/rendering/hwrenderer/scene/hw_decal.cpp @@ -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)); } //========================================================================== diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index 4d92c1cbc..41e455ccf 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -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: diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index 5b57c9f94..45a78c726 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -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); diff --git a/src/rendering/hwrenderer/scene/hw_lighting.cpp b/src/rendering/hwrenderer/scene/hw_lighting.cpp index ca8fa546d..09ef8344d 100644 --- a/src/rendering/hwrenderer/scene/hw_lighting.cpp +++ b/src/rendering/hwrenderer/scene/hw_lighting.cpp @@ -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; +} diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 88ed52068..2b8b68564 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -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)); } //========================================================================== diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index d66fc0c6f..b283df096 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -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(dlv.X), static_cast(dlv.Y), static_cast(dlv.Z), static_cast(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. diff --git a/wadsrc/static/shaders/glsl/material_normal.fp b/wadsrc/static/shaders/glsl/material_normal.fp index add128812..9fac48000 100644 --- a/wadsrc/static/shaders/glsl/material_normal.fp +++ b/wadsrc/static/shaders/glsl/material_normal.fp @@ -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); diff --git a/wadsrc/static/shaders/glsl/material_pbr.fp b/wadsrc/static/shaders/glsl/material_pbr.fp index 6859c28bb..dfd06b716 100644 --- a/wadsrc/static/shaders/glsl/material_pbr.fp +++ b/wadsrc/static/shaders/glsl/material_pbr.fp @@ -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); diff --git a/wadsrc/static/shaders/glsl/material_specular.fp b/wadsrc/static/shaders/glsl/material_specular.fp index 60a39ab1e..3a9795613 100644 --- a/wadsrc/static/shaders/glsl/material_specular.fp +++ b/wadsrc/static/shaders/glsl/material_specular.fp @@ -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); diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index 2cf4409ee..84c073fe6 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -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);