From 7a3c89de204751a7cf90bfd09cefc9518af4c0e6 Mon Sep 17 00:00:00 2001 From: rt Date: Mon, 26 Jun 2017 10:56:33 +0200 Subject: [PATCH] fix #2855 #5092 #5180 --- .../shaders/GLSL/ShadowGenFragProg.glsl | 19 ++++++-- .../shaders/GLSL/ShadowGenVertProg.glsl | 16 ++++++- rts/Game/UnsyncedGameCommands.cpp | 19 ++++++++ rts/Map/BaseGroundDrawer.h | 3 ++ rts/Map/SMF/SMFGroundDrawer.cpp | 10 ++--- rts/Rendering/Shaders/ShaderHandler.cpp | 29 ++++++------ rts/Rendering/ShadowHandler.cpp | 32 +++++++++----- rts/Rendering/UnitDrawer.cpp | 44 +++++++++++++------ 8 files changed, 121 insertions(+), 51 deletions(-) diff --git a/cont/base/springcontent/shaders/GLSL/ShadowGenFragProg.glsl b/cont/base/springcontent/shaders/GLSL/ShadowGenFragProg.glsl index e4672920dd9..d245a7ec1e8 100644 --- a/cont/base/springcontent/shaders/GLSL/ShadowGenFragProg.glsl +++ b/cont/base/springcontent/shaders/GLSL/ShadowGenFragProg.glsl @@ -1,12 +1,25 @@ uniform sampler2D alphaMaskTex; -varying vec4 vertexShadowClipPos; +uniform vec4 shadowParams; +uniform vec2 alphaParams; + +varying mat4 shadowViewMat; +varying mat4 shadowProjMat; +varying vec4 vertexModelPos; + void main() { - if (texture2D(alphaMaskTex, gl_TexCoord[0].st).a <= 0.5) + if (texture2D(alphaMaskTex, gl_TexCoord[0].st).a <= alphaParams.x) discard; - #if 0 + #if 1 + // note: voids the glPolygonOffset calls + vec4 vertexShadowPos = shadowViewMat * vertexModelPos; + vertexShadowPos.xy *= (inversesqrt(abs(vertexShadowPos.xy) + shadowParams.zz) + shadowParams.ww); + vertexShadowPos.xy += shadowParams.xy; + vertexShadowPos.z += 0.00250; + vec4 vertexShadowClipPos = shadowProjMat * vertexShadowPos; + float nearDepth = gl_DepthRange.near; float farDepth = gl_DepthRange.far; float depthRange = gl_DepthRange.diff; // far - near diff --git a/cont/base/springcontent/shaders/GLSL/ShadowGenVertProg.glsl b/cont/base/springcontent/shaders/GLSL/ShadowGenVertProg.glsl index d3d5b73ba55..3346ff5ceb2 100644 --- a/cont/base/springcontent/shaders/GLSL/ShadowGenVertProg.glsl +++ b/cont/base/springcontent/shaders/GLSL/ShadowGenVertProg.glsl @@ -8,7 +8,12 @@ uniform vec3 treeOffset; #define MAX_TREE_HEIGHT 60.0 #endif -varying vec4 vertexShadowClipPos; +#ifdef SHADOWGEN_PROGRAM_MAP +varying mat4 shadowViewMat; +varying mat4 shadowProjMat; +varying vec4 vertexModelPos; +#endif + void main() { #ifdef SHADOWGEN_PROGRAM_TREE_NEAR @@ -17,12 +22,19 @@ void main() { vec3 offsetVec = vec3(0.0, 0.0, 0.0); #endif + + #ifdef SHADOWGEN_PROGRAM_MAP + shadowViewMat = gl_ModelViewMatrix; + shadowProjMat = gl_ProjectionMatrix; + vertexModelPos = gl_Vertex + vec4(offsetVec, 0.0); + #endif + vec4 vertexPos = gl_Vertex + vec4(offsetVec, 0.0); vec4 vertexShadowPos = gl_ModelViewMatrix * vertexPos; vertexShadowPos.xy *= (inversesqrt(abs(vertexShadowPos.xy) + shadowParams.zz) + shadowParams.ww); vertexShadowPos.xy += shadowParams.xy; - gl_Position = vertexShadowClipPos = gl_ProjectionMatrix * vertexShadowPos; + gl_Position = gl_ProjectionMatrix * vertexShadowPos; #ifdef SHADOWGEN_PROGRAM_MODEL diff --git a/rts/Game/UnsyncedGameCommands.cpp b/rts/Game/UnsyncedGameCommands.cpp index 1098b444577..09ea24b70b8 100644 --- a/rts/Game/UnsyncedGameCommands.cpp +++ b/rts/Game/UnsyncedGameCommands.cpp @@ -314,6 +314,24 @@ class ShadowsActionExecutor : public IUnsyncedActionExecutor { } }; +class MapShadowPolyOffsetActionExecutor: public IUnsyncedActionExecutor { +public: + MapShadowPolyOffsetActionExecutor(): IUnsyncedActionExecutor("MapShadowPolyOffset", "") {} + + bool Execute(const UnsyncedAction& action) const { + std::istringstream buf(action.GetArgs() + " 0.0 0.0"); + + float& pofs = (readMap->GetGroundDrawer())->spPolygonOffsetScale; + float& pofu = (readMap->GetGroundDrawer())->spPolygonOffsetUnits; + + buf >> pofs; + buf >> pofu; + + LOG("MapShadowPolygonOffset{Scale,Units}={%f,%f}", pofs, pofu); + return true; + } +}; + class WaterActionExecutor : public IUnsyncedActionExecutor { @@ -3056,6 +3074,7 @@ void UnsyncedGameCommands::AddDefaultActionExecutors() { AddActionExecutor(new SelectCycleActionExecutor()); AddActionExecutor(new DeselectActionExecutor()); AddActionExecutor(new ShadowsActionExecutor()); + AddActionExecutor(new MapShadowPolyOffsetActionExecutor()); AddActionExecutor(new MapMeshDrawerActionExecutor()); AddActionExecutor(new MapBorderActionExecutor()); AddActionExecutor(new WaterActionExecutor()); diff --git a/rts/Map/BaseGroundDrawer.h b/rts/Map/BaseGroundDrawer.h index bf88c63f67c..b9eb716dbc7 100644 --- a/rts/Map/BaseGroundDrawer.h +++ b/rts/Map/BaseGroundDrawer.h @@ -65,6 +65,9 @@ class CBaseGroundDrawer float LODScaleRefraction; float LODScaleTerrainReflection; + float spPolygonOffsetScale = -1.0f; + float spPolygonOffsetUnits = -1.0f; + int jamColor[3]; int losColor[3]; int radarColor[3]; diff --git a/rts/Map/SMF/SMFGroundDrawer.cpp b/rts/Map/SMF/SMFGroundDrawer.cpp index 8455e7dc949..931d4d4a863 100644 --- a/rts/Map/SMF/SMFGroundDrawer.cpp +++ b/rts/Map/SMF/SMFGroundDrawer.cpp @@ -427,9 +427,8 @@ void CSMFGroundDrawer::DrawBorder(const DrawPass::e drawPass) glEnable(GL_BLEND); - if (wireframe) { + if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } /* if (mapRendering->voidWater && (drawPass != DrawPass::WaterReflection)) { @@ -446,9 +445,8 @@ void CSMFGroundDrawer::DrawBorder(const DrawPass::e drawPass) } */ - if (wireframe) { + if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } glDisable(GL_BLEND); @@ -477,10 +475,12 @@ void CSMFGroundDrawer::DrawShadowPass() Shader::IProgramObject* po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_MAP); glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(spPolygonOffsetScale, spPolygonOffsetUnits); // dz*s + r*u - glPolygonOffset(-1.0f, -1.0f); + // also render the border geometry to prevent light-visible backfaces po->Enable(); meshDrawer->DrawMesh(DrawPass::Shadow); + meshDrawer->DrawBorderMesh(DrawPass::Shadow); po->Disable(); glDisable(GL_POLYGON_OFFSET_FILL); diff --git a/rts/Rendering/Shaders/ShaderHandler.cpp b/rts/Rendering/Shaders/ShaderHandler.cpp index b2f5ccb950b..ca3f702a156 100644 --- a/rts/Rendering/Shaders/ShaderHandler.cpp +++ b/rts/Rendering/Shaders/ShaderHandler.cpp @@ -95,11 +95,11 @@ Shader::IProgramObject* CShaderHandler::GetProgramObject(const std::string& poCl Shader::IProgramObject* CShaderHandler::CreateProgramObject(const std::string& poClass, const std::string& poName, bool arbProgram) { Shader::IProgramObject* po = Shader::nullProgramObject; + const char* poType = arbProgram? "ARB": "GLSL"; if (programObjects.find(poClass) != programObjects.end()) { if (programObjects[poClass].find(poName) != programObjects[poClass].end()) { - LOG_L(L_WARNING, "[%s] There is already a shader program named \"%s\"!", - __FUNCTION__, poName.c_str()); + LOG_L(L_WARNING, "[SH::%s] program-object \"%s\" already exists", __func__, poName.c_str()); return (programObjects[poClass][poName]); } } else { @@ -107,20 +107,18 @@ Shader::IProgramObject* CShaderHandler::CreateProgramObject(const std::string& p } if (arbProgram) { - if (globalRendering->haveARB) { + if (globalRendering->haveARB) po = new Shader::ARBProgramObject(poName); - } + } else { - if (globalRendering->haveGLSL) { + if (globalRendering->haveGLSL) po = new Shader::GLSLProgramObject(poName); - } - } - if (po == Shader::nullProgramObject) { - LOG_L(L_ERROR, "[%s] Tried to create \"%s\" a %s shader program on hardware w/o support for it!", - __FUNCTION__, poName.c_str(), arbProgram ? "ARB" : "GLSL"); } + if (po == Shader::nullProgramObject) + LOG_L(L_ERROR, "[SH::%s] hardware does not support creating (%s) program-object \"%s\"", __func__, poType, poName.c_str()); + programObjects[poClass][poName] = po; return po; } @@ -136,24 +134,23 @@ Shader::IShaderObject* CShaderHandler::CreateShaderObject(const std::string& soN case GL_FRAGMENT_PROGRAM_ARB: { // assert(StringToLower(soName).find("arb") != std::string::npos); - if (globalRendering->haveARB) { + if (globalRendering->haveARB) so = new Shader::ARBShaderObject(soType, soName); - } + } break; default: { // assume GLSL shaders by default // assert(StringToLower(soName).find("arb") == std::string::npos); - if (globalRendering->haveGLSL) { + if (globalRendering->haveGLSL) so = new Shader::GLSLShaderObject(soType, soName, soDefs); - } + } break; } if (so == Shader::nullShaderObject) { - LOG_L(L_ERROR, "[%s] Tried to create a shader (\"%s\") on hardware that does not support them!", - __FUNCTION__, soName.c_str()); + LOG_L(L_ERROR, "[SH::%s] hardware does not support creating shader-object \"%s\"", __func__, soName.c_str()); return so; } diff --git a/rts/Rendering/ShadowHandler.cpp b/rts/Rendering/ShadowHandler.cpp index a96224409b8..ba3bfbbc578 100644 --- a/rts/Rendering/ShadowHandler.cpp +++ b/rts/Rendering/ShadowHandler.cpp @@ -211,19 +211,24 @@ void CShadowHandler::LoadShadowGenShaderProgs() if (globalRendering->haveGLSL) { for (int i = 0; i < SHADOWGEN_PROGRAM_LAST; i++) { Shader::IProgramObject* po = sh->CreateProgramObject("[ShadowHandler]", shadowGenProgHandles[i] + "GLSL", false); - Shader::IShaderObject* vso = sh->CreateShaderObject("GLSL/ShadowGenVertProg.glsl", shadowGenProgDefines[i] + extraDef, GL_VERTEX_SHADER); - // Shader::IShaderObject* fso = sh->CreateShaderObject("GLSL/ShadowGenFragProg.glsl", shadowGenProgDefines[i] + extraDef, GL_FRAGMENT_SHADER); - po->AttachShaderObject(vso); - // po->AttachShaderObject(fso); + if (i == SHADOWGEN_PROGRAM_MAP) { + po->AttachShaderObject(sh->CreateShaderObject("GLSL/ShadowGenVertProg.glsl", shadowGenProgDefines[i] + extraDef, GL_VERTEX_SHADER)); + po->AttachShaderObject(sh->CreateShaderObject("GLSL/ShadowGenFragProg.glsl", shadowGenProgDefines[i] + extraDef, GL_FRAGMENT_SHADER)); + } else { + po->AttachShaderObject(sh->CreateShaderObject("GLSL/ShadowGenVertProg.glsl", shadowGenProgDefines[i] + extraDef, GL_VERTEX_SHADER)); + } + po->Link(); po->SetUniformLocation("shadowParams"); // idx 0 po->SetUniformLocation("cameraDirX"); // idx 1, used by SHADOWGEN_PROGRAM_TREE_NEAR po->SetUniformLocation("cameraDirY"); // idx 2, used by SHADOWGEN_PROGRAM_TREE_NEAR po->SetUniformLocation("treeOffset"); // idx 3, used by SHADOWGEN_PROGRAM_TREE_NEAR po->SetUniformLocation("alphaMaskTex"); // idx 4 + po->SetUniformLocation("alphaParams"); // idx 5, used by SHADOWGEN_PROGRAM_MAP po->Enable(); po->SetUniform1i(4, 0); // alphaMaskTex + po->SetUniform2f(5, mapInfo->map.voidAlphaMin, 0.0f); // alphaParams po->Disable(); po->Validate(); @@ -356,8 +361,8 @@ void CShadowHandler::DrawShadowPasses() glPushAttrib(GL_POLYGON_BIT | GL_ENABLE_BIT); glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + eventHandler.DrawWorldShadow(); if ((shadowGenBits & SHADOWGEN_BIT_TREE) != 0) { @@ -373,14 +378,19 @@ void CShadowHandler::DrawShadowPasses() featureDrawer->DrawShadowPass(); } - glCullFace(GL_FRONT); - // cull front-faces during the terrain shadow pass: sun direction - // can be set so oblique that geometry back-faces are visible (eg. - // from hills near map edges) from its POV - // (could just disable culling of terrain faces, but we also want - // to prevent overdraw in such low-angle passes) + // cull front-faces during the terrain shadow pass: sun direction + // can be set so oblique that geometry back-faces are visible (eg. + // from hills near map edges) from its POV + // + // not the best idea, causes acne when projecting the shadow-map + // (rasterizing back-faces writes different depth values) and is + // no longer required since border geometry will fully hide them + // (could just disable culling of terrain faces entirely, but we + // also want to prevent overdraw in low-angle passes) + // glCullFace(GL_FRONT); if ((shadowGenBits & SHADOWGEN_BIT_MAP) != 0) readMap->GetGroundDrawer()->DrawShadowPass(); + glPopAttrib(); inShadowPass = false; diff --git a/rts/Rendering/UnitDrawer.cpp b/rts/Rendering/UnitDrawer.cpp index 3b6c94d75f1..dc274dda6c1 100644 --- a/rts/Rendering/UnitDrawer.cpp +++ b/rts/Rendering/UnitDrawer.cpp @@ -93,6 +93,20 @@ static const void KillShadowTex(const CS3OTextureHandler::S3OTexMat*) { } +static const void BindShadowTexAtlas(const CS3OTextureHandler::S3OTexMat*) { + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texturehandler3DO->GetAtlasTex2ID()); +} + +static const void KillShadowTexAtlas(const CS3OTextureHandler::S3OTexMat*) { + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); +} + + + static const void PushRenderState3DO() { BindOpaqueTexAtlas(nullptr); @@ -140,7 +154,7 @@ static const BindTexFunc opaqueTexBindFuncs[MODELTYPE_OTHER] = { }; static const BindTexFunc shadowTexBindFuncs[MODELTYPE_OTHER] = { - BindShadowTexDummy, // 3DO (no-op) + BindShadowTexAtlas, // 3DO BindShadowTex, // S3O BindShadowTex, // OBJ BindShadowTex, // ASS @@ -152,7 +166,7 @@ static const BindTexFunc* bindModelTexFuncs[] = { }; static const KillTexFunc shadowTexKillFuncs[MODELTYPE_OTHER] = { - KillShadowTexDummy, // 3DO (no-op) + KillShadowTexAtlas, // 3DO KillShadowTex, // S3O KillShadowTex, // OBJ KillShadowTex, // ASS @@ -377,14 +391,12 @@ void CUnitDrawer::Draw(bool drawReflection, bool drawRefraction) // first do the deferred pass; conditional because // most of the water renderers use their own FBO's - if (drawDeferred && !drawReflection && !drawRefraction) { + if (drawDeferred && !drawReflection && !drawRefraction) LuaObjectDrawer::DrawDeferredPass(LUAOBJ_UNIT); - } // now do the regular forward pass - if (drawForward) { + if (drawForward) DrawOpaquePass(false, drawReflection, drawRefraction); - } farTextureHandler->Draw(); @@ -417,10 +429,13 @@ void CUnitDrawer::DrawOpaqueUnits(int modelType, bool drawReflection, bool drawR { const auto& unitBin = opaqueModelRenderers[modelType]->GetUnitBin(); - for (auto unitBinIt = unitBin.cbegin(); unitBinIt != unitBin.cend(); ++unitBinIt) { - BindModelTypeTexture(modelType, unitBinIt->first); + for (const auto& unitBinPair: unitBin) { + const auto& unitSet = unitBinPair.second; + const int textureType = unitBinPair.first; + + BindModelTypeTexture(modelType, textureType); - for (CUnit* unit: unitBinIt->second) { + for (CUnit* unit: unitSet) { DrawOpaqueUnit(unit, drawReflection, drawRefraction); } } @@ -573,12 +588,13 @@ void CUnitDrawer::DrawOpaqueUnitShadow(CUnit* unit) { void CUnitDrawer::DrawOpaqueUnitsShadow(int modelType) { const auto& unitBin = opaqueModelRenderers[modelType]->GetUnitBin(); - for (const auto& unitBinP: unitBin) { - const auto& unitSet = unitBinP.second; - const int textureType = unitBinP.first; + for (const auto& unitBinPair: unitBin) { + const auto& unitSet = unitBinPair.second; + const int textureType = unitBinPair.first; - BindModelTypeTexture(modelType, textureType); - // shadowTexBindFuncs[modelType](texturehandlerS3O->GetTexture(textureType)); + // only need to bind the atlas once for 3DO's, but KISS + assert((modelType == MODELTYPE_3DO) == (textureType == -1)); + shadowTexBindFuncs[modelType](texturehandlerS3O->GetTexture(textureType)); for (const auto& unitSetP: unitSet) { DrawOpaqueUnitShadow(unitSetP);