Perspective

7242 ワード

https://github.com/glium/glium/blob/master/book/tuto-10-perspective.md
水筒を描くときにシェーダに渡される行列には、水筒モデルの位置、回転、サイズが含まれます.

Column Major


OpenGLでは、行列はColumn Major

例)

AddressRow-major OrderColumn-major order0a[1, 1]a[1, 1]1a[1, 2]a[2, 1]2a[1, 3]a[1, 2]3a[2, 1]a[2, 2]4a[2, 2]a[1, 3]5a[2, 3]a[2, 3]
以前の内容では,z成分の増加または減少が変化しなかったのは直交投影に起因した.

Correcting the perspective


遠くの物体をより小さく見せるには、x座標とy座標をz座標に分けるだけです.
z座標はゼロにすることができるので、頂点シェーダ演算後にw値で除算する
原点がスクリーンの中央にあるため、距離が遠い物体ほどスクリーンの原点に近づくように見えます

Aspect ratio


現在、レンダリングされたイメージはウィンドウサイズの増加に伴って減少します.
-1~1の座標は、ウィンドウの幅または高さに一致するため、通常の状態です.
画面の高さ/幅にx座標を乗じて、ウィンドウの幅や幅が変化したときに画面に表示される内容が大きくなったり小さくなったりしないようにすることができます.

Introducing the perspective matrix

let perspective = {
    let (width, height) = target.get_dimensions();
    let aspect_ratio = height as f32 / width as f32;

    let fov: f32 = 3.141592 / 3.0;
    let zfar = 1024.0;
    let znear = 0.1;

    let f = 1.0 / (fov / 2.0).tan();

    [
        [f * aspect_ratio,    0.0,              0.0              , 0.0],
        [       0.0      ,     f ,              0.0              , 0.0],
        [       0.0      ,    0.0,  (zfar+znear)/(zfar-znear)    , 1.0],
        [       0.0      ,    0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0],
    ]
};
パース投影マトリクスを作成するには4つのパラメータが必要です
  • aspect ratio = height/width
  • fov:カメラ目線
  • znear:カメラ視野角の最小深さ
  • zfar:カメラ視野角の最大深さ
  • 頂点シェーダを修正するには
    #version 140
    
    in vec3 position;
    in vec3 normal;
    
    out vec3 v_normal;
    
    uniform mat4 perspective;       // new
    uniform mat4 matrix;
    
    void main() {
        v_normal = transpose(inverse(mat3(matrix))) * normal;
        gl_Position = perspective * matrix * vec4(position, 1.0);       // new
    }
    drawコードの変更
    target.draw((&positions, &normals), &indices, &program,
                &uniform! { matrix: matrix, perspective: perspective, u_light: light },
                &params).unwrap();
    マトリックスの修正
    let matrix = [
        [0.01, 0.0, 0.0, 0.0],
        [0.0, 0.01, 0.0, 0.0],
        [0.0, 0.0, 0.01, 0.0],
        [0.0, 0.0, 2.0, 1.0f32]
    ];
    完全なコード
    #[macro_use]
    extern crate glium;
    
    mod teapot;
    
    fn main() {
        #[allow(unused_imports)]
        use glium::{glutin, Surface};
    
        let mut event_loop = glutin::event_loop::EventLoop::new();
        let wb = glutin::window::WindowBuilder::new();
        let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
        let display = glium::Display::new(wb, cb, &event_loop).unwrap();
    
        let positions = glium::VertexBuffer::new(&display, &teapot::VERTICES).unwrap();
        let normals = glium::VertexBuffer::new(&display, &teapot::NORMALS).unwrap();
        let indices = glium::IndexBuffer::new(
            &display,
            glium::index::PrimitiveType::TrianglesList,
            &teapot::INDICES,
        )
        .unwrap();
    
        let light = [-1.0, 0.4, 0.9f32];
    
        let vertex_shader_src = r#"
        #version 150      // updated
    
        in vec3 position;
        in vec3 normal;
        
        out vec3 v_normal;
        
        uniform mat4 perspective;       // new
        uniform mat4 matrix;
        
        void main() {
            v_normal = transpose(inverse(mat3(matrix))) * normal;
            gl_Position = perspective * matrix * vec4(position, 1.0);       // new
        }
    "#;
    
        let fragment_shader_src = r#"
        #version 140
    
        in vec3 v_normal;
        out vec4 color;
        uniform vec3 u_light;
    
        void main() {
            float brightness = dot(normalize(v_normal), normalize(u_light));
            vec3 dark_color = vec3(0.6, 0.0, 0.0);
            vec3 regular_color = vec3(1.0, 0.0, 0.0);
            color = vec4(mix(dark_color, regular_color, brightness), 1.0);
        }
    "#;
    
        let program =
            glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
                .unwrap();
    
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };
    
        let mut t: f32 = -0.5;
        event_loop.run(move |event, _, control_flow| {
            match event {
                glutin::event::Event::WindowEvent { event, .. } => match event {
                    glutin::event::WindowEvent::CloseRequested => {
                        *control_flow = glutin::event_loop::ControlFlow::Exit;
                        return;
                    }
                    _ => return,
                },
                glutin::event::Event::NewEvents(cause) => match cause {
                    glutin::event::StartCause::ResumeTimeReached { .. } => (),
                    glutin::event::StartCause::Init => (),
                    _ => return,
                },
                _ => return,
            }
    
            let next_frame_time =
                std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
            *control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);
    
            t += 0.002;
            if t > 0.5 {
                t = -0.5;
            }
    
            let mut target = display.draw();
            target.clear_color_and_depth((0.3, 0.5, 0.7, 1.0), 1.0);
    
            let perspective = {
                let (width, height) = target.get_dimensions();
                let aspect_ratio = height as f32 / width as f32;
        
                let fov: f32 = 3.141592 / 3.0;
                let zfar = 1024.0;
                let znear = 0.1;
        
                let f = 1.0 / (fov / 2.0).tan();
        
                [
                    [f *   aspect_ratio   ,    0.0,              0.0              ,   0.0],
                    [         0.0         ,     f ,              0.0              ,   0.0],
                    [         0.0         ,    0.0,  (zfar+znear)/(zfar-znear)    ,   1.0],
                    [         0.0         ,    0.0, -(2.0*zfar*znear)/(zfar-znear),   0.0],
                ]
            };
            
            let uniforms = uniform! {
                // matrix: [
                //     [ t.cos(), t.sin(), 0.0, 0.0],
                //     [-t.sin(), t.cos(), 0.0, 0.0],
                //     [0.0, 0.0, 1.0, 0.0],
                //     [0.0, 0.0, 0.0, 1.0f32],
                // ]
                matrix: [
                    [0.01, 0.0, 0.0, 0.0],
                    [0.0, 0.01, 0.0, 0.0],
                    [0.0, 0.0, 0.01, 0.0],
                    [0.0, 0.0, 2.0, 1.0f32]
                ],
                perspective: perspective,
                u_light: light
            };
            
            target
                .draw(
                    (&positions, &normals),
                    &indices,
                    &program,
                    &uniforms,
                    &params,
                )
                .unwrap();
            target.finish().unwrap();
        });
    }