만델브로 집합 다시

18414 단어 GLSLOpenGLRust

Previous



만델브로 집합
이전 ruby로 그린 것이 여기

400x400의 150프레임의 gif를 그리는데 30분 가까이 걸려 있었고, 루비로 하는 것이 아니라는 느낌이었습니다만 최근 rust 재차 입문했기 때문에 연습제재에 좋을까라고 생각하고 있었는데, scivola씨에게 앞으로 넘어 졌기 때문에 조금 다른 것을

scivola씨의 물건은, 주기적인 색채, 깔끔한 확대점, 마지막으로 최초의 모양이 나와 깨끗한 애니메이션입니다
Rust에서 만델브로 세트의 줌 애니메이션

같은 일을 해도 어쩔 수 없기 때문에
좀더 자유롭게 만델브로 집합을 여행할 수 있도록 하려고
그래서 OpenGL을 사용한 대화 형 묘사를 시도합니다.

손으로 움직이고 싶은 분은 여기를 cargo runMacOS에서만 작동 확인하고, 산만큼 라이브러리가 설치됩니다.
소스

코드



rust OpenGL의 type safe binding인 glium
윈도우나 인풋 등의 이벤트를 매니지해 주는 glutin
이 두 개의 크레이트를 사용합니다.

옛날 c로 그렸을 때는 여러가지 초기화나 컴파일이나 링크나 바인딩이나
어쩐지 귀찮았던 것이 너무 쉬워진다니, 훌륭합니다.

그런데, 중요한 발산 판정입니다만 rust가 아니라 GLSL(단편 쉐이더)로 쓰고 있습니다
정확한 벤치마크는 없지만 체감으로는 GLSL이 더 빨리 느껴집니다.

만델브로 집합 여행으로
자유롭게 이동, 확대/축소, 밀도 변경, 계산 정확도 변경
  • 화살표 키: 중심 이동
  • Enter: 확대
  • Backspace/Delete: 축소
  • z : 정확도 증가
  • x : 정확도 감소
  • c: 밀도 증가
  • v : 밀도 감소

  • 디폴트에서는 밀도, 정밀도 모두 꽤 낮게 설정하고 있으므로 CPU나 GPU와 상담 후 적당하게 조정해 보세요
    #[macro_use]
    extern crate glium;
    use glium::{DisplayBuild, Surface, Program};
    use glium::{glutin, index, vertex};
    
    #[derive(Copy, Clone)]
    struct Vertex {
      pos: [f64; 2]
    }
    
    implement_vertex!(Vertex, pos);
    
    fn vertexs(range_y: f64, range_x: f64, density: f64) -> Vec<Vertex> {
      let mut vs = vec!();
      let mut y: f64 = -range_y;
    
      while y < range_y {
        let mut x: f64 = -range_x;
    
        while x < range_x {
          vs.push(Vertex { pos: [x,y] });
          x += density;
        }
    
        y += density;
      }
    
      return vs;
    }
    
    fn main() {
      let display = glutin::WindowBuilder::new().build_glium().unwrap();
    
      let program = Program::from_source(
        &display, 
        r#"
          #version 400
    
          in vec2 pos;
          out vec2 p;
    
          void main() {
            p = pos;
            gl_Position = vec4(pos, 0.0, 1.0);
          }
        "#, 
    
        r#"
          #version 400
    
          in vec2 p;
          out vec4 color;
    
          uniform double max;
          uniform double scale;
          uniform double center_y;
          uniform double center_x;
    
          vec2 mandelbrot(double a, double b) {
            double y = 0;
            double x = 0;
            for (double n = 0; n < max; n++) {
              double yy = 2 * x * y + b;
              double xx = x * x - y * y + a;
              y = yy;
              x = xx;
    
              if (sqrt(y * y + x * x) > 4.0) {
                return vec2(true, n / max);
              }
            }
    
            return vec2(false, max / max);
          }
    
          void main() {
            double x = center_x + p.x * scale;
            double y = center_y + p.y * scale;
            vec2 m = mandelbrot(x, y);
            if (bool(m.x)) { 
              color = vec4(m.y, m.y, m.y, m.y);
            }
            else {
              color = vec4(0.0, 0.0, 0.0, 0.0);
            }
          }
        "#, 
    
        None
      );
    
      if let Err(msg) = program {
        println!("{}", msg); 
        return;
      }
      let program = program.unwrap();
    
      let index = index::NoIndices(index::PrimitiveType::Points);
    
      let mut density: f64 = 0.01;
      let mut max: f64 = 100.0;
      let mut scale: f64 = 3.0;
      let mut center_y: f64 = 0.0;
      let mut center_x: f64 = 0.0;
    
      loop {
        let vertex_buffer = vertex::VertexBuffer::new(
          &display, &vertexs(1.0, 1.0, density)
        ).unwrap();
    
        let mut frame = display.draw();
        frame.clear_color(0.0, 0.0, 0.0 ,0.0);
    
        for e in display.wait_events() {
          match e {
            glutin::Event::KeyboardInput(
              glutin::ElementState::Pressed, _, Some(keycode)
            ) => {
              println!("{:?}", e);
              match keycode {
                glutin::VirtualKeyCode::Up => {
                  center_y += 0.05 * scale; 
                },
    
                glutin::VirtualKeyCode::Down => {
                  center_y -= 0.05 * scale;
                },
    
                glutin::VirtualKeyCode::Left => {
                  center_x -= 0.05 * scale;
                },
    
                glutin::VirtualKeyCode::Right => {
                  center_x += 0.05 * scale;
                },
    
                glutin::VirtualKeyCode::Return => {
                  scale *= 0.9;
                },
    
                glutin::VirtualKeyCode::Back => {
                  scale /= 0.9;
                },
    
                glutin::VirtualKeyCode::Z => {
                  max += 1.0;
                },
    
                glutin::VirtualKeyCode::X => {
                  max -= 1.0;
                },
    
                glutin::VirtualKeyCode::C => {
                  if density > 0.002 {
                    density *= 0.9
                  }
                },
    
                glutin::VirtualKeyCode::V => {
                  density /= 0.9;
                },
    
                glutin::VirtualKeyCode::Escape => {
                  frame.finish().unwrap();
                  return
                },
    
                _ => {}
              }
    
            },
    
            _ => break
          }
        }
    
        let uniforms = uniform! {
          max: max,
          scale: scale,
          center_y: center_y,
          center_x: center_x,
        };
    
        println!("{} {} {} {} {}", center_y, center_x, scale, max, density);
    
        frame.draw(&vertex_buffer, &index, &program, &uniforms, &Default::default()).unwrap();
        frame.finish().unwrap();
      }
    }
    

    Result





    음, GIF는 이해하기 어렵기 때문에 손으로 움직여보고 싶습니다.

    좋은 웹페이지 즐겨찾기