blog.monophile.net

コンピュータのこととかのメモ。

Takaaki Yamamoto

東京工業大学において計算機科学と応用数学を学び、 情報科学芸術大学院大学[IAMAS] においてメディア表現を専攻し修了。 現在は digitiminimi Inc. において、インフラエンジニアとして生計をたててている。

work

各種システム構築と管理を承ります。

Cloud PlatformOpenstack, GCP, AWS, Azure, ...
Openstackkeystone, glance, cinder, swift, neutron, nova, ...
VirtualizationQEMU+KVM, LXD/LXC, Docker, ...
OSDebian GNU/Linux, Ubuntu, CentOS, ...
NetworksIPSec, L2TP, VXLAN, WirelessAP, ...
WebAppsWordPress, GitLab, Redmine, ...
Configuration ManagementAnsible, Terraform, ...
MonitoringNagios, Munin, ...

posts

DartとWebGLでマンデルブロ集合

概要

GLSLとフラクタルの勉強をしていて、 試しにマンデルブロ集合をDartとWebGLで描いてみました。 マウスでちょっとだけグリグリできます。 デモはこちら(http://sandbox.monophile.net/)で見れます。

code

外部のライブラリなどは使っていないので、 以下のコードをコピペするだけで動きます。 (コードの説明は時間ができたときに記載します。)

mandelbrot.html

<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Webgl</title>

    <script async type="application/dart" src="mandelbrot.dart"></script>
    <script async src="packages/browser/dart.js"></script>
  </head>
  <body>
    <canvas id="main"></canvas>
  </body>
</html>
library mandelbrot;
import 'dart:html';
import 'dart:web_gl' as gl;
import 'dart:typed_data' as typed;

String GET(String url) {
  return (new HttpRequest()
      ..open("GET", url, async: false)
      ..send()).responseText;
}

typed.Float32List s2fs(String s) =>
    new typed.Float32List.fromList(
        s.split(",").map(double.parse).toList());
typed.Uint16List s2is(String s) =>
    new typed.Uint16List.fromList(
        s.split(",").map(int.parse).toList());

gl.Shader makeShader(gl.RenderingContext ctx, String src, int type) {
  gl.Shader shader = ctx.createShader(type);
  ctx.shaderSource(shader, src);
  ctx.compileShader(shader);
  if (ctx.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    return shader;
  } else {
    var message = ctx.getShaderInfoLog(shader);
    throw new Exception("Failed to compile vertex shader: $message");
  }
}

gl.Program makeProgram(gl.RenderingContext ctx, List<gl.Shader> shaders) {
  gl.Program program = ctx.createProgram();
  shaders.forEach((shader) => ctx.attachShader(program, shader));
  ctx.linkProgram(program);
  if (ctx.getProgramParameter(program, gl.LINK_STATUS)) {
    ctx.useProgram(program);
    return program;
  } else {
    var message = ctx.getProgramInfoLog(program);
    throw new Exception("Failed to link program $message");
  }
}

gl.Program mandelbrotProgram(gl.RenderingContext ctx) {
  const VERTEX_SHADER_SOURCE = """
        attribute vec3 position;
        void main(void){
            gl_Position = vec4(position, 1.0);
        }
        """;
  const FRAGMENT_SHADER_SOURCE = """
        precision highp float;
        uniform vec2  point;
        uniform vec2  resolution;
        const int ITERATION = 200;
        const vec3 white = vec3(1., 1., 1.);
        float min(vec2 e){ return min(e.x, e.y); }
        void main(void){
            vec2 p = (gl_FragCoord.xy * 2.0 - resolution)/min(resolution);
            vec2 z = vec2(0.0, 0.0);
            int count = 0;
            for(int j = 0; j < int(ITERATION); j++){
                if(length(z) > 2.0)
                  break;
                z = vec2( z.x*z.x - z.y*z.y + point.x*2.*z.x*z.y,
                         (1. - point.y)*2.*z.x*z.y) + p;
                count++;
            }
            float brightness = sin(float(count)/float(ITERATION)*100.);
            gl_FragColor = vec4(vec3(brightness),1.);
        }
        """;
  gl.Shader vert =
        makeShader(ctx, VERTEX_SHADER_SOURCE, gl.VERTEX_SHADER);
  gl.Shader frag =
        makeShader(ctx, FRAGMENT_SHADER_SOURCE, gl.FRAGMENT_SHADER);
  gl.Program program = makeProgram(ctx, <gl.Shader>[vert, frag]);
  typed.Float32List vertices = s2fs("""
        -1.0,  1.0,  0.0,
         1.0,  1.0,  0.0,
        -1.0, -1.0,  0.0,
         1.0, -1.0,  0.0""");
  gl.Buffer vBuf = ctx.createBuffer();
  int vAttrLoc = ctx.getAttribLocation(program, "position");
  ctx.bindBuffer(gl.ARRAY_BUFFER, vBuf);
  ctx.enableVertexAttribArray(vAttrLoc);
  ctx.vertexAttribPointer(vAttrLoc, 3, gl.FLOAT, false, 0, 0);
  ctx.bufferDataTyped(gl.ARRAY_BUFFER, vertices, gl.STREAM_DRAW);
  typed.Uint16List vindices = s2is("""0, 2, 1, 1, 2, 3""");
  gl.Buffer iBuf = ctx.createBuffer();
  ctx.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuf);
  ctx.bufferDataTyped(gl.ELEMENT_ARRAY_BUFFER, vindices, gl.STATIC_DRAW);
  return program;
}

void draw(gl.RenderingContext ctx, gl.Program program, Point p) {
  ctx.clearColor(1.0, 0.0, 0.0, 1);
  ctx.clear(gl.COLOR_BUFFER_BIT);
  gl.UniformLocation point =
        ctx.getUniformLocation(program, "point");
  gl.UniformLocation resolution =
        ctx.getUniformLocation(program, "resolution");
  String _point = "${p.x / ctx.canvas.width}, ${p.y / ctx.canvas.height}";
  ctx.uniform2fv(point, s2fs(_point));
  ctx.uniform2fv(resolution, s2fs("${ctx.canvas.width}, ${ctx.canvas.height}"));
  ctx.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
  ctx.flush();
}

void main() {
  CanvasElement canvas = querySelector("#main");
  document.onKeyDown.listen((KeyboardEvent e) {
    if (e.keyCode == KeyCode.F) canvas.requestFullscreen();
  });

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  gl.RenderingContext ctx = canvas.getContext3d();
  gl.Program program = mandelbrotProgram(ctx);
  draw(ctx, program, new Point(0, 0));

  canvas.onMouseMove.listen((MouseEvent e) {
    print("${e.client},${e.movement},${e.offset}");
    draw(ctx, program, e.offset);
  });
}

reference