glfw 屏幕外和大图像窗口渲染之间的不同结果

时间:2021-02-26 08:55:44

标签: python opengl glfw texture-mapping texture2d

我在使用 glfw 窗口和离屏渲染时得到了不同的结果。我想在网格上使用此 texture_image 应用纹理映射。图片尺寸为 3500 x 1752。

我在弹出的glfw窗口上渲染和显示渲染图像的代码如下:

t_obj = "mesh.obj"
tex_file_path = "texture.png"

tex_im = cv2.imread(tex_file_path)
h, w = tex_im.shape[:2]
vertices, tex_coords, indices = load_obj_file(t_obj, dimension=3)
colors = np.ones((len(vertices), 3), dtype=np.float)

vertices = np.hstack((vertices, colors, tex_coords))
vertices = np.array(vertices, dtype=np.float32)

# a vertex shader consists of x, y, z and w.
vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
layout(location = 2) in vec2 a_texture;
uniform mat4 rotation;
out vec3 v_color;
out vec2 v_texture;
void main()
{
    gl_Position = rotation * vec4(a_position, 1.0);
    v_color = a_color;
    v_texture = a_texture;

    //v_texture = 1 - a_texture;                      // Flips the texture vertically and horizontally
    //v_texture = vec2(a_texture.s, 1 - a_texture.t); // Flips the texture vertically
}
"""

# fragment shader consists of R, G, B and A.
fragment_src = """
# version 330
in vec3 v_color;
in vec2 v_texture;
out vec4 out_color;
uniform sampler2D s_texture;
void main()
{
    out_color = texture(s_texture, v_texture) * vec4(v_color, 1.0f);
}
"""


# glfw callback functions
def window_resize(window, width, height):
    glViewport(0, 0, width, height)


# initializing glfw library
if not glfw.init():
    raise Exception("glfw can not be initialized!")

# creating the window
# glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window = glfw.create_window(w, h, "My OpenGL window", None, None)

# check if window was created
if not window:
    glfw.terminate()
    raise Exception("glfw window can not be created!")

# set window's position
glfw.set_window_pos(window, w, h)

# set the callback function for window resize
glfw.set_window_size_callback(window, window_resize)

# make the context current
glfw.make_context_current(window)

shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER),
                        compileShader(fragment_src, GL_FRAGMENT_SHADER))

# Step2: Create and bind VBO objects to transfer data
VBO = glGenBuffers(1)  # request a buffer slot from GPU.
glBindBuffer(GL_ARRAY_BUFFER, VBO)  # make this buffer the default one.
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)  # upload CPU data to GPU buffer.

# Step3: Create and bind EBO object to transfer data
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# Step4: Specify the resolution method and enable vertex attributes
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(0))
# Vertex color attributes
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(12))
# Vertex texture attributes
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(24))

texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)

# Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

# load image
image = Image.open(tex_file_path)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = image.convert("RGBA").tobytes()
# Attach a texture image to the texture buffer.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)

glUseProgram(shader)
glClearColor(1, 1, 1, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

model = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.0, 0.0, 0]))
rotation_loc = glGetUniformLocation(shader, "rotation")

# the main application loop
while not glfw.window_should_close(window):
    glfw.poll_events()
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, model)
    glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)

    glfw.swap_buffers(window)

# save_image
data = glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE)
pil_image = Image.frombytes("RGBA", (w, h), data)
pil_image = ImageOps.flip(pil_image)
pil_image.save('output.png')
glfw.terminate()

结果是with_popup_window_result

但是,保存到磁盘的输出图像被调整为较小的图像,然后进行填充,以便最终的宽度和高度与纹理图像的宽度和高度相同。这是saved_output

但是,如果我修改代码使其进行离屏渲染并且不显示 glfw 窗口,则会裁剪输出图像。修改后的代码如下:

t_obj = "obj_time_0.5.obj"
tex_file_path = "s.png"

tex_im = cv2.imread(tex_file_path)
h, w = tex_im.shape[:2]
vertices, tex_coords, indices = load_obj_file(t_obj, dimension=3)
colors = np.ones((len(vertices), 3), dtype=np.float)

vertices = np.hstack((vertices, colors, tex_coords))
vertices = np.array(vertices, dtype=np.float32)

# a vertex shader consists of x, y, z and w.
vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
layout(location = 2) in vec2 a_texture;
uniform mat4 rotation;
out vec3 v_color;
out vec2 v_texture;
void main()
{
    gl_Position = rotation * vec4(a_position, 1.0);
    v_color = a_color;
    v_texture = a_texture;

    //v_texture = 1 - a_texture;                      // Flips the texture vertically and horizontally
    //v_texture = vec2(a_texture.s, 1 - a_texture.t); // Flips the texture vertically
}
"""

# fragment shader consists of R, G, B and A.
fragment_src = """
# version 330
in vec3 v_color;
in vec2 v_texture;
out vec4 out_color;
uniform sampler2D s_texture;
void main()
{
    out_color = texture(s_texture, v_texture) * vec4(v_color, 1.0f);
}
"""


# glfw callback functions
def window_resize(window, width, height):
    glViewport(0, 0, width, height)


# initializing glfw library
if not glfw.init():
    raise Exception("glfw can not be initialized!")

# creating the window
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window = glfw.create_window(w, h, "My OpenGL window", None, None)

# check if window was created
if not window:
    glfw.terminate()
    raise Exception("glfw window can not be created!")

# set window's position
glfw.set_window_pos(window, w, h)

# set the callback function for window resize
glfw.set_window_size_callback(window, window_resize)

# make the context current
glfw.make_context_current(window)

shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER),
                        compileShader(fragment_src, GL_FRAGMENT_SHADER))

# Step2: Create and bind VBO objects to transfer data
VBO = glGenBuffers(1)  # request a buffer slot from GPU.
glBindBuffer(GL_ARRAY_BUFFER, VBO)  # make this buffer the default one.
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)  # upload CPU data to GPU buffer.

# Step3: Create and bind EBO object to transfer data
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
# Step4: Specify the resolution method and enable vertex attributes
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(0))
# Vertex color attributes
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(12))
# Vertex texture attributes
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertices.itemsize * 8, ctypes.c_void_p(24))

texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)

# Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

# load image
image = Image.open(tex_file_path)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
img_data = image.convert("RGBA").tobytes()
# Attach a texture image to the texture buffer.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)

glUseProgram(shader)
glClearColor(1, 1, 1, 1)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

model = pyrr.matrix44.create_from_translation(pyrr.Vector3([0.0, 0.0, 0]))
rotation_loc = glGetUniformLocation(shader, "rotation")

# the main application loop
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

glUniformMatrix4fv(rotation_loc, 1, GL_FALSE, model)
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)

# save_image
data = glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE)
pil_image = Image.frombytes("RGBA", (w, h), data)
pil_image = ImageOps.flip(pil_image)
pil_image.save('output.png')
glfw.destroy_window(window)
glfw.terminate()

此离屏渲染的保存结果为 offscreen_output。它被裁剪和填充,因此生成的图像尺寸不会改变。

我想知道是什么导致了这些调整大小和裁剪问题。这只发生在输出维度很大的时候。我尝试将较小的尺寸 (< 1000 x 1000) 传递给 glReadPixels() 并且输出图像很好(没有调整大小或裁剪)。我在某处读到有人可以尝试使用 frameBufferObject (FBO) 进行离屏渲染而不是使用 glfw 但由于我不知道如何使用 FBO,当我从某人那里复制 FBO 代码时程序崩溃了其他的。

非常感谢任何帮助。预先非常感谢您。

0 个答案:

没有答案