1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

gliumで3D表示するサンプル

Posted at

概要

gliumはRustでOpenGLを扱うライブラリです。

しかし、Qiitaを探してみても、GUIはあれど肝心の3Dの表示サンプルがない...。

ということで、サンプルと、はまりどころをメモ程度に残しておきます。

完成品

スクリーンショット 2021-08-29 165722.png
以下のコードを実行すると、xyzの3軸、メッシュ、x=10, z=10 の直角三角形を y 方向に 1 ずらしたものが表示されます。

ソースコード

main.rs
# [macro_use]
extern crate glium;

fn main() {
    #![allow(unused_imports)]
    use glium::{glutin, Surface};

    #[derive(Copy, Clone)]
    pub struct Vertex {
        position: (f32, f32, f32)
    }
    implement_vertex!(Vertex, position);

    let 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();

    const TRIANGLE_SHAPE: [Vertex;3] = [
        Vertex { position: (0.0, 1.0, 10.0) },
        Vertex { position: (10.0, 1.0, 0.0) },
        Vertex { position: (0.0, 1.0, 0.0) },
    ];

    let triangle_positions = glium::VertexBuffer::new(&display, &TRIANGLE_SHAPE).unwrap();
    let triangle_indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    const AXIS_LEN:f32 = 20.0;
    const LINE_X: [Vertex;2] = [
        Vertex { position: (-AXIS_LEN, 0.0, 0.0) },
        Vertex { position: (AXIS_LEN, 0.0, 0.0) },
    ];
    let line_x = glium::VertexBuffer::new(&display, &LINE_X).unwrap();

    const LINE_Y: [Vertex;2] = [
        Vertex { position: (0.0, -AXIS_LEN, 0.0) },
        Vertex { position: (0.0, AXIS_LEN, 0.0) },
    ];
    let line_y = glium::VertexBuffer::new(&display, &LINE_Y).unwrap();

    const LINE_Z: [Vertex;2] = [
        Vertex { position: (0.0, 0.0, -AXIS_LEN) },
        Vertex { position: (0.0, 0.0, AXIS_LEN) },
    ];
    let line_z = glium::VertexBuffer::new(&display, &LINE_Z).unwrap();
    let line_indices = glium::index::NoIndices(glium::index::PrimitiveType::LinesList);

    const MESH_LINES: [Vertex; 80] = [
        Vertex { position: (-10.0, 0.0, -10.0) },
        Vertex { position: ( 10.0, 0.0, -10.0) },
        Vertex { position: (-10.0, 0.0,  -9.0) },
        Vertex { position: ( 10.0, 0.0,  -9.0) },
        Vertex { position: (-10.0, 0.0,  -8.0) },
        Vertex { position: ( 10.0, 0.0,  -8.0) },
        Vertex { position: (-10.0, 0.0,  -7.0) },
        Vertex { position: ( 10.0, 0.0,  -7.0) },
        Vertex { position: (-10.0, 0.0,  -6.0) },
        Vertex { position: ( 10.0, 0.0,  -6.0) },
        Vertex { position: (-10.0, 0.0,  -5.0) },
        Vertex { position: ( 10.0, 0.0,  -5.0) },
        Vertex { position: (-10.0, 0.0,  -4.0) },
        Vertex { position: ( 10.0, 0.0,  -4.0) },
        Vertex { position: (-10.0, 0.0,  -3.0) },
        Vertex { position: ( 10.0, 0.0,  -3.0) },
        Vertex { position: (-10.0, 0.0,  -2.0) },
        Vertex { position: ( 10.0, 0.0,  -2.0) },
        Vertex { position: (-10.0, 0.0,  -1.0) },
        Vertex { position: ( 10.0, 0.0,  -1.0) },
        Vertex { position: (-10.0, 0.0,  10.0) },
        Vertex { position: ( 10.0, 0.0,  10.0) },
        Vertex { position: (-10.0, 0.0,   9.0) },
        Vertex { position: ( 10.0, 0.0,   9.0) },
        Vertex { position: (-10.0, 0.0,   8.0) },
        Vertex { position: ( 10.0, 0.0,   8.0) },
        Vertex { position: (-10.0, 0.0,   7.0) },
        Vertex { position: ( 10.0, 0.0,   7.0) },
        Vertex { position: (-10.0, 0.0,   6.0) },
        Vertex { position: ( 10.0, 0.0,   6.0) },
        Vertex { position: (-10.0, 0.0,   5.0) },
        Vertex { position: ( 10.0, 0.0,   5.0) },
        Vertex { position: (-10.0, 0.0,   4.0) },
        Vertex { position: ( 10.0, 0.0,   4.0) },
        Vertex { position: (-10.0, 0.0,   3.0) },
        Vertex { position: ( 10.0, 0.0,   3.0) },
        Vertex { position: (-10.0, 0.0,   2.0) },
        Vertex { position: ( 10.0, 0.0,   2.0) },
        Vertex { position: (-10.0, 0.0,   1.0) },
        Vertex { position: ( 10.0, 0.0,   1.0) },
        
        Vertex { position: (-10.0, 0.0, -10.0) },
        Vertex { position: (-10.0, 0.0,  10.0) },
        Vertex { position: ( -9.0, 0.0, -10.0) },
        Vertex { position: ( -9.0, 0.0,  10.0) },
        Vertex { position: ( -8.0, 0.0, -10.0) },
        Vertex { position: ( -8.0, 0.0,  10.0) },
        Vertex { position: ( -7.0, 0.0, -10.0) },
        Vertex { position: ( -7.0, 0.0,  10.0) },
        Vertex { position: ( -6.0, 0.0, -10.0) },
        Vertex { position: ( -6.0, 0.0,  10.0) },
        Vertex { position: ( -5.0, 0.0, -10.0) },
        Vertex { position: ( -5.0, 0.0,  10.0) },
        Vertex { position: ( -4.0, 0.0, -10.0) },
        Vertex { position: ( -4.0, 0.0,  10.0) },
        Vertex { position: ( -3.0, 0.0, -10.0) },
        Vertex { position: ( -3.0, 0.0,  10.0) },
        Vertex { position: ( -2.0, 0.0, -10.0) },
        Vertex { position: ( -2.0, 0.0,  10.0) },
        Vertex { position: ( -1.0, 0.0, -10.0) },
        Vertex { position: ( -1.0, 0.0,  10.0) },
        Vertex { position: ( 10.0, 0.0, -10.0) },
        Vertex { position: ( 10.0, 0.0,  10.0) },
        Vertex { position: (  9.0, 0.0, -10.0) },
        Vertex { position: (  9.0, 0.0,  10.0) },
        Vertex { position: (  8.0, 0.0, -10.0) },
        Vertex { position: (  8.0, 0.0,  10.0) },
        Vertex { position: (  7.0, 0.0, -10.0) },
        Vertex { position: (  7.0, 0.0,  10.0) },
        Vertex { position: (  6.0, 0.0, -10.0) },
        Vertex { position: (  6.0, 0.0,  10.0) },
        Vertex { position: (  5.0, 0.0, -10.0) },
        Vertex { position: (  5.0, 0.0,  10.0) },
        Vertex { position: (  4.0, 0.0, -10.0) },
        Vertex { position: (  4.0, 0.0,  10.0) },
        Vertex { position: (  3.0, 0.0, -10.0) },
        Vertex { position: (  3.0, 0.0,  10.0) },
        Vertex { position: (  2.0, 0.0, -10.0) },
        Vertex { position: (  2.0, 0.0,  10.0) },
        Vertex { position: (  1.0, 0.0, -10.0) },
        Vertex { position: (  1.0, 0.0,  10.0) },
    ];
    let mesh_lines = glium::VertexBuffer::new(&display, &MESH_LINES).unwrap();

    let vertex_shader_src = r#"
        #version 150
        in vec3 position;
        out vec3 col;
        out vec3 v_position;
        uniform vec3 color;
        uniform mat4 perspective;
        uniform mat4 view;
        uniform mat4 model;
        void main() {
            mat4 modelview = view * model;
            gl_Position = perspective * modelview * vec4(position, 1.0);
            col = color;
        }
    "#;

    let fragment_shader_src = r#"
        #version 150
        in vec3 col;
        out vec4 color;
        void main() {
            color = vec4(col, 1);
        }
    "#;

    let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src,
                                              None).unwrap();

    event_loop.run(move |event, _, control_flow| {
        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);

        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 mut target = display.draw();
        target.clear_color_and_depth((0.8, 0.8, 0.8, 1.0), 1.0);

        let model = [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32]
        ];

        let view = view_matrix(&[10.0, 20.0, -20.0], &[-10.0, -20.0, 20.0], &[0.0, 1.0, 0.0]);

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

            let fov: f32 = 3.141592 / 4.0; //視野角45度
            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 light = [1.4, 0.4, -0.7f32];

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };


        target.draw(&triangle_positions, &triangle_indices, &program,
                    &uniform! { model: model, view: view, perspective: perspective, u_light: light, color: [1.0, 0.0, 0.0f32] },
                    &params).unwrap();
        
        target.draw(&line_x, &line_indices, &program,
            &uniform! { model: model, view: view, perspective: perspective, u_light: light, color: [1.0, 0.0, 0.0f32] },
            &params).unwrap();

        target.draw(&line_y, &line_indices, &program,
            &uniform! { model: model, view: view, perspective: perspective, u_light: light, color: [0.0, 1.0, 0.0f32] },
            &params).unwrap();

        target.draw(&line_z, &line_indices, &program,
            &uniform! { model: model, view: view, perspective: perspective, u_light: light, color: [0.0, 0.0, 1.0f32] },
            &params).unwrap();

        target.draw(&mesh_lines, &line_indices, &program,
            &uniform! { model: model, view: view, perspective: perspective, u_light: light, color: [0.3, 0.3, 0.3f32] },
            &params).unwrap();

        target.finish().unwrap();
    });
}


