From 26bd800d63e84388ecaf9ecc19f6abe5f5805024 Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Mon, 9 Oct 2017 18:58:44 +0200 Subject: [PATCH] calculate the LOD on CPU side and restrict mipmap levels for huge textures to remove bad looking mipmap generations at high zoom levels --- shader/bordertilelinetex.vert | 6 ++--- shader/bordertiletex.vert | 6 ++--- shader/tiletex.vert | 10 ++++----- src/engine/client/backend_sdl.cpp | 27 +++++++++++++--------- src/engine/client/graphics_threaded.cpp | 30 +++++++++++++++++++++---- src/engine/client/graphics_threaded.h | 6 ++--- src/engine/client/opengl_sl_program.h | 2 +- 7 files changed, 58 insertions(+), 29 deletions(-) diff --git a/shader/bordertilelinetex.vert b/shader/bordertilelinetex.vert index 7b40b67b9..01fb577fe 100644 --- a/shader/bordertilelinetex.vert +++ b/shader/bordertilelinetex.vert @@ -5,7 +5,7 @@ layout (location = 1) in vec2 inVertexTexCoord; layout (location = 2) in ivec2 inVertexTexRightOrBottom; uniform mat4x2 Pos; -uniform float ZoomFactor; +uniform float LOD; uniform vec2 Dir; @@ -18,8 +18,8 @@ void main() VertPos.y += Dir.y * (gl_InstanceID+1); gl_Position = vec4(Pos * VertPos, 0.0, 1.0); - float F1 = -(0.75/1024.0) * ZoomFactor; - float F2 = (1.75/1024.0) * ZoomFactor; + float F1 = -(0.5/(1024.0 * pow(0.5, (LOD+1.0)))); + float F2 = (0.5/(1024.0 * pow(0.5, (LOD+1.0)))); float tx = (inVertexTexCoord.x/(16.0)) - (inVertexTexRightOrBottom.x == 0 ? 0.0 : (1.0/1024.0)); float ty = (inVertexTexCoord.y/(16.0)) - (inVertexTexRightOrBottom.y == 0 ? 0.0 : (1.0/1024.0)); texCoord = vec2(tx + (inVertexTexRightOrBottom.x == 0 ? F2 : F1), ty + (inVertexTexRightOrBottom.y == 0 ? F2 : F1)); diff --git a/shader/bordertiletex.vert b/shader/bordertiletex.vert index cf0fb2d84..526e0808e 100644 --- a/shader/bordertiletex.vert +++ b/shader/bordertiletex.vert @@ -5,7 +5,7 @@ layout (location = 1) in vec2 inVertexTexCoord; layout (location = 2) in ivec2 inVertexTexRightOrBottom; uniform mat4x2 Pos; -uniform float ZoomFactor; +uniform float LOD; uniform vec2 Offset; uniform vec2 Dir; @@ -22,8 +22,8 @@ void main() VertPos.y += Offset.y + Dir.y * YCount; gl_Position = vec4(Pos * VertPos, 0.0, 1.0); - float F1 = -(0.75/1024.0) * ZoomFactor; - float F2 = (1.75/1024.0) * ZoomFactor; + float F1 = -(0.5/(1024.0 * pow(0.5, (LOD+1.0)))); + float F2 = (0.5/(1024.0 * pow(0.5, (LOD+1.0)))); float tx = (inVertexTexCoord.x/(16.0)) - (inVertexTexRightOrBottom.x == 0 ? 0.0 : (1.0/1024.0)); float ty = (inVertexTexCoord.y/(16.0)) - (inVertexTexRightOrBottom.y == 0 ? 0.0 : (1.0/1024.0)); texCoord = vec2(tx + (inVertexTexRightOrBottom.x == 0 ? F2 : F1), ty + (inVertexTexRightOrBottom.y == 0 ? F2 : F1)); diff --git a/shader/tiletex.vert b/shader/tiletex.vert index a632e505c..f007603ad 100644 --- a/shader/tiletex.vert +++ b/shader/tiletex.vert @@ -5,16 +5,16 @@ layout (location = 1) in vec2 inVertexTexCoord; layout (location = 2) in ivec2 inVertexTexRightOrBottom; uniform mat4x2 Pos; -uniform float ZoomFactor; +uniform float LOD; noperspective out vec2 texCoord; void main() { gl_Position = vec4(Pos * vec4(inVertex, 0.0, 1.0), 0.0, 1.0); - float F1 = -(0.75/1024.0) * ZoomFactor; - float F2 = (1.75/1024.0) * ZoomFactor; - float tx = (inVertexTexCoord.x/(16.0)) - (inVertexTexRightOrBottom.x == 0 ? 0.0 : (1.0/1024.0)); - float ty = (inVertexTexCoord.y/(16.0)) - (inVertexTexRightOrBottom.y == 0 ? 0.0 : (1.0/1024.0)); + float F1 = -(0.5/(1024.0 * pow(0.5, (LOD+1.0)))); + float F2 = (0.5/(1024.0 * pow(0.5, (LOD+1.0)))); + float tx = (inVertexTexCoord.x/(16.0)); + float ty = (inVertexTexCoord.y/(16.0)); texCoord = vec2(tx + (inVertexTexRightOrBottom.x == 0 ? F2 : F1), ty + (inVertexTexRightOrBottom.y == 0 ? F2 : F1)); } \ No newline at end of file diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 7386f8c2b..55635f02a 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -621,7 +621,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pTileProgram->m_LocIsTextured = -1; m_pTileProgram->m_LocTextureSampler = -1; m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc("vertColor"); - m_pTileProgram->m_LocZoomFactor = -1; + m_pTileProgram->m_LocLOD = -1; } { CGLSL VertexShader; @@ -640,7 +640,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pTileProgramTextured->m_LocIsTextured = -1; m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc("textureSampler"); m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc("vertColor"); - m_pTileProgramTextured->m_LocZoomFactor = m_pTileProgramTextured->GetUniformLoc("ZoomFactor"); + m_pTileProgramTextured->m_LocLOD = m_pTileProgramTextured->GetUniformLoc("LOD"); } { CGLSL VertexShader; @@ -659,7 +659,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pBorderTileProgram->m_LocIsTextured = -1; m_pBorderTileProgram->m_LocTextureSampler = -1; m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc("vertColor"); - m_pBorderTileProgram->m_LocZoomFactor = -1; + m_pBorderTileProgram->m_LocLOD = -1; m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc("Offset"); m_pBorderTileProgram->m_LocDir = m_pBorderTileProgram->GetUniformLoc("Dir"); m_pBorderTileProgram->m_LocJumpIndex = m_pBorderTileProgram->GetUniformLoc("JumpIndex"); @@ -681,7 +681,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pBorderTileProgramTextured->m_LocIsTextured = -1; m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc("textureSampler"); m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc("vertColor"); - m_pBorderTileProgramTextured->m_LocZoomFactor = m_pBorderTileProgramTextured->GetUniformLoc("ZoomFactor"); + m_pBorderTileProgramTextured->m_LocLOD = m_pBorderTileProgramTextured->GetUniformLoc("LOD"); m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc("Offset"); m_pBorderTileProgramTextured->m_LocDir = m_pBorderTileProgramTextured->GetUniformLoc("Dir"); m_pBorderTileProgramTextured->m_LocJumpIndex = m_pBorderTileProgramTextured->GetUniformLoc("JumpIndex"); @@ -703,7 +703,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pBorderTileLineProgram->m_LocIsTextured = -1; m_pBorderTileLineProgram->m_LocTextureSampler = -1; m_pBorderTileLineProgram->m_LocColor = m_pBorderTileLineProgram->GetUniformLoc("vertColor"); - m_pBorderTileLineProgram->m_LocZoomFactor = -1; + m_pBorderTileLineProgram->m_LocLOD = -1; m_pBorderTileLineProgram->m_LocDir = m_pBorderTileLineProgram->GetUniformLoc("Dir"); } { @@ -723,7 +723,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand m_pBorderTileLineProgramTextured->m_LocIsTextured = -1; m_pBorderTileLineProgramTextured->m_LocTextureSampler = m_pBorderTileLineProgramTextured->GetUniformLoc("textureSampler"); m_pBorderTileLineProgramTextured->m_LocColor = m_pBorderTileLineProgramTextured->GetUniformLoc("vertColor"); - m_pBorderTileLineProgramTextured->m_LocZoomFactor = m_pBorderTileLineProgramTextured->GetUniformLoc("ZoomFactor"); + m_pBorderTileLineProgramTextured->m_LocLOD = m_pBorderTileLineProgramTextured->GetUniformLoc("LOD"); m_pBorderTileLineProgramTextured->m_LocDir = m_pBorderTileLineProgramTextured->GetUniformLoc("Dir"); } @@ -926,7 +926,14 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe { glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); + //prevent mipmap display bugs, when zooming out far + if(Width >= 1024 && Height >= 1024) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); + } + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + glGenerateMipmap(GL_TEXTURE_2D); } //this is the initial value for the wrap modes @@ -1166,7 +1173,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuf } else pProgram = m_pBorderTileProgram; pProgram->UseProgram(); - if(pProgram->m_LocZoomFactor != -1) pProgram->SetUniform(pProgram->m_LocZoomFactor, (float)(pCommand->m_ZoomScreenRatio < .5f ? .5f : pCommand->m_ZoomScreenRatio)); + if(pProgram->m_LocLOD != -1) pProgram->SetUniform(pProgram->m_LocLOD, (float)(pCommand->m_LOD)); SetState(pCommand->m_State, pProgram); pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float*)&pCommand->m_Color); @@ -1197,7 +1204,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTileLine(const CComman } else pProgram = m_pBorderTileLineProgram; pProgram->UseProgram(); - if(pProgram->m_LocZoomFactor != -1) pProgram->SetUniform(pProgram->m_LocZoomFactor, (float)(pCommand->m_ZoomScreenRatio < .5f ? .5f : pCommand->m_ZoomScreenRatio)); + if(pProgram->m_LocLOD != -1) pProgram->SetUniform(pProgram->m_LocLOD, (float)(pCommand->m_LOD)); SetState(pCommand->m_State, pProgram); pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float*)&pCommand->m_Color); @@ -1231,7 +1238,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderVertexArray(const CCommandBu else pProgram = m_pTileProgram; pProgram->UseProgram(); - if(pProgram->m_LocZoomFactor != -1) pProgram->SetUniform(pProgram->m_LocZoomFactor, (float)(pCommand->m_ZoomScreenRatio < .5f ? .5f : pCommand->m_ZoomScreenRatio)); + if(pProgram->m_LocLOD != -1) pProgram->SetUniform(pProgram->m_LocLOD, (float)(pCommand->m_LOD)); SetState(pCommand->m_State, pProgram); pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float*)&pCommand->m_Color); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 7492a1eec..aface6849 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -18,7 +18,7 @@ #include #include -#include // cosf, sinf +#include // cosf, sinf, log2f #include "graphics_threaded.h" @@ -879,7 +879,15 @@ void CGraphics_Threaded::DrawVisualObject(int VisualObjectIDX, float* pColor, ch Cmd.m_IndicesDrawNum = NumIndicesOffet; Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX]; mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color)); - Cmd.m_ZoomScreenRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + float ScreenZoomRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + //the number of pixels we would skip in the fragment shader -- basically the LOD + float LODFactor = (64.f / (32.f * 1.f/ScreenZoomRatio)); + //log2 gives us the amount of halving the texture for mipmapping + int LOD = (int)log2f(LODFactor); + //5 because log2(1024/(2^5)) is 5 -- 1024/(2^6) = 32 which would mean 2 pixels per tile index + if(LOD > 5) LOD = 5; + if(LOD < 0) LOD = 0; + Cmd.m_LOD = LOD; void* Data = m_pCommandBuffer->AllocData((sizeof(char*) + sizeof(unsigned int))*NumIndicesOffet); if(Data == 0x0) @@ -935,7 +943,14 @@ void CGraphics_Threaded::DrawBorderTile(int VisualObjectIDX, float* pColor, char Cmd.m_DrawNum = DrawNum; Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX]; mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color)); - Cmd.m_ZoomScreenRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + float ScreenZoomRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + //the number of pixels we would skip in the fragment shader -- basically the LOD + float LODFactor = (64.f / (32.f * 1.f/ScreenZoomRatio)); + //log2 gives us the amount of halving the texture for mipmapping + int LOD = (int)log2f(LODFactor); + if(LOD > 5) LOD = 5; + if(LOD < 0) LOD = 0; + Cmd.m_LOD = LOD; Cmd.m_pIndicesOffset = pOffset; Cmd.m_JumpIndex = JumpIndex; @@ -969,7 +984,14 @@ void CGraphics_Threaded::DrawBorderTileLine(int VisualObjectIDX, float* pColor, Cmd.m_DrawNum = RedrawNum; Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX]; mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color)); - Cmd.m_ZoomScreenRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + float ScreenZoomRatio = (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x) / ScreenWidth(); + //the number of pixels we would skip in the fragment shader -- basically the LOD + float LODFactor = (64.f / (32.f * 1.f/ScreenZoomRatio)); + //log2 gives us the amount of halving the texture for mipmapping + int LOD = (int)log2f(LODFactor); + if(LOD > 5) LOD = 5; + if(LOD < 0) LOD = 0; + Cmd.m_LOD = LOD; Cmd.m_pIndicesOffset = pOffset; diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 0e8836a35..9e54fdb02 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -252,7 +252,7 @@ public: int m_IndicesDrawNum; int m_VisualObjectIDX; - float m_ZoomScreenRatio; + int m_LOD; }; struct SCommand_RenderBorderTile : public SCommand @@ -263,7 +263,7 @@ public: char *m_pIndicesOffset; // you should use the command buffer data to allocate vertices for this command unsigned int m_DrawNum; int m_VisualObjectIDX; - float m_ZoomScreenRatio; + int m_LOD; float m_Offset[2]; float m_Dir[2]; @@ -279,7 +279,7 @@ public: unsigned int m_IndexDrawNum; unsigned int m_DrawNum; int m_VisualObjectIDX; - float m_ZoomScreenRatio; + int m_LOD; float m_Dir[2]; }; diff --git a/src/engine/client/opengl_sl_program.h b/src/engine/client/opengl_sl_program.h index 0ab3a9237..810243dbb 100644 --- a/src/engine/client/opengl_sl_program.h +++ b/src/engine/client/opengl_sl_program.h @@ -58,7 +58,7 @@ public: class CGLSLTileProgram : public CGLSLTWProgram { public: int m_LocColor; - int m_LocZoomFactor; + int m_LocLOD; }; class CGLSLBorderTileProgram : public CGLSLTileProgram {