Moderngl:带角度的项目照片

2024-05-18 15:18:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试着从某个角度投射一张照片

如果照片是在相机直视前方时拍摄的,那么相机角度(yawpitchroll)都为零

现在让我们假设相机向上看,假设使用pitch=1 radians,那么照片实际上捕捉的是梯形而不是矩形:

picture of sky with an angle

现在让我们来看一下代码——这是一个简单的程序,使用moderngl-window投影一张没有角度的照片:

import moderngl
import moderngl_window
import numpy as np
from PIL import Image


class Pygame(moderngl_window.WindowConfig):
    window_size = 1280, 720

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.program = self.ctx.program(
            vertex_shader="""
                #version 330
                in vec2 vertex_xy;
                in vec2 vertex_uv;
                uniform mat4 model;
                out vec2 fragment_uv; 
                void main() {
                    vec4 p = vec4(vertex_xy, 0.0, 1.0);
                    gl_Position = model * p;
                    fragment_uv = vertex_uv;
                }
                """,
            fragment_shader="""
                #version 330
                in vec2 fragment_uv;
                uniform sampler2D texture0;
                out vec4 fragment_color;
                void main() {
                    fragment_color = texture(texture0, fragment_uv);
                }
                """
        )
        self.program['model'].write(bytes(np.eye(4, dtype=np.float32)))
        self.program['texture0'].value = 0

        self.vertex_array = self.init_vertex_array(self.ctx, self.program)

        image = Image.open('test.jpg').transpose(Image.FLIP_TOP_BOTTOM)
        self.texture = self.ctx.texture(image.size, 3, image.tobytes())
        self.texture.use()

    def render(self, time, frametime):
        self.ctx.clear()
        self.vertex_array.render()

    def init_vertex_array(self, context: moderngl.Context, program: moderngl.Program) -> moderngl.VertexArray:
        vertices_xy = self.get_vertices_for_quad_2d(size=(2.0, 2.0), bottom_left_corner=(-1.0, -1.0))
        vertex_buffer_xy = context.buffer(vertices_xy.tobytes())

        vertices_uv = self.get_vertices_for_quad_2d(size=(1.0, 1.0), bottom_left_corner=(0.0, 0.0))
        vertex_buffer_uv = context.buffer(vertices_uv.tobytes())

        vertex_array = context.vertex_array(program, [(vertex_buffer_xy, "2f", "vertex_xy"),
                                                      (vertex_buffer_uv, "2f", "vertex_uv")])
        return vertex_array

    def get_vertices_for_quad_2d(self, size=(2.0, 2.0), bottom_left_corner=(-1.0, -1.0)) -> np.array:
        # A quad is composed of 2 triangles: https://en.wikipedia.org/wiki/Polygon_mesh
        w, h = size
        x_bl, y_bl = bottom_left_corner
        vertices = np.array([x_bl,     y_bl + h,
                             x_bl,     y_bl,
                             x_bl + w, y_bl,

                             x_bl,     y_bl + h,
                             x_bl + w, y_bl,
                             x_bl + w, y_bl + h], dtype=np.float32)
        return vertices


if __name__ == '__main__':
    moderngl_window.run_window_config(Pygame, args=('--window', 'glfw'))

运行此程序时,您将看到以下窗口:

moderngl window with sky

现在,如果我们编辑render函数以添加角度:

def render(self, time, frametime):
    pitch_rad = 1
    rotate_around_y_pitch = np.array([[np.cos(pitch_rad), 0, np.sin(pitch_rad), 0],
                                      [0, 1, 0, 0],
                                      [-np.sin(pitch_rad), 0, np.cos(pitch_rad), 0],
                                      [0, 0, 0, 1]], dtype=np.float32)
    self.program['model'].write(bytes(rotate_around_y_pitch))

    self.ctx.clear()
    self.vertex_array.render()

然后投影的照片仍将是矩形(仅在纵横比发生变化时)而不是梯形

