Improve accelerated supersampling 2x antialiasing

Avoid fractional pixel offsets by forcing integer division of m_screenSize.
Shift rounded lookAtPoint onto OpenGL pixel center to ensure consistent rounding to int.
The pixel 0..1 @ 1x needs to fill the area 0..2 @ 2x so its center moves by 0.5 * (pixel size @ 1x).
This commit is contained in:
Hajo Nils Krabbenhöft 2021-06-02 15:04:23 +02:00 committed by Seth Hillbrand
parent 53a75a4961
commit 937f502158
6 changed files with 31 additions and 7 deletions

View File

@ -189,7 +189,8 @@ void GAL::ComputeWorldScreenMatrix()
MATRIX3x3D translation; MATRIX3x3D translation;
translation.SetIdentity(); translation.SetIdentity();
translation.SetTranslation( 0.5 * VECTOR2D( m_screenSize ) ); // We're deliberately dividing integers to avoid fractional pixel offsets.
translation.SetTranslation( VECTOR2D( m_screenSize.x/2, m_screenSize.y/2 ) );
MATRIX3x3D rotate; MATRIX3x3D rotate;
rotate.SetIdentity(); rotate.SetIdentity();

View File

@ -83,6 +83,7 @@ uniform float worldPixelSize;
uniform vec2 screenPixelSize; uniform vec2 screenPixelSize;
uniform float pixelSizeMultiplier; uniform float pixelSizeMultiplier;
uniform float minLinePixelWidth; uniform float minLinePixelWidth;
uniform vec2 antialiasingOffset;
float roundr( float f, float r ) float roundr( float f, float r )
@ -239,6 +240,7 @@ void main()
} }
gl_Position.xy += antialiasingOffset;
} }
)SHADER_SOURCE"; )SHADER_SOURCE";

View File

@ -439,3 +439,13 @@ int OPENGL_COMPOSITOR::GetAntialiasSupersamplingFactor() const
default: return 1; default: return 1;
} }
} }
VECTOR2D OPENGL_COMPOSITOR::GetAntialiasRenderingOffset() const
{
switch( m_currentAntialiasingMode )
{
case OPENGL_ANTIALIASING_MODE::SUPERSAMPLING_X2: return VECTOR2D( 0.5, -0.5 );
case OPENGL_ANTIALIASING_MODE::SUPERSAMPLING_X4: return VECTOR2D( 0.25, -0.25 );
default: return VECTOR2D( 0, 0 );
}
}

View File

@ -281,6 +281,7 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
ufm_worldPixelSize = 1; ufm_worldPixelSize = 1;
ufm_screenPixelSize = 1; ufm_screenPixelSize = 1;
ufm_pixelSizeMultiplier = 1; ufm_pixelSizeMultiplier = 1;
ufm_antialiasingOffset = 1;
} }
@ -528,6 +529,7 @@ void OPENGL_GAL::beginDrawing()
ufm_worldPixelSize = m_shader->AddParameter( "worldPixelSize" ); ufm_worldPixelSize = m_shader->AddParameter( "worldPixelSize" );
ufm_screenPixelSize = m_shader->AddParameter( "screenPixelSize" ); ufm_screenPixelSize = m_shader->AddParameter( "screenPixelSize" );
ufm_pixelSizeMultiplier = m_shader->AddParameter( "pixelSizeMultiplier" ); ufm_pixelSizeMultiplier = m_shader->AddParameter( "pixelSizeMultiplier" );
ufm_antialiasingOffset = m_shader->AddParameter( "antialiasingOffset" );
m_shader->Use(); m_shader->Use();
m_shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT ); m_shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
@ -541,9 +543,14 @@ void OPENGL_GAL::beginDrawing()
m_shader->Use(); m_shader->Use();
m_shader->SetParameter( ufm_worldPixelSize, m_shader->SetParameter( ufm_worldPixelSize,
(float) ( getWorldPixelSize() / GetScaleFactor() ) ); (float) ( getWorldPixelSize() / GetScaleFactor() ) );
m_shader->SetParameter( ufm_screenPixelSize, getScreenPixelSize() ); const VECTOR2D& screenPixelSize = getScreenPixelSize();
m_shader->SetParameter( ufm_screenPixelSize, screenPixelSize );
double pixelSizeMultiplier = m_compositor->GetAntialiasSupersamplingFactor(); double pixelSizeMultiplier = m_compositor->GetAntialiasSupersamplingFactor();
m_shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier ); m_shader->SetParameter( ufm_pixelSizeMultiplier, (float) pixelSizeMultiplier );
VECTOR2D renderingOffset = m_compositor->GetAntialiasRenderingOffset();
renderingOffset.x *= screenPixelSize.x;
renderingOffset.y *= screenPixelSize.y;
m_shader->SetParameter( ufm_antialiasingOffset, renderingOffset );
m_shader->Deactivate(); m_shader->Deactivate();
// Something betreen BeginDrawing and EndDrawing seems to depend on // Something betreen BeginDrawing and EndDrawing seems to depend on
@ -2321,18 +2328,20 @@ void OPENGL_GAL::EnableDepthTest( bool aEnabled )
} }
static double roundr( double f, double r ) inline double round_to_half_pixel( double f, double r )
{ {
return floor( f / r + 0.5 ) * r; return ( ceil( f / r ) - 0.5 ) * r;
} }
void OPENGL_GAL::ComputeWorldScreenMatrix() void OPENGL_GAL::ComputeWorldScreenMatrix()
{ {
computeWorldScale();
auto pixelSize = m_worldScale; auto pixelSize = m_worldScale;
m_lookAtPoint.x = roundr( m_lookAtPoint.x, pixelSize ); // we need -m_lookAtPoint == -k * pixelSize + 0.5 * pixelSize for OpenGL
m_lookAtPoint.y = roundr( m_lookAtPoint.y, pixelSize ); // meaning m_lookAtPoint = (k-0.5)*pixelSize with integer k
m_lookAtPoint.x = round_to_half_pixel( m_lookAtPoint.x, pixelSize );
m_lookAtPoint.y = round_to_half_pixel( m_lookAtPoint.y, pixelSize );
GAL::ComputeWorldScreenMatrix(); GAL::ComputeWorldScreenMatrix();
} }

View File

@ -94,6 +94,7 @@ public:
OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const; OPENGL_ANTIALIASING_MODE GetAntialiasingMode() const;
int GetAntialiasSupersamplingFactor() const; int GetAntialiasSupersamplingFactor() const;
VECTOR2D GetAntialiasRenderingOffset() const;
protected: protected:
/// Binds a specific Framebuffer Object. /// Binds a specific Framebuffer Object.

View File

@ -336,6 +336,7 @@ private:
GLint ufm_worldPixelSize; GLint ufm_worldPixelSize;
GLint ufm_screenPixelSize; GLint ufm_screenPixelSize;
GLint ufm_pixelSizeMultiplier; GLint ufm_pixelSizeMultiplier;
GLint ufm_antialiasingOffset;
wxCursor m_currentwxCursor; ///< wxCursor showing the current native cursor wxCursor m_currentwxCursor; ///< wxCursor showing the current native cursor