From f3c55c01c86fbc48e92ed401c4ab618143b7e152 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 20 Jan 2018 16:28:24 +0100 Subject: [PATCH 01/23] Add material definition to GLDEFS --- src/g_shared/a_dynlightdata.cpp | 8 ++- src/gl/textures/gl_texture.cpp | 111 ++++++++++++++++++++++++++++++++ src/textures/textures.h | 10 +++ 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/g_shared/a_dynlightdata.cpp b/src/g_shared/a_dynlightdata.cpp index fcdbcd3d1..2c2a6bd08 100644 --- a/src/g_shared/a_dynlightdata.cpp +++ b/src/g_shared/a_dynlightdata.cpp @@ -56,6 +56,7 @@ int ScriptDepth; void gl_InitGlow(FScanner &sc); void gl_ParseBrightmap(FScanner &sc, int); +void gl_ParseMaterial(FScanner &sc, int); void gl_DestroyUserShaders(); void gl_ParseHardwareShader(FScanner &sc, int deflump); void gl_ParseDetailTexture(FScanner &sc); @@ -906,7 +907,8 @@ static const char *CoreKeywords[]= "hardwareshader", "detail", "#include", - NULL + "material", + nullptr }; @@ -928,6 +930,7 @@ enum TAG_HARDWARESHADER, TAG_DETAIL, TAG_INCLUDE, + TAG_MATERIAL }; @@ -1285,6 +1288,9 @@ static void DoParseDefs(FScanner &sc, int workingLump) case TAG_BRIGHTMAP: gl_ParseBrightmap(sc, workingLump); break; + case TAG_MATERIAL: + gl_ParseMaterial(sc, workingLump); + break; case TAG_HARDWARESHADER: gl_ParseHardwareShader(sc, workingLump); break; diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index ddfd7ecc9..e7e459186 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -195,6 +195,11 @@ FTexture::MiscGLInfo::MiscGLInfo() throw() Material[1] = Material[0] = NULL; SystemTexture[1] = SystemTexture[0] = NULL; Brightmap = NULL; + Normal = NULL; + Specular = NULL; + Metallic = NULL; + Roughness = NULL; + AmbientOcclusion = NULL; } FTexture::MiscGLInfo::~MiscGLInfo() @@ -542,6 +547,112 @@ int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotat return 0; } +//========================================================================== +// +// Parses a material definition +// +//========================================================================== + +void gl_ParseMaterial(FScanner &sc, int deflump) +{ + int type = FTexture::TEX_Any; + bool disable_fullbright = false; + bool disable_fullbright_specified = false; + bool thiswad = false; + bool iwad = false; + + FTexture *textures[6]; + const char *keywords[7] = { "brightmap", "normal", "specular", "metallic", "roughness", "ao", nullptr }; + const char *notFound[6] = { "Brightmap", "Normalmap", "Specular texture", "Metallic texture", "Roughness texture", "Ambient occlusion texture" }; + memset(textures, 0, sizeof(textures)); + + sc.MustGetString(); + if (sc.Compare("texture")) type = FTexture::TEX_Wall; + else if (sc.Compare("flat")) type = FTexture::TEX_Flat; + else if (sc.Compare("sprite")) type = FTexture::TEX_Sprite; + else sc.UnGet(); + + sc.MustGetString(); + FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); + FTexture *tex = TexMan[no]; + + sc.MustGetToken('{'); + while (!sc.CheckToken('}')) + { + sc.MustGetString(); + if (sc.Compare("disablefullbright")) + { + // This can also be used without a brightness map to disable + // fullbright in rotations that only use brightness maps on + // other angles. + disable_fullbright = true; + disable_fullbright_specified = true; + } + else if (sc.Compare("thiswad")) + { + // only affects textures defined in the WAD containing the definition file. + thiswad = true; + } + else if (sc.Compare ("iwad")) + { + // only affects textures defined in the IWAD. + iwad = true; + } + else + { + for (int i = 0; keywords[i] != nullptr; i++) + { + if (sc.Compare (keywords[i])) + { + sc.MustGetString(); + if (textures[i]) + Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->Name.GetChars() : "(null)"); + textures[i] = TexMan.FindTexture(sc.String, FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny); + if (!textures[i]) + Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->Name.GetChars() : "(null)"); + break; + } + } + } + } + if (!tex) + { + return; + } + if (thiswad || iwad) + { + bool useme = false; + int lumpnum = tex->GetSourceLump(); + + if (lumpnum != -1) + { + if (iwad && Wads.GetLumpFile(lumpnum) <= Wads.GetIwadNum()) useme = true; + if (thiswad && Wads.GetLumpFile(lumpnum) == deflump) useme = true; + } + if (!useme) return; + } + + FTexture **bindings[6] = + { + &tex->gl_info.Brightmap, + &tex->gl_info.Normal, + &tex->gl_info.Specular, + &tex->gl_info.Metallic, + &tex->gl_info.Roughness, + &tex->gl_info.AmbientOcclusion + }; + for (int i = 0; keywords[i] != nullptr; i++) + { + if (textures[i]) + { + textures[i]->bMasked = false; + *bindings[i] = textures[i]; + } + } + + if (disable_fullbright_specified) + tex->gl_info.bDisableFullbright = disable_fullbright; +} //========================================================================== // diff --git a/src/textures/textures.h b/src/textures/textures.h index 539d38c43..72501e492 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -328,6 +328,11 @@ protected: Rotations = other->Rotations; gl_info = other->gl_info; gl_info.Brightmap = NULL; + gl_info.Normal = NULL; + gl_info.Specular = NULL; + gl_info.Metallic = NULL; + gl_info.Roughness = NULL; + gl_info.AmbientOcclusion = NULL; gl_info.areas = NULL; } @@ -362,6 +367,11 @@ public: FMaterial *Material[2]; FGLTexture *SystemTexture[2]; FTexture *Brightmap; + FTexture *Normal; // Normal map texture + FTexture *Specular; // Specular light texture for the diffuse+normal+specular light model + FTexture *Metallic; // Metalness texture for the physically based rendering (PBR) light model + FTexture *Roughness; // Roughness texture for PBR + FTexture *AmbientOcclusion; // Ambient occlusion texture for PBR PalEntry GlowColor; int GlowHeight; FloatRect *areas; From 4dd2d789f47fba1178e89bd49ae59f541de9c610 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 21 Jan 2018 01:19:16 +0100 Subject: [PATCH 02/23] - Rename mTextureEffects to mMaterialShaders to help distinguish between those and effect shaders (mEffectShaders) - Add MaterialShaderIndex enum --- src/gl/shaders/gl_shader.cpp | 45 ++++++++++++++++----------------- src/gl/shaders/gl_shader.h | 35 +++++++++++++++++-------- src/gl/textures/gl_material.cpp | 8 +++--- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index d551106a4..c7944f141 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -376,8 +376,7 @@ struct FDefaultShader const char * gettexelfunc; }; -// Note: the FIRST_USER_SHADER constant in gl_shader.h needs -// to be updated whenever the size of this array is modified. +// Note: the ShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. static const FDefaultShader defaultshaders[]= { {"Default", "shaders/glsl/func_normal.fp"}, @@ -522,8 +521,8 @@ FShaderCollection::~FShaderCollection() void FShaderCollection::CompileShaders(EPassType passType) { - mTextureEffects.Clear(); - mTextureEffectsNAT.Clear(); + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); for (int i = 0; i < MAX_EFFECTS; i++) { mEffectShaders[i] = NULL; @@ -532,11 +531,11 @@ void FShaderCollection::CompileShaders(EPassType passType) for(int i=0;defaultshaders[i].ShaderName != NULL;i++) { FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true, passType); - mTextureEffects.Push(shc); - if (i <= 3) + mMaterialShaders.Push(shc); + if (i <= SHADER_Brightmap) { FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false, passType); - mTextureEffectsNAT.Push(shc); + mMaterialShadersNAT.Push(shc); } } @@ -546,7 +545,7 @@ void FShaderCollection::CompileShaders(EPassType passType) FName sfn = name; FShader *shc = Compile(sfn, usershaders[i], true, passType); - mTextureEffects.Push(shc); + mMaterialShaders.Push(shc); } for(int i=0;imName == sfn) + if (mMaterialShaders[i]->mName == sfn) { return i; } @@ -636,19 +635,19 @@ void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view) VSMatrix norm; norm.computeNormalMatrix(*view); - for (int i = 0; i < 4; i++) + for (int i = 0; i < SHADER_NoTexture; i++) { - mTextureEffects[i]->ApplyMatrices(proj, view, &norm); - mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm); + mMaterialShaders[i]->ApplyMatrices(proj, view, &norm); + mMaterialShadersNAT[i]->ApplyMatrices(proj, view, &norm); } - mTextureEffects[4]->ApplyMatrices(proj, view, &norm); + mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(proj, view, &norm); if (gl_fuzztype != 0) { - mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm); + mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(proj, view, &norm); } - for (unsigned i = 12; i < mTextureEffects.Size(); i++) + for (unsigned i = FIRST_USER_SHADER; i < mMaterialShaders.Size(); i++) { - mTextureEffects[i]->ApplyMatrices(proj, view, &norm); + mMaterialShaders[i]->ApplyMatrices(proj, view, &norm); } for (int i = 0; i < MAX_EFFECTS; i++) { diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index f41f7467b..6995c7b28 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -355,8 +355,8 @@ private: class FShaderCollection { - TArray mTextureEffects; - TArray mTextureEffectsNAT; + TArray mMaterialShaders; + TArray mMaterialShadersNAT; FShader *mEffectShaders[MAX_EFFECTS]; void Clean(); @@ -372,13 +372,13 @@ public: void ResetFixedColormap() { - for (unsigned i = 0; i < mTextureEffects.Size(); i++) + for (unsigned i = 0; i < mMaterialShaders.Size(); i++) { - mTextureEffects[i]->currentfixedcolormap = -1; + mMaterialShaders[i]->currentfixedcolormap = -1; } - for (unsigned i = 0; i < mTextureEffectsNAT.Size(); i++) + for (unsigned i = 0; i < mMaterialShadersNAT.Size(); i++) { - mTextureEffectsNAT[i]->currentfixedcolormap = -1; + mMaterialShadersNAT[i]->currentfixedcolormap = -1; } } @@ -387,17 +387,32 @@ public: // indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom if (!alphateston && eff <= 3) { - return mTextureEffectsNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway + return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway } - if (eff < mTextureEffects.Size()) + if (eff < mMaterialShaders.Size()) { - return mTextureEffects[eff]; + return mMaterialShaders[eff]; } return NULL; } }; -#define FIRST_USER_SHADER 12 +enum MaterialShaderIndex +{ + SHADER_Default = 0, + SHADER_Warp1 = 1, + SHADER_Warp2 = 2, + SHADER_Brightmap = 3, + SHADER_NoTexture = 4, + SHADER_BasicFuzz = 5, + SHADER_SmoothFuzz = 6, + SHADER_SwirlyFuzz = 7, + SHADER_TranslucentFuzz = 8, + SHADER_JaggedFuzz = 9, + SHADER_NoiseFuzz = 10, + SHADER_SmoothNoiseFuzz = 11, + FIRST_USER_SHADER = 12 +}; enum { diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index 53d22f857..c716f5717 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -438,7 +438,7 @@ int FMaterial::mMaxBound; FMaterial::FMaterial(FTexture * tx, bool expanded) { - mShaderIndex = 0; + mShaderIndex = SHADER_Default; tex = tx; // TODO: apply custom shader object here @@ -449,7 +449,7 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) */ if (tx->bWarped) { - mShaderIndex = tx->bWarped; + mShaderIndex = tx->bWarped; // This picks SHADER_Warp1 or SHADER_Warp2 tx->gl_info.shaderspeed = static_cast(tx)->GetSpeed(); } else if (tx->bHasCanvas) @@ -474,7 +474,7 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) ValidateSysTexture(tx->gl_info.Brightmap, expanded); FTextureLayer layer = {tx->gl_info.Brightmap, false}; mTextureLayers.Push(layer); - mShaderIndex = 3; + mShaderIndex = SHADER_Brightmap; } } } @@ -804,7 +804,7 @@ void FMaterial::GetTexCoordInfo(FTexCoordInfo *tci, float x, float y) const int FMaterial::GetAreas(FloatRect **pAreas) const { - if (mShaderIndex == 0) // texture splitting can only be done if there's no attached effects + if (mShaderIndex == SHADER_Default) // texture splitting can only be done if there's no attached effects { FTexture *tex = mBaseLayer->tex; *pAreas = tex->gl_info.areas; From 0f69778e233ebab0b8eafe2fb02e206a535bc109 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 21 Jan 2018 01:53:44 +0100 Subject: [PATCH 03/23] - Add new material shader entries for specular and PBR light modes --- src/gl/scene/gl_sprite.cpp | 2 +- src/gl/scene/gl_weapon.cpp | 2 +- src/gl/shaders/gl_shader.cpp | 44 ++++++++++++++++++++---------------- src/gl/shaders/gl_shader.h | 32 ++++++++++++++------------ 4 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index edd0da1d9..3a27a7cde 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -991,7 +991,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) { // Todo: implement shader selection here RenderStyle = LegacyRenderStyles[STYLE_Translucent]; - OverrideShader = gl_fuzztype + 4; + OverrideShader = SHADER_NoTexture + gl_fuzztype; trans = 0.99f; // trans may not be 1 here hw_styleflags = STYLEHW_NoAlphaTest; } diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 69551f28a..2061d67f3 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -355,7 +355,7 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { // Todo: implement shader selection here RenderStyle = LegacyRenderStyles[STYLE_Translucent]; - OverrideShader = gl_fuzztype + 4; + OverrideShader = SHADER_NoTexture + gl_fuzztype; trans = 0.99f; // trans may not be 1 here } else diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index c7944f141..5d7cdd359 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -325,9 +325,10 @@ bool FShader::Bind() // //========================================================================== -FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType) +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType) { FString defines; + defines += shaderdefines; // this can't be in the shader code due to ATI strangeness. if (gl.MaxLights() == 128) defines += "#define MAXLIGHTS128\n"; if (!usediscard) defines += "#define NO_ALPHATEST\n"; @@ -374,24 +375,29 @@ struct FDefaultShader { const char * ShaderName; const char * gettexelfunc; + const char * Defines; }; -// Note: the ShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. +// Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. static const FDefaultShader defaultshaders[]= { - {"Default", "shaders/glsl/func_normal.fp"}, - {"Warp 1", "shaders/glsl/func_warp1.fp"}, - {"Warp 2", "shaders/glsl/func_warp2.fp"}, - {"Brightmap","shaders/glsl/func_brightmap.fp"}, - {"No Texture", "shaders/glsl/func_notexture.fp"}, - {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp"}, - {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp"}, - {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp"}, - {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp"}, - {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp"}, - {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp"}, - {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp"}, - {NULL,NULL} + {"Default", "shaders/glsl/func_normal.fp", ""}, + {"Warp 1", "shaders/glsl/func_warp1.fp", ""}, + {"Warp 2", "shaders/glsl/func_warp2.fp", ""}, + {"Brightmap","shaders/glsl/func_brightmap.fp", ""}, + {"Specular","shaders/glsl/func_normal.fp", "#define SPECULAR\n"}, + {"SpecularBrightmap","shaders/glsl/func_brightmap.fp", "#define SPECULAR\n"}, + {"PBR","shaders/glsl/func_normal.fp", "#define PBR\n"}, + {"PBRBrightmap","shaders/glsl/func_brightmap.fp", "#define PBR\n"}, + {"No Texture", "shaders/glsl/func_notexture.fp", ""}, + {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", ""}, + {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", ""}, + {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", ""}, + {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", ""}, + {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", ""}, + {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", ""}, + {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", ""}, + {NULL,NULL,NULL} }; static TArray usershaders; @@ -530,11 +536,11 @@ void FShaderCollection::CompileShaders(EPassType passType) for(int i=0;defaultshaders[i].ShaderName != NULL;i++) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, true, passType); mMaterialShaders.Push(shc); - if (i <= SHADER_Brightmap) + if (i < SHADER_NoTexture) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, false, passType); mMaterialShadersNAT.Push(shc); } } @@ -544,7 +550,7 @@ void FShaderCollection::CompileShaders(EPassType passType) FString name = ExtractFileBase(usershaders[i]); FName sfn = name; - FShader *shc = Compile(sfn, usershaders[i], true, passType); + FShader *shc = Compile(sfn, usershaders[i], "", true, passType); mMaterialShaders.Push(shc); } diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 6995c7b28..aa81808ec 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -365,7 +365,7 @@ class FShaderCollection public: FShaderCollection(EPassType passType); ~FShaderCollection(); - FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType); + FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); FShader *BindEffect(int effect); void ApplyMatrices(VSMatrix *proj, VSMatrix *view); @@ -399,19 +399,23 @@ public: enum MaterialShaderIndex { - SHADER_Default = 0, - SHADER_Warp1 = 1, - SHADER_Warp2 = 2, - SHADER_Brightmap = 3, - SHADER_NoTexture = 4, - SHADER_BasicFuzz = 5, - SHADER_SmoothFuzz = 6, - SHADER_SwirlyFuzz = 7, - SHADER_TranslucentFuzz = 8, - SHADER_JaggedFuzz = 9, - SHADER_NoiseFuzz = 10, - SHADER_SmoothNoiseFuzz = 11, - FIRST_USER_SHADER = 12 + SHADER_Default, + SHADER_Warp1, + SHADER_Warp2, + SHADER_Brightmap, + SHADER_Specular, + SHADER_SpecularBrightmap, + SHADER_PBR, + SHADER_PBRBrightmap, + SHADER_NoTexture, + SHADER_BasicFuzz, + SHADER_SmoothFuzz, + SHADER_SwirlyFuzz, + SHADER_TranslucentFuzz, + SHADER_JaggedFuzz, + SHADER_NoiseFuzz, + SHADER_SmoothNoiseFuzz, + FIRST_USER_SHADER }; enum From e045fb57c9e57ca94cf66d19312cfa664a741251 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 23 Jan 2018 20:51:48 +0100 Subject: [PATCH 04/23] - Declare new textures for specular and pbr modes --- wadsrc/static/shaders/glsl/func_brightmap.fp | 11 +++++++++- wadsrc/static/shaders/glsl/main.fp | 22 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/shaders/glsl/func_brightmap.fp b/wadsrc/static/shaders/glsl/func_brightmap.fp index 8e5f44d04..00760bd62 100644 --- a/wadsrc/static/shaders/glsl/func_brightmap.fp +++ b/wadsrc/static/shaders/glsl/func_brightmap.fp @@ -1,4 +1,13 @@ +#if defined(SPECULAR) +uniform sampler2D texture4; +#define brighttexture texture4 +#elif defined(PBR) +uniform sampler2D texture6; +#define brighttexture texture6 +#else uniform sampler2D texture2; +#define brighttexture texture2 +#endif vec4 ProcessTexel() { @@ -7,6 +16,6 @@ vec4 ProcessTexel() vec4 ProcessLight(vec4 color) { - vec4 brightpix = desaturate(texture(texture2, vTexCoord.st)); + vec4 brightpix = desaturate(texture(brighttexture, vTexCoord.st)); return vec4(min (color.rgb + brightpix.rgb, 1.0), color.a); } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 25a2c14d2..3aa404162 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -28,6 +28,22 @@ out vec4 FragNormal; uniform sampler2D tex; uniform sampler2D ShadowMap; +#if defined(SPECULAR) +uniform sampler2D texture2; +uniform sampler2D texture3; +#define normaltexture texture2 +#define speculartexture texture3 +#elif defined(PBR) +uniform sampler2D texture2; +uniform sampler2D texture3; +uniform sampler2D texture4; +uniform sampler2D texture5; +#define normaltexture texture2 +#define metallictexture texture3 +#define roughnesstexture texture4 +#define aotexture texture5 +#endif + vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); @@ -441,6 +457,12 @@ void main() { vec4 frag = ProcessTexel(); +#if defined(SPECULAR) + frag = texture(speculartexture, vTexCoord.st); +#elif defined(PBR) + frag = texture(metallictexture, vTexCoord.st); +#endif + #ifndef NO_ALPHATEST if (frag.a <= uAlphaThreshold) discard; #endif From 81c6808d2ac681765f07f72988c50c693be9451f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 23 Jan 2018 23:10:28 +0100 Subject: [PATCH 05/23] - Add specular and normal map handling to main.fp --- src/gl/textures/gl_material.cpp | 26 +++++- wadsrc/static/shaders/glsl/main.fp | 140 +++++++++++++++++++++++------ 2 files changed, 137 insertions(+), 29 deletions(-) diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index c716f5717..859706772 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -468,13 +468,37 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) } else { + if (tx->gl_info.Normal && tx->gl_info.Specular) + { + for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Specular }) + { + ValidateSysTexture(texture, expanded); + mTextureLayers.Push({ texture, false }); + } + mShaderIndex = SHADER_Specular; + } + else if (tx->gl_info.Normal && tx->gl_info.Metallic && tx->gl_info.Roughness && tx->gl_info.AmbientOcclusion) + { + for (auto &texture : { tx->gl_info.Normal, tx->gl_info.Metallic, tx->gl_info.Roughness, tx->gl_info.AmbientOcclusion }) + { + ValidateSysTexture(texture, expanded); + mTextureLayers.Push({ texture, false }); + } + mShaderIndex = SHADER_PBR; + } + tx->CreateDefaultBrightmap(); if (tx->gl_info.Brightmap != NULL) { ValidateSysTexture(tx->gl_info.Brightmap, expanded); FTextureLayer layer = {tx->gl_info.Brightmap, false}; mTextureLayers.Push(layer); - mShaderIndex = SHADER_Brightmap; + if (mShaderIndex == SHADER_Specular) + mShaderIndex = SHADER_SpecularBrightmap; + else if (mShaderIndex == SHADER_PBR) + mShaderIndex = SHADER_PBRBrightmap; + else + mShaderIndex = SHADER_Brightmap; } } } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 3aa404162..71e973c17 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -268,29 +268,112 @@ float diffuseContribution(vec3 lightDirection, vec3 normal) //=========================================================================== // -// Calculates the brightness of a dynamic point light -// Todo: Find a better way to define which lighting model to use. -// (Specular mode has been removed for now.) +// Blinn specular light calculation // //=========================================================================== -float pointLightAttenuation(vec4 lightpos, float lightcolorA) +float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, vec3 faceNormal, float glossiness, float specularLevel) +{ + if (diffuseContribution > 0.0f) + { + vec3 viewDir = normalize(uCameraPos.xyz - pixelpos.xyz); + vec3 halfDir = normalize(lightDirection + viewDir); + float specAngle = max(dot(halfDir, faceNormal), 0.0f); + float phExp = glossiness * 4.0f; + return specularLevel * pow(specAngle, phExp); + } + else + { + return 0.0f; + } +} + +//=========================================================================== +// +// Adjust normal vector according to the normal map +// +//=========================================================================== + +#if defined(SPECULAR) || defined(PBR) +mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) +{ + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + + // solve the linear system + vec3 dp2perp = cross(n, dp2); // cross(dp2, n); + vec3 dp1perp = cross(dp1, n); // cross(n, dp1); + vec3 t = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 b = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = inversesqrt(max(dot(t,t), dot(b,b))); + return mat3(t * invmax, b * invmax, n); +} + +vec3 ApplyNormalMap() +{ + #define WITH_NORMALMAP_UNSIGNED + #define WITH_NORMALMAP_GREEN_UP + //#define WITH_NORMALMAP_2CHANNEL + + vec3 interpolatedNormal = normalize(gl_FrontFacing ? -vWorldNormal.xyz : vWorldNormal.xyz); + + vec3 map = texture(normaltexture, vTexCoord.st).xyz; + #if defined(WITH_NORMALMAP_UNSIGNED) + map = map * 255./127. - 128./127.; // Math so "odd" because 0.5 cannot be precisely described in an unsigned format + #endif + #if defined(WITH_NORMALMAP_2CHANNEL) + map.z = sqrt(1 - dot(map.xy, map.xy)); + #endif + #if defined(WITH_NORMALMAP_GREEN_UP) + map.y = -map.y; + #endif + + mat3 tbn = cotangent_frame(interpolatedNormal, pixelpos.xyz, vTexCoord.st); + vec3 bumpedNormal = normalize(tbn * map); + return bumpedNormal; +} +#else +vec3 ApplyNormalMap() +{ + return normalize(vWorldNormal.xyz); +} +#endif + +//=========================================================================== +// +// Calculates the brightness of a dynamic point light +// +//=========================================================================== + +vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) { float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - if (attenuation == 0.0) return 0.0; + if (attenuation == 0.0) return vec2(0.0); #ifdef SUPPORTS_SHADOWMAPS float shadowIndex = abs(lightcolorA) - 1.0; attenuation *= shadowmapAttenuation(lightpos, shadowIndex); #endif if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag { - return attenuation; + return vec2(attenuation, 0.0); } else { vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); - float diffuseAmount = diffuseContribution(lightDirection, normalize(vWorldNormal.xyz)); - return attenuation * diffuseAmount; + vec3 pixelnormal = ApplyNormalMap(); + float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); + +#if defined(SPECULAR) + float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, 10.0, 0.12); + return vec2(diffuseAmount, specularAmount) * attenuation; +#else + return vec2(attenuation * diffuseAmount, 0.0); +#endif } } @@ -315,7 +398,7 @@ float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle // //=========================================================================== -vec4 getLightColor(float fogdist, float fogfactor) +vec4 getLightColor(vec4 material, vec4 materialSpec, float fogdist, float fogfactor) { vec4 color = vColor; @@ -361,6 +444,7 @@ vec4 getLightColor(float fogdist, float fogfactor) // vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); #if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS if (uLightIndex >= 0) @@ -378,11 +462,11 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightspot1 = lights[i+2]; vec4 lightspot2 = lights[i+3]; - float attenuation = pointLightAttenuation(lightpos, lightcolor.a); + vec2 attenuation = pointLightAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - lightcolor.rgb *= attenuation; - dynlight.rgb += lightcolor.rgb; + attenuation.xy *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + dynlight.rgb += lightcolor.rgb * attenuation.x; + specular.rgb += lightcolor.rgb * attenuation.y; } // // subtractive lights @@ -394,19 +478,20 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightspot1 = lights[i+2]; vec4 lightspot2 = lights[i+3]; - float attenuation = pointLightAttenuation(lightpos, lightcolor.a); + vec2 attenuation = pointLightAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - lightcolor.rgb *= attenuation; - dynlight.rgb -= lightcolor.rgb; + attenuation.xy *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + dynlight.rgb -= lightcolor.rgb * attenuation.x; + specular.rgb -= lightcolor.rgb * attenuation.y; } } } #endif color.rgb = clamp(color.rgb + desaturate(dynlight).rgb, 0.0, 1.4); - + specular.rgb = clamp(specular.rgb + desaturate(specular).rgb, 0.0, 1.4); + // prevent any unintentional messing around with the alpha. - return vec4(color.rgb, vColor.a); + return vec4(material.rgb * color.rgb + materialSpec.rgb * specular.rgb, material.a * vColor.a); } //=========================================================================== @@ -457,12 +542,6 @@ void main() { vec4 frag = ProcessTexel(); -#if defined(SPECULAR) - frag = texture(speculartexture, vTexCoord.st); -#elif defined(PBR) - frag = texture(metallictexture, vTexCoord.st); -#endif - #ifndef NO_ALPHATEST if (frag.a <= uAlphaThreshold) discard; #endif @@ -492,8 +571,13 @@ void main() fogfactor = exp2 (uFogDensity * fogdist); } - - frag *= getLightColor(fogdist, fogfactor); +#if defined(SPECULAR) + vec4 materialSpec = texture(speculartexture, vTexCoord.st); +#else + vec4 materialSpec = vec4(0.0); +#endif + + frag = getLightColor(frag, materialSpec, fogdist, fogfactor); #if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS if (uLightIndex >= 0) @@ -513,7 +597,7 @@ void main() vec4 lightspot1 = lights[i+2]; vec4 lightspot2 = lights[i+3]; - float attenuation = pointLightAttenuation(lightpos, lightcolor.a); + float attenuation = pointLightAttenuation(lightpos, lightcolor.a).x; if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); lightcolor.rgb *= attenuation; From 18759024143f81ce180590d87b91167adf07ded8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 23 Jan 2018 23:59:58 +0100 Subject: [PATCH 06/23] - Do not flip the normal based on face direction --- wadsrc/static/shaders/glsl/main.fp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 71e973c17..6bc9f7a90 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -320,7 +320,7 @@ vec3 ApplyNormalMap() #define WITH_NORMALMAP_GREEN_UP //#define WITH_NORMALMAP_2CHANNEL - vec3 interpolatedNormal = normalize(gl_FrontFacing ? -vWorldNormal.xyz : vWorldNormal.xyz); + vec3 interpolatedNormal = normalize(vWorldNormal.xyz); vec3 map = texture(normaltexture, vTexCoord.st).xyz; #if defined(WITH_NORMALMAP_UNSIGNED) @@ -369,7 +369,7 @@ vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); #if defined(SPECULAR) - float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, 10.0, 0.12); + float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, 100.0, 200.0); return vec2(diffuseAmount, specularAmount) * attenuation; #else return vec2(attenuation * diffuseAmount, 0.0); From 7a59bcde4c0c77314b88125b6af5eba56f6e3289 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 25 Jan 2018 19:53:55 +0100 Subject: [PATCH 07/23] - move glossiness and specular level to GLDEFS --- src/gl/renderer/gl_renderstate.cpp | 3 +++ src/gl/renderer/gl_renderstate.h | 8 ++++++++ src/gl/shaders/gl_shader.cpp | 1 + src/gl/shaders/gl_shader.h | 1 + src/gl/textures/gl_texture.cpp | 14 ++++++++++++++ src/textures/textures.h | 2 ++ wadsrc/static/shaders/glsl/main.fp | 2 +- wadsrc/static/shaders/glsl/shaderdefs.i | 3 +++ 8 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 119444af6..499303cab 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -87,6 +87,8 @@ void FRenderState::Reset() mSpecialEffect = EFF_NONE; mClipHeight = 0.f; mClipHeightDirection = 0.f; + mGlossiness = 0.0f; + mSpecularLevel = 0.0f; mShaderTimer = 0.0f; ClearClipSplit(); @@ -178,6 +180,7 @@ bool FRenderState::ApplyShader() activeShader->muLightIndex.Set(mLightIndex); // will always be -1 for now activeShader->muClipSplit.Set(mClipSplit); activeShader->muViewHeight.Set(viewheight); + activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel); if (mGlowEnabled) { diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 92de96e9a..e6a6c1dcb 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -94,6 +94,7 @@ class FRenderState bool mLastDepthClamp; float mInterpolationFactor; float mClipHeight, mClipHeightDirection; + float mGlossiness, mSpecularLevel; float mShaderTimer; FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; @@ -152,6 +153,7 @@ public: } mEffectState = overrideshader >= 0? overrideshader : mat->mShaderIndex; mShaderTimer = mat->tex->gl_info.shaderspeed; + SetSpecular(mat->tex->gl_info.Glossiness, mat->tex->gl_info.SpecularLevel); mat->Bind(clampmode, translation); } @@ -386,6 +388,12 @@ public: mObjectColor2 = pe; } + void SetSpecular(float glossiness, float specularLevel) + { + mGlossiness = glossiness; + mSpecularLevel = specularLevel; + } + void SetFog(PalEntry c, float d) { const float LOG2E = 1.442692f; // = 1/log(2) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 833c1722d..bcaea9bb4 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -254,6 +254,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muClipHeight.Init(hShader, "uClipHeight"); muClipHeightDirection.Init(hShader, "uClipHeightDirection"); muAlphaThreshold.Init(hShader, "uAlphaThreshold"); + muSpecularMaterial.Init(hShader, "uSpecularMaterial"); muViewHeight.Init(hShader, "uViewHeight"); muTimer.Init(hShader, "timer"); diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 5b4e23c63..8041f4880 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -285,6 +285,7 @@ class FShader FBufferedUniform1f muClipHeightDirection; FBufferedUniform1f muAlphaThreshold; FBufferedUniform1i muViewHeight; + FBufferedUniform2f muSpecularMaterial; FBufferedUniform1f muTimer; int lights_index; diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index e7e459186..6501d9709 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -191,6 +191,8 @@ FTexture::MiscGLInfo::MiscGLInfo() throw() mIsTransparent = -1; shaderspeed = 1.f; shaderindex = 0; + Glossiness = 0.0f; + SpecularLevel = 0.0f; Material[1] = Material[0] = NULL; SystemTexture[1] = SystemTexture[0] = NULL; @@ -598,6 +600,18 @@ void gl_ParseMaterial(FScanner &sc, int deflump) // only affects textures defined in the IWAD. iwad = true; } + else if (sc.Compare("glossiness")) + { + sc.MustGetFloat(); + if (tex) + tex->gl_info.Glossiness = sc.Float; + } + else if (sc.Compare("specularlevel")) + { + sc.MustGetFloat(); + if (tex) + tex->gl_info.SpecularLevel = sc.Float; + } else { for (int i = 0; keywords[i] != nullptr; i++) diff --git a/src/textures/textures.h b/src/textures/textures.h index 72501e492..c80abf87b 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -372,6 +372,8 @@ public: FTexture *Metallic; // Metalness texture for the physically based rendering (PBR) light model FTexture *Roughness; // Roughness texture for PBR FTexture *AmbientOcclusion; // Ambient occlusion texture for PBR + float Glossiness; + float SpecularLevel; PalEntry GlowColor; int GlowHeight; FloatRect *areas; diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 6bc9f7a90..d1ae8f50f 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -369,7 +369,7 @@ vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); #if defined(SPECULAR) - float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, 100.0, 200.0); + float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelnormal, uSpecularMaterial.x, uSpecularMaterial.y); return vec2(diffuseAmount, specularAmount) * attenuation; #else return vec2(attenuation * diffuseAmount, 0.0); diff --git a/wadsrc/static/shaders/glsl/shaderdefs.i b/wadsrc/static/shaders/glsl/shaderdefs.i index 15d68428e..6836135d3 100644 --- a/wadsrc/static/shaders/glsl/shaderdefs.i +++ b/wadsrc/static/shaders/glsl/shaderdefs.i @@ -51,6 +51,9 @@ uniform int uLightIndex; // Software fuzz scaling uniform int uViewHeight; +// Blinn glossiness and specular level +uniform vec2 uSpecularMaterial; + // quad drawer stuff #ifdef USE_QUAD_DRAWER uniform mat4 uQuadVertices; From 2c9a2e7170828ac4d82b81deda0fd106b362b1cf Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 25 Jan 2018 19:59:57 +0100 Subject: [PATCH 08/23] - fix specular defaults to be a little more sane --- src/gl/textures/gl_texture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index 6501d9709..7e39fd9f8 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -191,8 +191,8 @@ FTexture::MiscGLInfo::MiscGLInfo() throw() mIsTransparent = -1; shaderspeed = 1.f; shaderindex = 0; - Glossiness = 0.0f; - SpecularLevel = 0.0f; + Glossiness = 10.0f; + SpecularLevel = 0.1f; Material[1] = Material[0] = NULL; SystemTexture[1] = SystemTexture[0] = NULL; From 30af6d38b35f29c85349df89baf9f6ed73e735ab Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 25 Jan 2018 20:22:51 +0100 Subject: [PATCH 09/23] - fix automap render bug --- src/gl/renderer/gl_renderstate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 499303cab..593b7490e 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -139,7 +139,7 @@ bool FRenderState::ApplyShader() } else { - activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f, mPassType); + activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, mPassType); activeShader->Bind(); } From a6da1d356aa96cb5fc7beaf8c107c7e511c0d0aa Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 27 Jan 2018 00:22:15 +0100 Subject: [PATCH 10/23] - add PBR materials to main.fp --- wadsrc/static/shaders/glsl/main.fp | 156 +++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index d1ae8f50f..d7c06eb1c 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -384,6 +384,158 @@ float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); } +#if defined(PBR) + +const float PI = 3.14159265359; + +float DistributionGGX(vec3 N, vec3 H, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float nom = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return nom / denom; +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r * r) / 8.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} + +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + return ggx1 * ggx2; +} + +vec3 fresnelSchlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} + +vec3 applyLight(vec3 albedo, vec3 ambientLight) +{ + vec3 worldpos = pixelpos.xyz; + + albedo = pow(albedo, vec3(2.2)); // sRGB to linear + ambientLight = pow(ambientLight, vec3(2.2)); + + vec3 normal = ApplyNormalMap(); + float metallic = texture(metallictexture, vTexCoord.st).r; + float roughness = texture(roughnesstexture, vTexCoord.st).r; + float ao = texture(aotexture, vTexCoord.st).r; + + vec3 N = normalize(normal); + vec3 V = normalize(uCameraPos.xyz - worldpos); + + vec3 F0 = mix(vec3(0.04), albedo, metallic); + + vec3 Lo = uDynLightColor.rgb; + +#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS + if (uLightIndex >= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.z > lightRange.x) + { + // + // modulated lights + // + for(int i=lightRange.x; i Date: Sat, 27 Jan 2018 00:42:17 +0100 Subject: [PATCH 11/23] - disable the tonemapping to let it bloom instead --- wadsrc/static/shaders/glsl/main.fp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index d7c06eb1c..21609f5f7 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -530,7 +530,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 color = ambient + Lo; // Tonemap (reinhard) and apply sRGB gamma - color = color / (color + vec3(1.0)); + //color = color / (color + vec3(1.0)); return pow(color, vec3(1.0 / 2.2)); } From 747ef8324e0468f7747a889b2021571b2ed8ff10 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 29 Jan 2018 19:09:24 +0100 Subject: [PATCH 12/23] - Improve sector light slightly for PBR --- wadsrc/static/shaders/glsl/main.fp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 21609f5f7..d02ecd317 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -427,6 +427,11 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0) return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } +vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) +{ + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); +} + vec3 applyLight(vec3 albedo, vec3 ambientLight) { vec3 worldpos = pixelpos.xyz; @@ -526,7 +531,25 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) } #endif - vec3 ambient = ambientLight * albedo * ao; + // Pretend we sampled the sector light level from an irradiance map + + vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); + + vec3 kS = F; + vec3 kD = 1.0 - kS; + + vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb + vec3 diffuse = irradiance * albedo; + + //kD *= 1.0 - metallic; + //const float MAX_REFLECTION_LOD = 4.0; + //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + //vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; + //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + + //vec3 ambient = (kD * diffuse + specular) * ao; + vec3 ambient = (kD * diffuse) * ao; + vec3 color = ambient + Lo; // Tonemap (reinhard) and apply sRGB gamma From 7b9a334f776a70224421849fd1833cf7411099c7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Feb 2018 13:17:09 +0100 Subject: [PATCH 13/23] - Change PBR materials to use quadratic light falloff --- wadsrc/static/shaders/glsl/main.fp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index d02ecd317..9bd1b39a4 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -432,6 +432,31 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); } +float pointLightAttenuationQuadratic(vec4 lightpos, float lightcolorA) +{ + float strength = (1.0 + lightpos.w * lightpos.w * 0.25) * 0.5; + + vec3 distVec = lightpos.xyz - pixelpos.xyz; + float attenuation = strength / (1.0 + dot(distVec, distVec)); + if (attenuation <= 1.0 / 256.0) return 0.0; + +#ifdef SUPPORTS_SHADOWMAPS + float shadowIndex = abs(lightcolorA) - 1.0; + attenuation *= shadowmapAttenuation(lightpos, shadowIndex); +#endif + + if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag + { + return attenuation; + } + else + { + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + vec3 pixelnormal = ApplyNormalMap(); + return attenuation * diffuseContribution(lightDirection, pixelnormal); + } +} + vec3 applyLight(vec3 albedo, vec3 ambientLight) { vec3 worldpos = pixelpos.xyz; @@ -471,7 +496,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 H = normalize(V + L); //float distance = length(lightpos.xyz - worldpos); //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuation(lightpos, lightcolor.a).x; + float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); @@ -506,7 +531,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 H = normalize(V + L); //float distance = length(lightpos.xyz - worldpos); //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuation(lightpos, lightcolor.a).x; + float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); From 769867475cd198aebc56e77ce403430f30c298aa Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Feb 2018 23:56:55 +0100 Subject: [PATCH 14/23] - Replaced max(dot(a,b), 0.0) with clamp as some rounding errors caused pow to receive negative values when then value was subtracted from 1.0 (undefined glsl behavior) - Fixed that surface angle attenuation was getting applied twice --- wadsrc/static/shaders/glsl/main.fp | 99 ++++++++++++++++-------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 9bd1b39a4..a768d1244 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -432,7 +432,7 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); } -float pointLightAttenuationQuadratic(vec4 lightpos, float lightcolorA) +float quadraticDistanceAttenuation(vec4 lightpos) { float strength = (1.0 + lightpos.w * lightpos.w * 0.25) * 0.5; @@ -440,21 +440,17 @@ float pointLightAttenuationQuadratic(vec4 lightpos, float lightcolorA) float attenuation = strength / (1.0 + dot(distVec, distVec)); if (attenuation <= 1.0 / 256.0) return 0.0; + return attenuation; +} + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ #ifdef SUPPORTS_SHADOWMAPS float shadowIndex = abs(lightcolorA) - 1.0; - attenuation *= shadowmapAttenuation(lightpos, shadowIndex); + return shadowmapAttenuation(lightpos, shadowIndex); +#else + return 1.0; #endif - - if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag - { - return attenuation; - } - else - { - vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); - vec3 pixelnormal = ApplyNormalMap(); - return attenuation * diffuseContribution(lightDirection, pixelnormal); - } } vec3 applyLight(vec3 albedo, vec3 ambientLight) @@ -464,12 +460,11 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) albedo = pow(albedo, vec3(2.2)); // sRGB to linear ambientLight = pow(ambientLight, vec3(2.2)); - vec3 normal = ApplyNormalMap(); float metallic = texture(metallictexture, vTexCoord.st).r; float roughness = texture(roughnesstexture, vTexCoord.st).r; float ao = texture(aotexture, vTexCoord.st).r; - vec3 N = normalize(normal); + vec3 N = ApplyNormalMap(); vec3 V = normalize(uCameraPos.xyz - worldpos); vec3 F0 = mix(vec3(0.04), albedo, metallic); @@ -494,28 +489,33 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - //float distance = length(lightpos.xyz - worldpos); - //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); + + float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + if (lightcolor.a < 0.0) + attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag - vec3 radiance = lightcolor.rgb * attenuation; + if (attenuation > 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); + vec3 radiance = lightcolor.rgb * attenuation; - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - vec3 nominator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - vec3 specular = nominator / max(denominator, 0.001); + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo += (kD * albedo / PI + specular) * radiance; + } } // // subtractive lights @@ -529,28 +529,33 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - //float distance = length(lightpos.xyz - worldpos); - //float attenuation = 1.0 / (distance * distance); - float attenuation = pointLightAttenuationQuadratic(lightpos, lightcolor.a); + + float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + if (lightcolor.a < 0.0) + attenuation *= clamp(dot(N, L), 0.0, 1.0); // Sign bit is the attenuated light flag - vec3 radiance = lightcolor.rgb * attenuation; + if (attenuation > 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); + vec3 radiance = lightcolor.rgb * attenuation; - vec3 kS = F; - vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0); - vec3 nominator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - vec3 specular = nominator / max(denominator, 0.001); + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); - float NdotL = max(dot(N, L), 0.0); - Lo -= (kD * albedo / PI + specular) * radiance * NdotL; + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo -= (kD * albedo / PI + specular) * radiance; + } } } } @@ -558,7 +563,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) // Pretend we sampled the sector light level from an irradiance map - vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); + vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); vec3 kS = F; vec3 kD = 1.0 - kS; @@ -569,7 +574,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) //kD *= 1.0 - metallic; //const float MAX_REFLECTION_LOD = 4.0; //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - //vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; + //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); //vec3 ambient = (kD * diffuse + specular) * ao; From 3207d8aef79c1730eef7e04ee586a63304221056 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Feb 2018 23:29:31 +0100 Subject: [PATCH 15/23] - generate uniform declarations from c++ --- src/gl/shaders/gl_shader.cpp | 116 +++++++++++++++++- wadsrc/static/shaders/glsl/burn.fp | 3 +- wadsrc/static/shaders/glsl/func_brightmap.fp | 10 -- wadsrc/static/shaders/glsl/func_warp1.fp | 1 - wadsrc/static/shaders/glsl/func_warp2.fp | 1 - wadsrc/static/shaders/glsl/func_warp3.fp | 1 - wadsrc/static/shaders/glsl/func_wavex.fp | 1 - wadsrc/static/shaders/glsl/fuzz_jagged.fp | 1 - wadsrc/static/shaders/glsl/fuzz_noise.fp | 1 - wadsrc/static/shaders/glsl/fuzz_smooth.fp | 1 - .../static/shaders/glsl/fuzz_smoothnoise.fp | 1 - .../shaders/glsl/fuzz_smoothtranslucent.fp | 1 - wadsrc/static/shaders/glsl/fuzz_software.fp | 1 - wadsrc/static/shaders/glsl/fuzz_standard.fp | 1 - wadsrc/static/shaders/glsl/fuzz_swirly.fp | 1 - wadsrc/static/shaders/glsl/main.fp | 32 ----- wadsrc/static/shaders/glsl/shaderdefs.i | 71 ----------- 17 files changed, 113 insertions(+), 131 deletions(-) delete mode 100644 wadsrc/static/shaders/glsl/shaderdefs.i diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index bcaea9bb4..b535b606c 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -63,9 +63,117 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * static char buffer[10000]; FString error; - int i_lump = Wads.CheckNumForFullName("shaders/glsl/shaderdefs.i", 0); - if (i_lump == -1) I_Error("Unable to load 'shaders/glsl/shaderdefs.i'"); - FMemLump i_data = Wads.ReadLump(i_lump); + FString i_data; + + // these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. + i_data += "precision highp int;\n"; + i_data += "precision highp float;\n"; + + i_data += "uniform vec4 uCameraPos;\n"; + i_data += "uniform int uTextureMode;\n"; + i_data += "uniform float uClipHeight;\n"; + i_data += "uniform float uClipHeightDirection;\n"; + i_data += "uniform vec2 uClipSplit;\n"; + i_data += "uniform vec4 uClipLine;\n"; + i_data += "uniform float uAlphaThreshold;\n"; + + // colors + i_data += "uniform vec4 uObjectColor;\n"; + i_data += "uniform vec4 uObjectColor2;\n"; + i_data += "uniform vec4 uDynLightColor;\n"; + i_data += "uniform vec4 uFogColor;\n"; + i_data += "uniform float uDesaturationFactor;\n"; + i_data += "uniform float uInterpolationFactor;\n"; + + // Fixed colormap stuff + i_data += "uniform int uFixedColormap;\n"; // 0, when no fixed colormap, 1 for a light value, 2 for a color blend, 3 for a fog layer + i_data += "uniform vec4 uFixedColormapStart;\n"; + i_data += "uniform vec4 uFixedColormapRange;\n"; + + // Glowing walls stuff + i_data += "uniform vec4 uGlowTopPlane;\n"; + i_data += "uniform vec4 uGlowTopColor;\n"; + i_data += "uniform vec4 uGlowBottomPlane;\n"; + i_data += "uniform vec4 uGlowBottomColor;\n"; + + i_data += "uniform vec4 uSplitTopPlane;\n"; + i_data += "uniform vec4 uSplitBottomPlane;\n"; + + // Lighting + Fog + i_data += "uniform vec4 uLightAttr;\n"; + i_data += "#define uLightLevel uLightAttr.a\n"; + i_data += "#define uFogDensity uLightAttr.b\n"; + i_data += "#define uLightFactor uLightAttr.g\n"; + i_data += "#define uLightDist uLightAttr.r\n"; + i_data += "uniform int uFogEnabled;\n"; + i_data += "uniform int uPalLightLevels;\n"; + i_data += "uniform float uGlobVis;\n"; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 + + // dynamic lights + i_data += "uniform int uLightIndex;\n"; + + // Software fuzz scaling + i_data += "uniform int uViewHeight;\n"; + + // Blinn glossiness and specular level + i_data += "uniform vec2 uSpecularMaterial;\n"; + + // quad drawer stuff + i_data += "#ifdef USE_QUAD_DRAWER\n"; + i_data += "uniform mat4 uQuadVertices;\n"; + i_data += "uniform mat4 uQuadTexCoords;\n"; + i_data += "uniform int uQuadMode;\n"; + i_data += "#endif\n"; + + // matrices + i_data += "uniform mat4 ProjectionMatrix;\n"; + i_data += "uniform mat4 ViewMatrix;\n"; + i_data += "uniform mat4 ModelMatrix;\n"; + i_data += "uniform mat4 NormalViewMatrix;\n"; + i_data += "uniform mat4 NormalModelMatrix;\n"; + i_data += "uniform mat4 TextureMatrix;\n"; + + // light buffers + i_data += "#ifdef SHADER_STORAGE_LIGHTS\n"; + i_data += "layout(std430, binding = 1) buffer LightBufferSSO\n"; + i_data += "{\n"; + i_data += " vec4 lights[];\n"; + i_data += "};\n"; + i_data += "#elif defined NUM_UBO_LIGHTS\n"; + i_data += "uniform LightBufferUBO\n"; + i_data += "{\n"; + i_data += " vec4 lights[NUM_UBO_LIGHTS];\n"; + i_data += "};\n"; + i_data += "#endif\n"; + + // textures + i_data += "uniform sampler2D tex;\n"; + i_data += "uniform sampler2D ShadowMap;\n"; + i_data += "uniform sampler2D texture2;\n"; + i_data += "uniform sampler2D texture3;\n"; + i_data += "uniform sampler2D texture4;\n"; + i_data += "uniform sampler2D texture5;\n"; + i_data += "uniform sampler2D texture6;\n"; + + // timer data + i_data += "uniform float timer;\n"; // To do: we must search user shaders for this declaration and remove it + + // material types + i_data += "#if defined(SPECULAR)\n"; + i_data += "#define normaltexture texture2\n"; + i_data += "#define speculartexture texture3\n"; + i_data += "#define brighttexture texture4\n"; + i_data += "#elif defined(PBR)\n"; + i_data += "#define normaltexture texture2\n"; + i_data += "#define metallictexture texture3\n"; + i_data += "#define roughnesstexture texture4\n"; + i_data += "#define aotexture texture5\n"; + i_data += "#define brighttexture texture6\n"; + i_data += "#else\n"; + i_data += "#define brighttexture texture2\n"; + i_data += "#endif\n"; + + i_data += "#line 1\n"; int vp_lump = Wads.CheckNumForFullName(vert_prog_lump, 0); if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump); @@ -120,7 +228,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * vp_comb << "#define SUPPORTS_SHADOWMAPS\n"; } - vp_comb << defines << i_data.GetString().GetChars(); + vp_comb << defines << i_data.GetChars(); FString fp_comb = vp_comb; vp_comb << vp_data.GetString().GetChars() << "\n"; diff --git a/wadsrc/static/shaders/glsl/burn.fp b/wadsrc/static/shaders/glsl/burn.fp index f928fd8db..d3f6f20e9 100644 --- a/wadsrc/static/shaders/glsl/burn.fp +++ b/wadsrc/static/shaders/glsl/burn.fp @@ -1,5 +1,4 @@ -uniform sampler2D tex; -uniform sampler2D texture2; + in vec4 vTexCoord; in vec4 vColor; out vec4 FragColor; diff --git a/wadsrc/static/shaders/glsl/func_brightmap.fp b/wadsrc/static/shaders/glsl/func_brightmap.fp index 00760bd62..7f92d36e5 100644 --- a/wadsrc/static/shaders/glsl/func_brightmap.fp +++ b/wadsrc/static/shaders/glsl/func_brightmap.fp @@ -1,13 +1,3 @@ -#if defined(SPECULAR) -uniform sampler2D texture4; -#define brighttexture texture4 -#elif defined(PBR) -uniform sampler2D texture6; -#define brighttexture texture6 -#else -uniform sampler2D texture2; -#define brighttexture texture2 -#endif vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/func_warp1.fp b/wadsrc/static/shaders/glsl/func_warp1.fp index 891eaa936..4214f771f 100644 --- a/wadsrc/static/shaders/glsl/func_warp1.fp +++ b/wadsrc/static/shaders/glsl/func_warp1.fp @@ -1,4 +1,3 @@ -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/func_warp2.fp b/wadsrc/static/shaders/glsl/func_warp2.fp index ee712593d..389fad9df 100644 --- a/wadsrc/static/shaders/glsl/func_warp2.fp +++ b/wadsrc/static/shaders/glsl/func_warp2.fp @@ -1,4 +1,3 @@ -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/func_warp3.fp b/wadsrc/static/shaders/glsl/func_warp3.fp index a81969ca6..dceca2477 100644 --- a/wadsrc/static/shaders/glsl/func_warp3.fp +++ b/wadsrc/static/shaders/glsl/func_warp3.fp @@ -1,4 +1,3 @@ -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/func_wavex.fp b/wadsrc/static/shaders/glsl/func_wavex.fp index e4230ae87..05ab53028 100644 --- a/wadsrc/static/shaders/glsl/func_wavex.fp +++ b/wadsrc/static/shaders/glsl/func_wavex.fp @@ -1,4 +1,3 @@ -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_jagged.fp b/wadsrc/static/shaders/glsl/fuzz_jagged.fp index c088c7b30..083c22068 100644 --- a/wadsrc/static/shaders/glsl/fuzz_jagged.fp +++ b/wadsrc/static/shaders/glsl/fuzz_jagged.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_noise.fp b/wadsrc/static/shaders/glsl/fuzz_noise.fp index 75afc251f..6d1c0094c 100644 --- a/wadsrc/static/shaders/glsl/fuzz_noise.fp +++ b/wadsrc/static/shaders/glsl/fuzz_noise.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_smooth.fp b/wadsrc/static/shaders/glsl/fuzz_smooth.fp index 4261d5415..3c642c399 100644 --- a/wadsrc/static/shaders/glsl/fuzz_smooth.fp +++ b/wadsrc/static/shaders/glsl/fuzz_smooth.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp b/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp index bfe04ec16..d446a3d0a 100644 --- a/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp +++ b/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp b/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp index 75bee0330..1b727a1bc 100644 --- a/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp +++ b/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_software.fp b/wadsrc/static/shaders/glsl/fuzz_software.fp index cf905bb6e..4fe4ab669 100644 --- a/wadsrc/static/shaders/glsl/fuzz_software.fp +++ b/wadsrc/static/shaders/glsl/fuzz_software.fp @@ -1,5 +1,4 @@ // Fuzz effect as rendered by the software renderer -uniform float timer; #define FUZZTABLE 50 #define FUZZ_RANDOM_X_SIZE 100 diff --git a/wadsrc/static/shaders/glsl/fuzz_standard.fp b/wadsrc/static/shaders/glsl/fuzz_standard.fp index b467f64b2..3eb3b67e6 100644 --- a/wadsrc/static/shaders/glsl/fuzz_standard.fp +++ b/wadsrc/static/shaders/glsl/fuzz_standard.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/fuzz_swirly.fp b/wadsrc/static/shaders/glsl/fuzz_swirly.fp index 86a66ac8e..266858999 100644 --- a/wadsrc/static/shaders/glsl/fuzz_swirly.fp +++ b/wadsrc/static/shaders/glsl/fuzz_swirly.fp @@ -1,5 +1,4 @@ //created by Evil Space Tomato -uniform float timer; vec4 ProcessTexel() { diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index a768d1244..b868f86c3 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -12,38 +12,6 @@ out vec4 FragFog; out vec4 FragNormal; #endif -#ifdef SHADER_STORAGE_LIGHTS - layout(std430, binding = 1) buffer LightBufferSSO - { - vec4 lights[]; - }; -#elif defined NUM_UBO_LIGHTS - /*layout(std140)*/ uniform LightBufferUBO - { - vec4 lights[NUM_UBO_LIGHTS]; - }; -#endif - - -uniform sampler2D tex; -uniform sampler2D ShadowMap; - -#if defined(SPECULAR) -uniform sampler2D texture2; -uniform sampler2D texture3; -#define normaltexture texture2 -#define speculartexture texture3 -#elif defined(PBR) -uniform sampler2D texture2; -uniform sampler2D texture3; -uniform sampler2D texture4; -uniform sampler2D texture5; -#define normaltexture texture2 -#define metallictexture texture3 -#define roughnesstexture texture4 -#define aotexture texture5 -#endif - vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); diff --git a/wadsrc/static/shaders/glsl/shaderdefs.i b/wadsrc/static/shaders/glsl/shaderdefs.i deleted file mode 100644 index 6836135d3..000000000 --- a/wadsrc/static/shaders/glsl/shaderdefs.i +++ /dev/null @@ -1,71 +0,0 @@ -// This file contains common data definitions for both vertex and fragment shader - -// these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. -precision highp int; -precision highp float; - -uniform vec4 uCameraPos; -uniform int uTextureMode; -uniform float uClipHeight, uClipHeightDirection; -uniform vec2 uClipSplit; -uniform vec4 uClipLine; - -uniform float uAlphaThreshold; - - -// colors -uniform vec4 uObjectColor; -uniform vec4 uObjectColor2; -uniform vec4 uDynLightColor; -uniform vec4 uFogColor; -uniform float uDesaturationFactor; -uniform float uInterpolationFactor; - -// Fixed colormap stuff -uniform int uFixedColormap; // 0, when no fixed colormap, 1 for a light value, 2 for a color blend, 3 for a fog layer -uniform vec4 uFixedColormapStart; -uniform vec4 uFixedColormapRange; - -// Glowing walls stuff -uniform vec4 uGlowTopPlane; -uniform vec4 uGlowTopColor; -uniform vec4 uGlowBottomPlane; -uniform vec4 uGlowBottomColor; - -uniform vec4 uSplitTopPlane; -uniform vec4 uSplitBottomPlane; - -// Lighting + Fog -uniform vec4 uLightAttr; -#define uLightLevel uLightAttr.a -#define uFogDensity uLightAttr.b -#define uLightFactor uLightAttr.g -#define uLightDist uLightAttr.r -uniform int uFogEnabled; -uniform int uPalLightLevels; -uniform float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 - -// dynamic lights -uniform int uLightIndex; - -// Software fuzz scaling -uniform int uViewHeight; - -// Blinn glossiness and specular level -uniform vec2 uSpecularMaterial; - -// quad drawer stuff -#ifdef USE_QUAD_DRAWER -uniform mat4 uQuadVertices; -uniform mat4 uQuadTexCoords; -uniform int uQuadMode; -#endif - -// matrices -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrix; -uniform mat4 ModelMatrix; -uniform mat4 NormalViewMatrix; -uniform mat4 NormalModelMatrix; -uniform mat4 TextureMatrix; - From f01ef3d7a7a9ae51906bb9abf68088e2f6e051a5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 10 Feb 2018 12:52:59 +0100 Subject: [PATCH 16/23] - Remove uniforms from user shader code --- src/gl/shaders/gl_shader.cpp | 61 ++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index b535b606c..90d906f62 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -52,11 +52,60 @@ #include "gl/textures/gl_material.h" #include "gl/dynlights/gl_lightbuffer.h" -//========================================================================== -// -// -// -//========================================================================== +static bool IsGlslWhitespace(char c) +{ + switch (c) + { + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + return true; + default: + return false; + } +} + +static FString RemoveLegacyUserUniforms(FString code) +{ + // User shaders must declare their uniforms via the GLDEFS file. + // The following code searches for uniform declarations in the shader itself and replaces them with whitespace. + + long len = (long)code.Len(); + char *chars = code.LockBuffer(); + + long startIndex = 0; + while (true) + { + long matchIndex = code.IndexOf("uniform", startIndex); + if (matchIndex == -1) + break; + + bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); + bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]); + if (isKeywordStart && isKeywordEnd) + { + long statementEndIndex = code.IndexOf(';', matchIndex + 7); + if (statementEndIndex == -1) + statementEndIndex = len; + for (long i = matchIndex; i < statementEndIndex; i++) + { + if (!IsGlslWhitespace(chars[i])) + chars[i] = ' '; + } + startIndex = statementEndIndex; + } + else + { + startIndex = matchIndex + 7; + } + } + + code.UnlockBuffer(); + + return code; +} bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * defines) { @@ -232,7 +281,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * FString fp_comb = vp_comb; vp_comb << vp_data.GetString().GetChars() << "\n"; - fp_comb << fp_data.GetString().GetChars() << "\n"; + fp_comb << RemoveLegacyUserUniforms(fp_data.GetString()).GetChars() << "\n"; if (proc_prog_lump != NULL) { From 5528d4157b7cddc532f9d2f4b92648be2d63a580 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 10 Feb 2018 14:06:17 +0100 Subject: [PATCH 17/23] - Make uniform removal a little bit more robust by only searching for known legacy uniforms --- src/gl/shaders/gl_shader.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 90d906f62..0dd1c9d2d 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -67,10 +67,26 @@ static bool IsGlslWhitespace(char c) } } +static FString NextGlslToken(const char *chars, long len, long &pos) +{ + // Eat whitespace + long tokenStart = pos; + while (tokenStart != len && IsGlslWhitespace(chars[tokenStart])) + tokenStart++; + + // Find token end + long tokenEnd = tokenStart; + while (tokenEnd != len && !IsGlslWhitespace(chars[tokenEnd]) && chars[tokenEnd] != ';') + tokenEnd++; + + pos = tokenEnd; + return FString(chars + tokenStart, tokenEnd - tokenStart); +} + static FString RemoveLegacyUserUniforms(FString code) { // User shaders must declare their uniforms via the GLDEFS file. - // The following code searches for uniform declarations in the shader itself and replaces them with whitespace. + // The following code searches for legacy uniform declarations in the shader itself and replaces them with whitespace. long len = (long)code.Len(); char *chars = code.LockBuffer(); @@ -82,14 +98,25 @@ static FString RemoveLegacyUserUniforms(FString code) if (matchIndex == -1) break; + bool isLegacyUniformName = false; + bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]); bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]); if (isKeywordStart && isKeywordEnd) + { + long pos = matchIndex + 7; + FString type = NextGlslToken(chars, len, pos); + FString identifier = NextGlslToken(chars, len, pos); + + isLegacyUniformName = type.Compare("float") == 0 && identifier.Compare("timer") == 0; + } + + if (isLegacyUniformName) { long statementEndIndex = code.IndexOf(';', matchIndex + 7); if (statementEndIndex == -1) statementEndIndex = len; - for (long i = matchIndex; i < statementEndIndex; i++) + for (long i = matchIndex; i <= statementEndIndex; i++) { if (!IsGlslWhitespace(chars[i])) chars[i] = ' '; @@ -281,7 +308,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * FString fp_comb = vp_comb; vp_comb << vp_data.GetString().GetChars() << "\n"; - fp_comb << RemoveLegacyUserUniforms(fp_data.GetString()).GetChars() << "\n"; + fp_comb << fp_data.GetString().GetChars() << "\n"; if (proc_prog_lump != NULL) { @@ -298,7 +325,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * fp_comb.Substitute("vec4 frag = ProcessTexel();", "vec4 frag = Process(vec4(1.0));"); } - fp_comb << pp_data.GetString().GetChars(); + fp_comb << RemoveLegacyUserUniforms(pp_data.GetString()).GetChars(); fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders. if (pp_data.GetString().IndexOf("ProcessLight") < 0) From e2cab652d0bb220995e781ae7affbb13c72f6eee Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 10 Feb 2018 14:46:43 +0100 Subject: [PATCH 18/23] - Improve the "#line 1" directive insertion so that errors in all the shaders use line numbers relative to the lump they are referring to --- src/gl/shaders/gl_shader.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 0dd1c9d2d..05ddaa234 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -249,8 +249,6 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "#define brighttexture texture2\n"; i_data += "#endif\n"; - i_data += "#line 1\n"; - int vp_lump = Wads.CheckNumForFullName(vert_prog_lump, 0); if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump); FMemLump vp_data = Wads.ReadLump(vp_lump); @@ -307,11 +305,16 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * vp_comb << defines << i_data.GetChars(); FString fp_comb = vp_comb; + vp_comb << "#line 1\n"; + fp_comb << "#line 1\n"; + vp_comb << vp_data.GetString().GetChars() << "\n"; fp_comb << fp_data.GetString().GetChars() << "\n"; if (proc_prog_lump != NULL) { + fp_comb << "#line 1\n"; + if (*proc_prog_lump != '#') { int pp_lump = Wads.CheckNumForFullName(proc_prog_lump); From eb39e88682e2ef297096d22c9930d1fb2cb76103 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 19 Feb 2018 02:01:33 +0100 Subject: [PATCH 19/23] - clean up the main.fp light handling code so that a single ApplyDynLights function applies all dynamic light --- wadsrc/static/shaders/glsl/main.fp | 375 ++++++++++++++++------------- 1 file changed, 210 insertions(+), 165 deletions(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index b868f86c3..a6c02654d 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -221,39 +221,26 @@ float shadowmapAttenuation(vec4 lightpos, float shadowIndex) #endif } -#endif - -//=========================================================================== -// -// Standard lambertian diffuse light calculation -// -//=========================================================================== - -float diffuseContribution(vec3 lightDirection, vec3 normal) +float shadowAttenuation(vec4 lightpos, float lightcolorA) { - return max(dot(normal, lightDirection), 0.0f); + float shadowIndex = abs(lightcolorA) - 1.0; + return shadowmapAttenuation(lightpos, shadowIndex); } -//=========================================================================== -// -// Blinn specular light calculation -// -//=========================================================================== +#else -float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, vec3 faceNormal, float glossiness, float specularLevel) +float shadowAttenuation(vec4 lightpos, float lightcolorA) { - if (diffuseContribution > 0.0f) - { - vec3 viewDir = normalize(uCameraPos.xyz - pixelpos.xyz); - vec3 halfDir = normalize(lightDirection + viewDir); - float specAngle = max(dot(halfDir, faceNormal), 0.0f); - float phExp = glossiness * 4.0f; - return specularLevel * pow(specAngle, phExp); - } - else - { - return 0.0f; - } + return 1.0; +} + +#endif + +float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) +{ + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float cosDir = dot(lightDirection, spotdir); + return smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir); } //=========================================================================== @@ -262,7 +249,7 @@ float blinnSpecularContribution(float diffuseContribution, vec3 lightDirection, // //=========================================================================== -#if defined(SPECULAR) || defined(PBR) +#if defined(SPECULAR) || defined(PBR) // To do: create define for when normal map is present mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle @@ -313,46 +300,118 @@ vec3 ApplyNormalMap() #endif //=========================================================================== +// Dynamic light material modes begin // -// Calculates the brightness of a dynamic point light -// +// To do: move each of the following #if blocks needs to its own file //=========================================================================== -vec2 pointLightAttenuation(vec4 lightpos, float lightcolorA) +#if !defined(NUM_UBO_LIGHTS) && !defined(SHADER_STORAGE_LIGHTS) // Legacy light mode (no lights[] array) + +vec3 ApplyDynLights(vec3 material, vec3 color) { - float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - if (attenuation == 0.0) return vec2(0.0); -#ifdef SUPPORTS_SHADOWMAPS - float shadowIndex = abs(lightcolorA) - 1.0; - attenuation *= shadowmapAttenuation(lightpos, shadowIndex); -#endif - if (lightcolorA >= 0.0) // Sign bit is the attenuated light flag + return material * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); +} + +#elif defined(SPECULAR) // Specular light mode + +vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) +{ + vec4 lightpos = lights[i]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec2(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + + if (lightcolorA < 0.0) // Sign bit is the attenuated light flag + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + + if (attenuation > 0.0) // Skip shadow map test if possible + attenuation *= shadowAttenuation(lightpos, lightcolorA); + + if (attenuation <= 0.0) + return vec2(0.0); + + float glossiness = uSpecularMaterial.x; + float specularLevel = uSpecularMaterial.y; + + vec3 halfdir = normalize(viewdir + lightdir); + float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); + float phExp = glossiness * 4.0f; + return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); +} + +vec3 ApplyDynLights(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) { - return vec2(attenuation, 0.0); + vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 normal = ApplyNormalMap(); + vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) { ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); @@ -458,7 +506,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); + float attenuation = quadraticDistanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) @@ -498,7 +546,7 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) vec3 L = normalize(lightpos.xyz - worldpos); vec3 H = normalize(V + L); - float attenuation = quadraticDistanceAttenuation(lightpos) * shadowAttenuation(lightpos, lightcolor.a); + float attenuation = quadraticDistanceAttenuation(lightpos); if (lightspot1.w == 1.0) attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); if (lightcolor.a < 0.0) @@ -527,7 +575,6 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) } } } -#endif // Pretend we sampled the sector light level from an irradiance map @@ -555,8 +602,94 @@ vec3 applyLight(vec3 albedo, vec3 ambientLight) return pow(color, vec3(1.0 / 2.2)); } +#else // Normal dynlight mode + +vec3 lightContribution(int i, vec3 normal) +{ + vec4 lightpos = lights[i]; + vec4 lightcolor = lights[i+1]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec3(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag + { + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + } + + if (attenuation > 0.0) // Skip shadow map test if possible + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + return lightcolor.rgb * attenuation; + } + else + { + return vec3(0.0); + } +} + +vec3 ApplyDynLights(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec3 normal = ApplyNormalMap(); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.z > lightRange.x) - { - // - // modulated lights - // - for(int i=lightRange.x; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.w > lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // - // additive lights - these can be done after the alpha test. - // - for(int i=lightRange.z; i Date: Tue, 20 Feb 2018 00:13:05 +0100 Subject: [PATCH 20/23] - move material light modes to their own subshader lumps --- src/gl/shaders/gl_shader.cpp | 68 +-- src/gl/shaders/gl_shader.h | 4 +- wadsrc/static/shaders/glsl/main.fp | 397 +----------------- .../static/shaders/glsl/material_nolight.fp | 5 + wadsrc/static/shaders/glsl/material_normal.fp | 80 ++++ wadsrc/static/shaders/glsl/material_pbr.fp | 189 +++++++++ .../static/shaders/glsl/material_specular.fp | 97 +++++ 7 files changed, 415 insertions(+), 425 deletions(-) create mode 100644 wadsrc/static/shaders/glsl/material_nolight.fp create mode 100644 wadsrc/static/shaders/glsl/material_normal.fp create mode 100644 wadsrc/static/shaders/glsl/material_pbr.fp create mode 100644 wadsrc/static/shaders/glsl/material_specular.fp diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 05ddaa234..141ee333a 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -134,7 +134,7 @@ static FString RemoveLegacyUserUniforms(FString code) return code; } -bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * defines) +bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * light_fragprog, const char * defines) { static char buffer[10000]; FString error; @@ -346,6 +346,14 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * } } + if (light_fragprog) + { + int pp_lump = Wads.CheckNumForFullName(light_fragprog); + if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog); + FMemLump pp_data = Wads.ReadLump(pp_lump); + fp_comb << pp_data.GetString().GetChars() << "\n"; + } + if (gl.flags & RFL_NO_CLIP_PLANES) { // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. @@ -514,7 +522,7 @@ bool FShader::Bind() // //========================================================================== -FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType) +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) { FString defines; defines += shaderdefines; @@ -527,7 +535,7 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP try { shader = new FShader(ShaderName); - if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, defines.GetChars())) + if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars())) { I_FatalError("Unable to load shader %s\n", ShaderName); } @@ -564,30 +572,31 @@ struct FDefaultShader { const char * ShaderName; const char * gettexelfunc; + const char * lightfunc; const char * Defines; }; // Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified. static const FDefaultShader defaultshaders[]= { - {"Default", "shaders/glsl/func_normal.fp", ""}, - {"Warp 1", "shaders/glsl/func_warp1.fp", ""}, - {"Warp 2", "shaders/glsl/func_warp2.fp", ""}, - {"Brightmap","shaders/glsl/func_brightmap.fp", ""}, - {"Specular","shaders/glsl/func_normal.fp", "#define SPECULAR\n"}, - {"SpecularBrightmap","shaders/glsl/func_brightmap.fp", "#define SPECULAR\n"}, - {"PBR","shaders/glsl/func_normal.fp", "#define PBR\n"}, - {"PBRBrightmap","shaders/glsl/func_brightmap.fp", "#define PBR\n"}, - {"No Texture", "shaders/glsl/func_notexture.fp", ""}, - {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", ""}, - {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", ""}, - {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", ""}, - {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", ""}, - {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", ""}, - {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", ""}, - {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", ""}, - {"Software Fuzz", "shaders/glsl/fuzz_software.fp", ""}, - {NULL,NULL,NULL} + {"Default", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 1", "shaders/glsl/func_warp1.fp", "shaders/glsl/material_normal.fp", ""}, + {"Warp 2", "shaders/glsl/func_warp2.fp", "shaders/glsl/material_normal.fp", ""}, + {"Brightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_normal.fp", ""}, + {"Specular", "shaders/glsl/func_normal.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, + {"SpecularBrightmap", "shaders/glsl/func_brightmap.fp", "shaders/glsl/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"}, + {"PBR","shaders/glsl/func_normal.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, + {"PBRBrightmap","shaders/glsl/func_brightmap.fp", "shaders/glsl/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"}, + {"No Texture", "shaders/glsl/func_notexture.fp", "shaders/glsl/material_normal.fp", ""}, + {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp", "shaders/glsl/material_normal.fp", ""}, + {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp", "shaders/glsl/material_normal.fp", ""}, + {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp", "shaders/glsl/material_normal.fp", ""}, + {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp", "shaders/glsl/material_normal.fp", ""}, + {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp", "shaders/glsl/material_normal.fp", ""}, + {"Software Fuzz", "shaders/glsl/fuzz_software.fp", "shaders/glsl/material_normal.fp", ""}, + {nullptr,nullptr,nullptr,nullptr} }; static TArray usershaders; @@ -598,15 +607,16 @@ struct FEffectShader const char *vp; const char *fp1; const char *fp2; + const char *fp3; const char *defines; }; static const FEffectShader effectshaders[]= { - { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", NULL, "#define NO_ALPHATEST\n" }, - { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, - { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" }, - { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", nullptr, nullptr, "#define NO_ALPHATEST\n" }, + { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, + { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, }; FShaderManager::FShaderManager() @@ -726,11 +736,11 @@ void FShaderCollection::CompileShaders(EPassType passType) for(int i=0;defaultshaders[i].ShaderName != NULL;i++) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, true, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType); mMaterialShaders.Push(shc); if (i < SHADER_NoTexture) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].Defines, false, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType); mMaterialShadersNAT.Push(shc); } } @@ -740,7 +750,7 @@ void FShaderCollection::CompileShaders(EPassType passType) FString name = ExtractFileBase(usershaders[i]); FName sfn = name; - FShader *shc = Compile(sfn, usershaders[i], "", true, passType); + FShader *shc = Compile(sfn, usershaders[i], "shaders/glsl/material_normal.fp", "", true, passType); mMaterialShaders.Push(shc); } @@ -748,7 +758,7 @@ void FShaderCollection::CompileShaders(EPassType passType) { FShader *eff = new FShader(effectshaders[i].ShaderName); if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, - effectshaders[i].fp2, effectshaders[i].defines)) + effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines)) { delete eff; } diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 8041f4880..8b119aec9 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -317,7 +317,7 @@ public: ~FShader(); - bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char *defines); + bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char * light_fragprog, const char *defines); void SetColormapColor(float r, float g, float b, float r1, float g1, float b1); void SetGlowParams(float *topcolors, float topheight, float *bottomcolors, float bottomheight); @@ -367,7 +367,7 @@ class FShaderCollection public: FShaderCollection(EPassType passType); ~FShaderCollection(); - FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *shaderdefines, bool usediscard, EPassType passType); + FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); FShader *BindEffect(int effect); void ApplyMatrices(VSMatrix *proj, VSMatrix *view); diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index a6c02654d..444a9811f 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -15,7 +15,7 @@ out vec4 FragNormal; vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); - +vec3 ProcessMaterial(vec3 material, vec3 color); //=========================================================================== // @@ -249,7 +249,7 @@ float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle // //=========================================================================== -#if defined(SPECULAR) || defined(PBR) // To do: create define for when normal map is present +#if defined(NORMALMAP) mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle @@ -299,397 +299,6 @@ vec3 ApplyNormalMap() } #endif -//=========================================================================== -// Dynamic light material modes begin -// -// To do: move each of the following #if blocks needs to its own file -//=========================================================================== - -#if !defined(NUM_UBO_LIGHTS) && !defined(SHADER_STORAGE_LIGHTS) // Legacy light mode (no lights[] array) - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - return material * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4); -} - -#elif defined(SPECULAR) // Specular light mode - -vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) -{ - vec4 lightpos = lights[i]; - vec4 lightspot1 = lights[i+2]; - vec4 lightspot2 = lights[i+3]; - - float lightdistance = distance(lightpos.xyz, pixelpos.xyz); - if (lightpos.w < lightdistance) - return vec2(0.0); // Early out lights touching surface but not this fragment - - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); - - if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - - vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); - - if (lightcolorA < 0.0) // Sign bit is the attenuated light flag - attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); - - if (attenuation > 0.0) // Skip shadow map test if possible - attenuation *= shadowAttenuation(lightpos, lightcolorA); - - if (attenuation <= 0.0) - return vec2(0.0); - - float glossiness = uSpecularMaterial.x; - float specularLevel = uSpecularMaterial.y; - - vec3 halfdir = normalize(viewdir + lightdir); - float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); - float phExp = glossiness * 4.0f; - return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); -} - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - if (uLightIndex >= 0) - { - vec4 dynlight = uDynLightColor; - vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); - - vec3 normal = ApplyNormalMap(); - vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); - - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - - if (lightRange.z > lightRange.x) - { - // modulated lights - for(int i=lightRange.x; i lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // additive lights - for(int i=lightRange.z; i= 0) - { - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - if (lightRange.z > lightRange.x) - { - // - // modulated lights - // - for(int i=lightRange.x; i 0.0) - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - - vec3 radiance = lightcolor.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, 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, L), 0.0, 1.0); - vec3 specular = nominator / max(denominator, 0.001); - - Lo += (kD * albedo / PI + specular) * radiance; - } - } - // - // subtractive lights - // - for(int i=lightRange.y; i 0.0) - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - - vec3 radiance = lightcolor.rgb * attenuation; - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, 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, L), 0.0, 1.0); - vec3 specular = nominator / max(denominator, 0.001); - - Lo -= (kD * albedo / PI + specular) * radiance; - } - } - } - } - - // Pretend we sampled the sector light level from an irradiance map - - vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); - - vec3 kS = F; - vec3 kD = 1.0 - kS; - - vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb - vec3 diffuse = irradiance * albedo; - - //kD *= 1.0 - metallic; - //const float MAX_REFLECTION_LOD = 4.0; - //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; - //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); - - //vec3 ambient = (kD * diffuse + specular) * ao; - vec3 ambient = (kD * diffuse) * ao; - - vec3 color = ambient + Lo; - - // Tonemap (reinhard) and apply sRGB gamma - //color = color / (color + vec3(1.0)); - return pow(color, vec3(1.0 / 2.2)); -} - -#else // Normal dynlight mode - -vec3 lightContribution(int i, vec3 normal) -{ - vec4 lightpos = lights[i]; - vec4 lightcolor = lights[i+1]; - vec4 lightspot1 = lights[i+2]; - vec4 lightspot2 = lights[i+3]; - - float lightdistance = distance(lightpos.xyz, pixelpos.xyz); - if (lightpos.w < lightdistance) - return vec3(0.0); // Early out lights touching surface but not this fragment - - float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); - - if (lightspot1.w == 1.0) - attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); - - if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag - { - vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); - attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); - } - - if (attenuation > 0.0) // Skip shadow map test if possible - { - attenuation *= shadowAttenuation(lightpos, lightcolor.a); - return lightcolor.rgb * attenuation; - } - else - { - return vec3(0.0); - } -} - -vec3 ApplyDynLights(vec3 material, vec3 color) -{ - if (uLightIndex >= 0) - { - vec4 dynlight = uDynLightColor; - vec3 normal = ApplyNormalMap(); - - ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); - - if (lightRange.z > lightRange.x) - { - // modulated lights - for(int i=lightRange.x; i lightRange.z) - { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // additive lights - for(int i=lightRange.z; i 0.0) // Skip shadow map test if possible + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + return lightcolor.rgb * attenuation; + } + else + { + return vec3(0.0); + } +} + +vec3 ProcessMaterial(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec3 normal = ApplyNormalMap(); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i= 0) + { + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + if (lightRange.z > lightRange.x) + { + // + // modulated lights + // + for(int i=lightRange.x; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, 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, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo += (kD * albedo / PI + specular) * radiance; + } + } + // + // subtractive lights + // + for(int i=lightRange.y; i 0.0) + { + attenuation *= shadowAttenuation(lightpos, lightcolor.a); + + vec3 radiance = lightcolor.rgb * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, 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, L), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + + Lo -= (kD * albedo / PI + specular) * radiance; + } + } + } + } + + // Pretend we sampled the sector light level from an irradiance map + + vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); + + vec3 kS = F; + vec3 kD = 1.0 - kS; + + vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb + vec3 diffuse = irradiance * albedo; + + //kD *= 1.0 - metallic; + //const float MAX_REFLECTION_LOD = 4.0; + //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; + //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + + //vec3 ambient = (kD * diffuse + specular) * ao; + vec3 ambient = (kD * diffuse) * ao; + + vec3 color = ambient + Lo; + + // Tonemap (reinhard) and apply sRGB gamma + //color = color / (color + vec3(1.0)); + return pow(color, vec3(1.0 / 2.2)); +} diff --git a/wadsrc/static/shaders/glsl/material_specular.fp b/wadsrc/static/shaders/glsl/material_specular.fp new file mode 100644 index 000000000..ab61d6cf9 --- /dev/null +++ b/wadsrc/static/shaders/glsl/material_specular.fp @@ -0,0 +1,97 @@ + +vec2 lightAttenuation(int i, vec3 normal, vec3 viewdir, float lightcolorA) +{ + vec4 lightpos = lights[i]; + vec4 lightspot1 = lights[i+2]; + vec4 lightspot2 = lights[i+3]; + + float lightdistance = distance(lightpos.xyz, pixelpos.xyz); + if (lightpos.w < lightdistance) + return vec2(0.0); // Early out lights touching surface but not this fragment + + float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); + + if (lightspot1.w == 1.0) + attenuation *= spotLightAttenuation(lightpos, lightspot1.xyz, lightspot2.x, lightspot2.y); + + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); + + if (lightcolorA < 0.0) // Sign bit is the attenuated light flag + attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + + if (attenuation > 0.0) // Skip shadow map test if possible + attenuation *= shadowAttenuation(lightpos, lightcolorA); + + if (attenuation <= 0.0) + return vec2(0.0); + + float glossiness = uSpecularMaterial.x; + float specularLevel = uSpecularMaterial.y; + + vec3 halfdir = normalize(viewdir + lightdir); + float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f); + float phExp = glossiness * 4.0f; + return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp)); +} + +vec3 ProcessMaterial(vec3 material, vec3 color) +{ + if (uLightIndex >= 0) + { + vec4 dynlight = uDynLightColor; + vec4 specular = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 normal = ApplyNormalMap(); + vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); + + ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i lightRange.z) + { + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // additive lights + for(int i=lightRange.z; i Date: Wed, 21 Feb 2018 23:12:46 +0100 Subject: [PATCH 21/23] - Implement auto textures for materials --- src/gl/data/gl_data.cpp | 4 ++-- src/gl/textures/gl_texture.cpp | 44 ++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/gl/data/gl_data.cpp b/src/gl/data/gl_data.cpp index 42fc6e96d..ca3e25ab9 100644 --- a/src/gl/data/gl_data.cpp +++ b/src/gl/data/gl_data.cpp @@ -68,7 +68,7 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, 0) void gl_CreateSections(); -void AddAutoBrightmaps(); +void AddAutoMaterials(); //----------------------------------------------------------------------------- // @@ -364,7 +364,7 @@ void gl_RecalcVertexHeights(vertex_t * v) void gl_InitData() { AdjustSpriteOffsets(); - AddAutoBrightmaps(); + AddAutoMaterials(); } //========================================================================== diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index 7e39fd9f8..fae65d980 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -763,26 +763,50 @@ void gl_ParseBrightmap(FScanner &sc, int deflump) //========================================================================== // -// +// Search auto paths for extra material textures // //========================================================================== -void AddAutoBrightmaps() +struct AutoTextureSearchPath +{ + const char *path; + ptrdiff_t offset; + + void SetTexture(FTexture *material, FTexture *texture) const + { + *reinterpret_cast(reinterpret_cast(&material->gl_info) + offset) = texture; + } +}; + +static AutoTextureSearchPath autosearchpaths[] = +{ + { "brightmaps/auto/", offsetof(FTexture::MiscGLInfo, Brightmap) }, + { "normalmaps/auto/", offsetof(FTexture::MiscGLInfo, Normal) }, + { "specular/auto/", offsetof(FTexture::MiscGLInfo, Specular) }, + { "metallic/auto/", offsetof(FTexture::MiscGLInfo, Metallic) }, + { "roughness/auto/", offsetof(FTexture::MiscGLInfo, Roughness) }, + { "ao/auto/", offsetof(FTexture::MiscGLInfo, AmbientOcclusion) } +}; + +void AddAutoMaterials() { int num = Wads.GetNumLumps(); for (int i = 0; i < num; i++) { const char *name = Wads.GetLumpFullName(i); - if (strstr(name, "brightmaps/auto/") == name) + for (const AutoTextureSearchPath &searchpath : autosearchpaths) { - TArray list; - FString texname = ExtractFileBase(name, false); - TexMan.ListTextures(texname, list); - auto bmtex = TexMan.FindTexture(name, FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny); - for (auto texid : list) + if (strstr(name, searchpath.path) == name) { - bmtex->bMasked = false; - TexMan[texid]->gl_info.Brightmap = bmtex; + TArray list; + FString texname = ExtractFileBase(name, false); + TexMan.ListTextures(texname, list); + auto bmtex = TexMan.FindTexture(name, FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny); + for (auto texid : list) + { + bmtex->bMasked = false; + searchpath.SetTexture(TexMan[texid], bmtex); + } } } } From 57e66555da4216c5029d01cf9bda5e9eff1a049d Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 21 Feb 2018 23:20:31 +0100 Subject: [PATCH 22/23] - Change the search paths for auto folders --- src/gl/textures/gl_texture.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index fae65d980..0d3e84e4b 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -780,12 +780,13 @@ struct AutoTextureSearchPath static AutoTextureSearchPath autosearchpaths[] = { - { "brightmaps/auto/", offsetof(FTexture::MiscGLInfo, Brightmap) }, - { "normalmaps/auto/", offsetof(FTexture::MiscGLInfo, Normal) }, - { "specular/auto/", offsetof(FTexture::MiscGLInfo, Specular) }, - { "metallic/auto/", offsetof(FTexture::MiscGLInfo, Metallic) }, - { "roughness/auto/", offsetof(FTexture::MiscGLInfo, Roughness) }, - { "ao/auto/", offsetof(FTexture::MiscGLInfo, AmbientOcclusion) } + { "brightmaps/auto/", offsetof(FTexture::MiscGLInfo, Brightmap) }, // For backwards compatibility + { "materials/brightmaps/auto/", offsetof(FTexture::MiscGLInfo, Brightmap) }, + { "materials/normalmaps/auto/", offsetof(FTexture::MiscGLInfo, Normal) }, + { "materials/specular/auto/", offsetof(FTexture::MiscGLInfo, Specular) }, + { "materials/metallic/auto/", offsetof(FTexture::MiscGLInfo, Metallic) }, + { "materials/roughness/auto/", offsetof(FTexture::MiscGLInfo, Roughness) }, + { "materials/ao/auto/", offsetof(FTexture::MiscGLInfo, AmbientOcclusion) } }; void AddAutoMaterials() From 48e534bf19eb4adabd00ed853bdde80b53ce078e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 1 Mar 2018 01:27:12 +0100 Subject: [PATCH 23/23] - Add per-pixel model light to the OpenGL 3.3 render path --- src/gl/scene/gl_scene.cpp | 2 ++ src/gl/scene/gl_scenedrawer.h | 4 ++++ src/gl/scene/gl_sprite.cpp | 23 ++++++++++++++++++++-- src/gl/scene/gl_spritelight.cpp | 26 ++++++++++++++++++------ src/gl/scene/gl_wall.h | 4 +++- src/gl/scene/gl_weapon.cpp | 35 ++++++++++++++++++++++++++++++++- 6 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 178b39ff7..060eaf6a3 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -331,6 +331,8 @@ void GLSceneDrawer::RenderScene(int recursion) gl_drawinfo->drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(GLPASS_LIGHTSONLY); gl_drawinfo->drawlists[GLDL_TRANSLUCENTBORDER].Draw(GLPASS_LIGHTSONLY); gl_drawinfo->drawlists[GLDL_TRANSLUCENT].Draw(GLPASS_LIGHTSONLY, true); + gl_drawinfo->drawlists[GLDL_MODELS].Draw(GLPASS_LIGHTSONLY); + SetupWeaponLight(); GLRenderer->mLights->Finish(); } diff --git a/src/gl/scene/gl_scenedrawer.h b/src/gl/scene/gl_scenedrawer.h index 9ade64b73..9ca7132f1 100644 --- a/src/gl/scene/gl_scenedrawer.h +++ b/src/gl/scene/gl_scenedrawer.h @@ -14,6 +14,10 @@ class GLSceneDrawer subsector_t *currentsubsector; // used by the line processing code. sector_t *currentsector; + TMap weapondynlightindex; + + void SetupWeaponLight(); + void RenderMultipassStuff(); void UnclipSubsector(subsector_t *sub); diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 920b4d7d9..af7eec06c 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -82,6 +82,7 @@ EXTERN_CVAR (Bool, r_debug_disable_vis_filter) extern TArray sprites; extern TArray SpriteFrames; extern uint32_t r_renderercaps; +extern int modellightindex; enum HWRenderStyle { @@ -263,7 +264,25 @@ void GLSprite::CalculateVertices(FVector3 *v) void GLSprite::Draw(int pass) { - if (pass == GLPASS_DECALS || pass == GLPASS_LIGHTSONLY) return; + if (pass == GLPASS_DECALS) return; + + if (pass == GLPASS_LIGHTSONLY) + { + if (modelframe) + { + if (RenderStyle.BlendOp != STYLEOP_Shadow) + { + if (gl_lights && GLRenderer->mLightCount && mDrawer->FixedColormap == CM_DEFAULT && !fullbright) + { + if (!particle) + { + dynlightindex = gl_SetDynModelLight(gl_light_sprites ? actor : nullptr, -1); + } + } + } + } + return; + } bool additivefog = false; bool foglayer = false; @@ -336,7 +355,7 @@ void GLSprite::Draw(int pass) if (gl_lights && GLRenderer->mLightCount && mDrawer->FixedColormap == CM_DEFAULT && !fullbright) { if (modelframe && !particle) - gl_SetDynModelLight(gl_light_sprites ? actor : NULL); + gl_SetDynModelLight(gl_light_sprites ? actor : NULL, dynlightindex); else gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL); } diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index 1415ce16c..72f69cb7d 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -198,13 +198,21 @@ void BSPWalkCircle(float x, float y, float radiusSquared, const Callback &callba BSPNodeWalkCircle(level.HeadNode(), x, y, radiusSquared, callback); } -void gl_SetDynModelLight(AActor *self) +int gl_SetDynModelLight(AActor *self, int dynlightindex) { - // Legacy and deferred render paths gets the old flat model light - if (gl.lightmethod != LM_DIRECT) + // For deferred light mode this function gets called twice. First time for list upload, and second for draw. + if (gl.lightmethod == LM_DEFERRED && dynlightindex != -1) + { + gl_RenderState.SetDynLight(0, 0, 0); + modellightindex = dynlightindex; + return dynlightindex; + } + + // Legacy render path gets the old flat model light + if (gl.lightmethod == LM_LEGACY) { gl_SetDynSpriteLight(self, nullptr); - return; + return -1; } modellightdata.Clear(); @@ -249,6 +257,12 @@ void gl_SetDynModelLight(AActor *self) }); } - gl_RenderState.SetDynLight(0, 0, 0); - modellightindex = GLRenderer->mLights->UploadLights(modellightdata); + dynlightindex = GLRenderer->mLights->UploadLights(modellightdata); + + if (gl.lightmethod != LM_DEFERRED) + { + gl_RenderState.SetDynLight(0, 0, 0); + modellightindex = dynlightindex; + } + return dynlightindex; } diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index aa0bbaed4..5d041a55f 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -392,6 +392,8 @@ public: TArray *lightlist; DRotator Angles; + int dynlightindex; + void SplitSprite(sector_t * frontsector, bool translucent); void SetLowerParam(); void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight); @@ -422,6 +424,6 @@ inline float Dist2(float x1,float y1,float x2,float y2) void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec); void gl_SetDynSpriteLight(AActor *actor, particle_t *particle); -void gl_SetDynModelLight(AActor *self); +int gl_SetDynModelLight(AActor *self, int dynlightindex); #endif diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 2061d67f3..421517a26 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -183,6 +183,39 @@ static bool isBright(DPSprite *psp) return false; } +void GLSceneDrawer::SetupWeaponLight() +{ + weapondynlightindex.Clear(); + + AActor *camera = r_viewpoint.camera; + AActor * playermo = players[consoleplayer].camera; + player_t * player = playermo->player; + + // this is the same as in DrawPlayerSprites below + if (!player || + !r_drawplayersprites || + !camera->player || + (player->cheats & CF_CHASECAM) || + (r_deathcamera && camera->health <= 0)) + return; + + for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) + { + if (psp->GetState() != nullptr) + { + // set the lighting parameters + if (gl_lights && GLRenderer->mLightCount && FixedColormap == CM_DEFAULT && gl_light_sprites) + { + FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false) : nullptr; + if (smf) + { + weapondynlightindex[psp] = gl_SetDynModelLight(playermo, -1); + } + } + } + } +} + //========================================================================== // // R_DrawPlayerSprites @@ -422,7 +455,7 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false) : nullptr; if (smf) - gl_SetDynModelLight(playermo); + gl_SetDynModelLight(playermo, weapondynlightindex[psp]); else gl_SetDynSpriteLight(playermo, NULL); }