When down scaling 2D images in Java2D, it does a great job at preserving hard edges while downscaling to non power of 2s. However, in OpenGL, I have been unable to find a solution to this. I have tried using GL_NEAREST
to get hard edges, but it also creates the wonky edges aswell. I cannot use GL_LINEAR
in this case either, but still, the linear interpolation still looks wonky.
Example (Both rendering 30x30 hard image, rendering at 30x30 pixels).
Please note : I am aware that this occurs with images that aren't power of twos, like 30, but the main problem is, if I try to upscale or downscale an image that is power of two (say 16x16) to something that isn't a power of two (say 20x20), I still get this effect. This issue with scaling this occurs in Java2D, but it is by far less noticable.
My question is: What parameters will I need to use when rendering a non power of two image? So I can get a similar effect that I get in Java 2D.
I can post source code if needed.
EDIT
Original Image (30 x 30 png)
Turns out I wasn't scaling them at all! Both were being rendered at the original 30 x 30 pixels on both OpenGL and Java2D.
Sample Code: Java2D:
g.drawImage(heart, 0, 0, 30, 30, null);
No rendering hints are being applied, just the bare minimum.
In OpenGL
Vertex Shader:
#version 400
in vec2 position;
out vec2 textureCoords;
uniform float width;
uniform float height;
uniform float xOffset;
uniform float yOffset;
uniform mat4 transformationMatrix;
void main(void)
{
gl_Position = transformationMatrix * vec4(position.x, position.y, 0.0, 1.0);
gl_Position.x += (xOffset) / (width / 2);
gl_Position.y += (yOffset) / (height / 2);
gl_Position.y = gl_Position.y;
textureCoords = vec2(position.x / 1, position.y / 1);
}
Fragment Shader:
#version 400
in vec2 textureCoords;
out vec4 out_Color;
uniform sampler2D texture2d;
uniform float transparency;
void main()
{
out_Color = texture2D(texture2d, vec2(textureCoords.x, textureCoords.y));
if(textureCoords.y > 1 || textureCoords.y < 0)
{
discard;
}
}
Rendering methods:
public void makeWonkyImage()
{
render(0, 0, 30, 30, heart);
}
public void render(float x, float y, float width, float height, int textureID)
{
PostProcess.imageRenderer.render(x, Gfx.HEIGHT - y, width / 1000, -height / 1000, textureID);
}
public void render(float x, float y, float width, float height, int textureID)
{
shader.start();
prepare(textureID);
Vector2f position = new Vector2f((-Display.WIDTH / (width * 1000f))
, (-Display.HEIGHT / (height * 1000f)));
Matrix4f matrix = Maths.createTransformationMatrix(position,
new Vector2f(width / Gfx.WIDTH * 1000f, height / Gfx.HEIGHT * 1000f));
shader.loadTransformation(matrix);
shader.loadScreenDimensions((float) Display.getWidth(), (float) Display.getHeight());
shader.loadOffsets(x, y);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, quad.getVertexCount());
end();
shader.stop();
}
public void prepare(int texture)
{
GL30.glBindVertexArray(quad.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
}