WebGL(2D) - 入門編 - 6日目: 線の先端を丸くする(round)

# 目標

線の先端を丸くする(round)

<img width="467" alt="スクリーンショット 2016-07-13 19.58.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/80502/f11b8628-6c25-ff71-d848-e0390a1f71a3.png">




# WebGL開始。

```js:study.js
var w = 400; // 幅
var h = 400; // 高さ
var canvas = document.getElementById("canvas");
canvas.width = w;
canvas.height = h;
var gl = canvas.getContext("webgl");
```


# 座標セット

```js:study.js
// 始点
var x = 50; // x座標
var y = 280; // y座標

// 終点
var dx = 350; // x座標
var dy = 130; // y座標

// 線太さ
var lineWidth = 100;
```


# 始点と終点から4点の座標をセット

座標の詳細はこちら
[WebGL(2D) - 入門編 - 2日目: 線の太さをコントロールする](http://qiita.com/ienaga/items/f0392e1aaf41651ace7a)

```js:study.js
// 始点と終点の角度を取得
var angle = Math.atan2(y - dy, x - dx) / (Math.PI / 180) * -1;

// border
var lw = lineWidth + 1;

// 4点の座標をセット
var x1 = x + Math.cos((angle + 270) * Math.PI / 180) * lw / 2;
var y1 = y + Math.sin((angle + 270) * Math.PI / 180) * lw / 2 * -1;

var x2 = dx + Math.cos((angle + 270) * Math.PI / 180) * lw / 2;
var y2 = dy + Math.sin((angle + 270) * Math.PI / 180) * lw / 2 * -1;

var x3 = dx + Math.cos((angle + 90) * Math.PI / 180) * lw / 2;
var y3 = dy + Math.sin((angle + 90) * Math.PI / 180) * lw / 2 * -1;

var x4 = x + Math.cos((angle + 90) * Math.PI / 180) * lw / 2;
var y4 = y + Math.sin((angle + 90) * Math.PI / 180) * lw / 2 * -1;

var vertices = [
    (x1-(w/2))/(w/2), -(y1-(h/2))/(h/2),
    (x2-(w/2))/(w/2), -(y2-(h/2))/(h/2),
    (x3-(w/2))/(w/2), -(y3-(h/2))/(h/2),
    (x4-(w/2))/(w/2), -(y4-(h/2))/(h/2)
];
```



# 初期化

```js:study.js
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
```


# alphaを有効にする

```js:study.js
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
```


# 空のバッファオブジェクトを生成

```js:study.js
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
```

# バーテックス(頂点)シェーダー

```js:study.js
var vSource = [
    "precision mediump float;",
    "attribute vec2 vertex;",
    "void main(void) {",
        "gl_Position = vec4(vertex, 0.0, 1.0);",
    "}"
].join("\n");

var vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader, vSource);
gl.compileShader(vShader);
gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
```

# フラグメントシェーダー


```js:study.js
var rgba = [0.0, 0.0, 0.0, 1.0]; // Red, Green, Blue, Alpha

// 4点からzを算出
function edge (x0, y0, x1, y1, h)
{
    var x = x1 - x0;
    var y = y1 - y0;
    var _y0 = (h - y0);
    var _y1 = (h - y1);

    var edges = [];
    var scale = 1.0 / Math.sqrt(x * x + y * y);
    edges[edges.length] = (_y0 - _y1) * scale;
    edges[edges.length] = (x1 - x0) * scale;
    edges[edges.length] = (x0 * _y1 - x1 * _y0) * scale;
    return edges;
}

var e0 = edge(x2, y2, x1, y1, h);
var e1 = edge(x4, y4, x3, y3, h);

var fSource = [
    "precision mediump float;",
    "void main(void) {",
        "vec3 pos = vec3(gl_FragCoord.xy, 1.0);",
        "float a0 = clamp(dot(vec3("+ e0.join(",") +"), pos), 0.0, 1.0);",
        "float a1 = clamp(dot(vec3("+ e1.join(",") +"), pos), 0.0, 1.0);",
        "gl_FragColor = vec4("+ rgba.join(",") +") * min(a0, a1);",
    "}"
].join("\n");

var fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader, fSource);
gl.compileShader(fShader);
gl.getShaderParameter(fShader, gl.COMPILE_STATUS);
```

# プログラムオブジェクトの生成

```js:study.js
var program = gl.createProgram();
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
gl.linkProgram(program);
gl.getProgramParameter(program, gl.LINK_STATUS);
gl.useProgram(program);
```

# シェーダー側の変数をjs側で受け受け取る

```js:study.js
var vertex = gl.getAttribLocation(program, "vertex");
gl.enableVertexAttribArray(vertex);
gl.vertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0);
```



# 線の描画

```js:study.js
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertices.length/2);
```


# 先端の三角形の長さを取得する
![image1.png](https://qiita-image-store.s3.amazonaws.com/0/80502/a9eed7c5-c37b-e4b1-04f4-570137bf43d4.png)



```js:study.js
var rl = (lineWidth / 2) / Math.cos(45 * Math.PI / 180);
```

# 長さから三点の座標を取得

![image2.png](https://qiita-image-store.s3.amazonaws.com/0/80502/75496d39-bbd0-b1c7-b825-aaa62c0e3272.png)

* 先端 - 1

```js:study.js
var x1 = x + Math.cos(angle * Math.PI / 180) * rl;
var y1 = y + Math.sin(angle * Math.PI / 180) * rl * -1;

var x2 = x + Math.cos((angle - 90) * Math.PI / 180) * rl;
var y2 = y + Math.sin((angle - 90) * Math.PI / 180) * rl * -1;

var x3 = x + Math.cos((angle - 270) * Math.PI / 180) * rl;
var y3 = y + Math.sin((angle - 270) * Math.PI / 180) * rl * -1;
```

* 先端 - 2

```js:study.js
var x1 = dx + Math.cos((angle + 90) * Math.PI / 180) * rl;
var y1 = dy + Math.sin((angle + 90) * Math.PI / 180) * rl * -1;

var x2 = dx + Math.cos((angle + 180) * Math.PI / 180) * rl;
var y2 = dy + Math.sin((angle + 180) * Math.PI / 180) * rl * -1;

var x3 = dx + Math.cos((angle + 270) * Math.PI / 180) * rl;
var y3 = dy + Math.sin((angle + 270) * Math.PI / 180) * rl * -1;
```

# 円の描画はこちらから

[WebGL(2D) - 入門編 - 4日目: 滑らか(アンチエイリアス)な円を描く](http://qiita.com/ienaga/items/02e4b8d8c2a975ab86e1)


# 備忘録

[WebGLStudy](https://github.com/ienaga/WebGLStudy)