【问题标题】:Moderngl: project photo with angleModerngl:带角度的投影照片
【发布时间】:2021-04-19 12:03:40
【问题描述】:

我正在尝试以某个角度投影照片。

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

现在假设相机有点向上看,比如pitch=1 radians,那么照片实际上是在捕捉梯形而不是矩形:

现在让我们来看看代码 - 这是一个简单的程序,它使用 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'))

当你运行这个程序时,你会看到这个窗口:

现在,如果我们编辑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()

那么投影的照片仍将是矩形(只是纵横比有所变化)而不是梯形

我错过了什么?

【问题讨论】:

    标签: python opengl graphics glsl python-moderngl


    【解决方案1】:

    非常感谢@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'))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      • 2015-06-29
      相关资源
      最近更新 更多