I am using ModernGL to render a 2D texture with pixel perfect precision. My image contains a series of boxes which are 1 px wide, but when I render them, some of the edges are wider than others. I am using orthographic projection which should give me 1:1 pixel accuracy. Here is a minimum working example:
import pygame
from pygame.locals import *
import moderngl
import numpy as np
from PIL import Image
import glm
pygame.init()
pygame.display.gl_set_attribute(pygame.GL_CONTEXT_MAJOR_VERSION, 3)
pygame.display.gl_set_attribute(pygame.GL_CONTEXT_MINOR_VERSION, 3)
pygame.display.gl_set_attribute(pygame.GL_CONTEXT_PROFILE_MASK, pygame.GL_CONTEXT_PROFILE_CORE)
SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 900
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.DOUBLEBUF | pygame.OPENGL)
clock = pygame.time.Clock()
ctx = moderngl.create_context()
ctx.enable(moderngl.CULL_FACE)
ctx.cull_face = 'back'
vert = np.array([
# x, y, z, tx, ty
0.0, 1.0, 0.0, 0.0, 0.0,
1.0, 0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 0.0, 0.0,
1.0, 1.0, 0.0, 1.0, 0.0,
1.0, 0.0, 0.0, 1.0, 1.0,
], dtype='f4')
prog = ctx.program(
vertex_shader =
'''
#version 330
in vec3 in_vert;
in vec3 in_color;
in vec2 in_text;
out vec3 v_color;
out vec2 v_text;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() {
gl_Position = projection * view * model * vec4(in_vert, 1.0);
v_color = in_color;
v_text = in_text;
}
''',
fragment_shader =
'''
#version 330
uniform sampler2D Texture;
uniform vec3 Color;
in vec3 v_color;
in vec2 v_text;
out vec4 f_color;
void main() {
f_color = texture(Texture, v_text);
}
''',
)
vbo = ctx.buffer(vert)
vao = ctx.simple_vertex_array(prog, vbo, 'in_vert', 'in_text')
IMG_WIDTH = 858
IMG_HEIGHT = 647
img = Image.open("img.png")
texture = ctx.texture(img.size, 4, img.tobytes())
texture.use()
model = glm.mat4()
model = glm.translate(model, glm.vec3(0, 100, 0))
model = glm.scale(model, glm.vec3(IMG_WIDTH, IMG_HEIGHT, 0))
prog['model'].write(model)
view = glm.mat4()
prog['view'].write(view)
projection = glm.ortho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 100)
prog['projection'].write(projection)
vao.render()
while True:
clock.tick(60)
pygame.display.flip()
I have confirmed using file
that my image is indeed 858x647:
img.png: PNG image data, 858 x 647, 8-bit/color RGBA, non-interlaced
EDIT: Added screenshots
This is how the image is supposed to look:
and this is how it appears in my opengl application:
notice how some edges on the squares appear to be wider than others.