moderngl window with photo with bad angle

我错过了什么?


Tags: selfsizebuffernpwindowprogramarrayuv
1条回答
网友
1楼 · 发布于 2024-05-18 15:18:28

非常感谢@Grimmy提供了缺失的细节:

  1. 我应该使用projection矩阵

  2. 我应该把物体放在远离摄像机的地方

完整的工作代码:

import moderngl
import moderngl_window
import numpy as np
from PIL import Image

from pyrr import Matrix44


class Pygame(moderngl_window.WindowConfig):
    window_size = 1280, 720

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.program = self.ctx.program(
            vertex_shader="""
                #version 330
                in vec2 vertex_xy;
                in vec2 vertex_uv;
                uniform mat4 model;
                uniform mat4 projection;
                out vec2 fragment_uv; 
                void main() {
                    vec4 p = vec4(vertex_xy, 0.0, 1.0);
                    gl_Position = projection * model * p;
                    fragment_uv = vertex_uv;
                }
                """,
            fragment_shader="""
                #version 330
                in vec2 fragment_uv;
                uniform sampler2D texture0;
                out vec4 fragment_color;
                void main() {
                    fragment_color = texture(texture0, fragment_uv);
                }
                """
        )
        self.program['model'].write(bytes(np.eye(4, dtype=np.float32)))
        self.program['texture0'].value = 0

        self.vertex_array = self.init_vertex_array(self.ctx, self.program)

        image = Image.open('test.jpg').transpose(Image.FLIP_TOP_BOTTOM)
        self.texture = self.ctx.texture(image.size, 3, image.tobytes())
        self.texture.use()

    def render(self, time, frametime):
        pitch_rad = -1
        # Important! the -3 here positions the object far from the camera
        rotate_around_x_pitch = np.array([[1, 0, 0, 0],
                                          [0, np.cos(pitch_rad), -np.sin(pitch_rad), 0],
                                          [0, np.sin(pitch_rad), np.cos(pitch_rad), 0],
                                          [0, 0, -3, 1]], dtype=np.float32)

        projection = Matrix44.perspective_projection(45.0, self.aspect_ratio, 0.1, 1000.0, dtype="f4")
        self.program["projection"].write(projection)

        self.program['model'].write(bytes(rotate_around_x_pitch))

        self.ctx.clear()
        self.vertex_array.render()

    def init_vertex_array(self, context: moderngl.Context, program: moderngl.Program) -> moderngl.VertexArray:
        vertices_xy = self.get_vertices_for_quad_2d(size=(2.0, 2.0), bottom_left_corner=(-1.0, -1.0))
        vertex_buffer_xy = context.buffer(vertices_xy.tobytes())

        vertices_uv = self.get_vertices_for_quad_2d(size=(1.0, 1.0), bottom_left_corner=(0.0, 0.0))
        vertex_buffer_uv = context.buffer(vertices_uv.tobytes())

        vertex_array = context.vertex_array(program, [(vertex_buffer_xy, "2f", "vertex_xy"),
                                                      (vertex_buffer_uv, "2f", "vertex_uv")])
        return vertex_array

    def get_vertices_for_quad_2d(self, size=(2.0, 2.0), bottom_left_corner=(-1.0, -1.0)) -> np.array:
        # A quad is composed of 2 triangles: https://en.wikipedia.org/wiki/Polygon_mesh
        w, h = size
        x_bl, y_bl = bottom_left_corner
        vertices = np.array([x_bl,     y_bl + h,
                             x_bl,     y_bl,
                             x_bl + w, y_bl,

                             x_bl,     y_bl + h,
                             x_bl + w, y_bl,
                             x_bl + w, y_bl + h], dtype=np.float32)
        return vertices


if __name__ == '__main__':
    moderngl_window.run_window_config(Pygame, args=(' window', 'glfw'))

enter image description here

相关问题 更多 >

    热门问题