1

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

如果照片是在相机直视前方时拍摄的,则相机角度 ( yaw, pitch, roll) 都为零。

现在让我们说相机有点向上看,假设用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'))

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

与天空的moderngl窗口

现在,如果我们编辑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 窗口,带有不良角度的照片

我错过了什么?

4

1 回答 1

2

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

在此处输入图像描述

于 2021-04-19T13:12:39.933 回答