fn view_matrix(position: &[f32; 3], direction: &[f32; 3], up: &[f32; 3]) -> [[f32; 4]; 4] {
    let f = {
        let f = direction;
        let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2];
        let len = len.sqrt();
        [f[0] / len, f[1] / len, f[2] / len]
    };

    let s = [up[1] * f[2] - up[2] * f[1],
             up[2] * f[0] - up[0] * f[2],
             up[0] * f[1] - up[1] * f[0]];

    let s_norm = {
        let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2];
        let len = len.sqrt();
        [s[0] / len, s[1] / len, s[2] / len]
    };

    let u = [f[1] * s_norm[2] - f[2] * s_norm[1],
             f[2] * s_norm[0] - f[0] * s_norm[2],
             f[0] * s_norm[1] - f[1] * s_norm[0]];

    let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
             -position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
             -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]];

    [
        [s_norm[0], u[0], f[0], 0.0],
        [s_norm[1], u[1], f[1], 0.0],
        [s_norm[2], u[2], f[2], 0.0],
        [p[0], p[1], p[2], 1.0],
    ]
}

はまりどころ

はまった点は2つありました。

1つ目は、gliumはOpenGLなのにも関わらず 「左手系」 です。
(もしかしたら書き方次第でどうにかなるかもしれないです)
上記の例でもz軸の正方向が画面奥になっています。
少し勝手が違うので、注意する必要があります。

2つ目はVAOのサンプルが皆無ということです。
OpenGLで大量の点を扱うとなると、高速表示のためにもデータの受け渡しの効率化が必須です。
VAOは実装されているように見えるのですが、少し探してもサンプル等見当たらなかったので、本格的に使えるようになるまで、調べたりなんだりで結構かかるのではないかと思います。
上記の例でも、VAOで軸と色をまとめて渡したかったのですが、泣く泣くあきらめています。

最後に

gliumについてざっとしか調べていませんが、gliumのサンプル自体が少なかったのでメモ程度に残してみました。

メッシュの座標、どうにかならなかったんかい

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?