Skip to content

Instantly share code, notes, and snippets.

@petamoriken
Created June 25, 2016 11:21
Show Gist options
  • Save petamoriken/b9788346f57cad2a1a29cb1a313fb2bc to your computer and use it in GitHub Desktop.
Save petamoriken/b9788346f57cad2a1a29cb1a313fb2bc to your computer and use it in GitHub Desktop.
WebGL で描画テスト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Obj View</title>
<!-- JavaScript -->
<script src="js/gl-matrix.js"></script>
<script>
(() => {
"use strict";
window.addEventListener("DOMContentLoaded", () => {
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
// 頂点シェーダーのコンパイル
const vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, document.getElementById("vs").text);
gl.compileShader(vs);
if(!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
console.log("vertex shader compile error");
console.error(gl.getShaderInfoLog(vs));
return;
}
// フラグメントシェーダのコンパイル
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, document.getElementById("fs").text);
gl.compileShader(fs);
if(!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
console.log("fragment shader compile error");
console.error(gl.getShaderInfoLog(fs));
return;
}
// シェーダをリンク
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log("link error");
console.error(gl.getShaderInfoLog(fs));
return;
}
// リンクしたプログラムの使用
gl.useProgram(program);
// 描画するバッファの読み込み
const [vbuf, nbuf] = [gl.createBuffer(), gl.createBuffer()]; // 頂点座標バッファと法線ベクトルバッファ
gl.bindBuffer(gl.ARRAY_BUFFER, vbuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-0.5, -0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, nbuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1]), gl.STATIC_DRAW);
// 描画処理
const startTime = performance.now();
requestAnimationFrame(function draw() {
// frustum 行列の生成
const projMat = mat4.create();
mat4.frustum(projMat, -1, 1, -1, 1, 3, 10);
// 移動回転行列の生成
const mvMat = mat4.create();
mat4.translate(mvMat, mvMat, [0, 0, -6]);
mat4.rotate(mvMat, mvMat, (startTime - performance.now()) * 0.002, [0, 1, 0]); // 軸 [0, 1, 0] で回転
// uniform で頂点シェーダに送信
gl.uniformMatrix4fv(gl.getUniformLocation(program, "projectionMatrix"), false, projMat);
gl.uniformMatrix4fv(gl.getUniformLocation(program, "modelviewMatrix"), false, mvMat);
// WebGL の canvas の内容をクリア
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
// attribute の index を取得
const vpos = gl.getAttribLocation(program, "vertex");
const npos = gl.getAttribLocation(program, "normal");
// 取得した attribute postion にバッファを送信
gl.bindBuffer(gl.ARRAY_BUFFER, vbuf); // 頂点座標
gl.vertexAttribPointer(vpos, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vpos);
gl.bindBuffer(gl.ARRAY_BUFFER, nbuf); // 法線ベクトル
gl.vertexAttribPointer(npos, 3, gl.FLOAT, true, 0, 0);
gl.enableVertexAttribArray(npos);
// 今まで設定した内容で WebGL に送信
gl.drawArrays(gl.TRIANGLES, 0, 3);
// 繰り返し
requestAnimationFrame(draw);
});
}, { capture: false, once: true });
})();
</script>
<!-- 頂点シェーダ -->
<script id="vs" type="x-shader/x-vertex">
// 演算精度 highp, mediump, lowp
precision mediump float;
// 描画プリミティブごとに与えられる変数
uniform mat4 projectionMatrix; // 錐台(frustum)変換行列
uniform mat4 modelviewMatrix; // 平行起動回転行列
// 頂点ごとに与えられる変数
attribute vec3 vertex; // 頂点座標
attribute vec3 normal; // 頂点の法線ベクトル
// フラグメントシェーダに渡す変数
varying vec3 e_normal; // 法線ベクトルと平行移動回転行列との積
void main() {
// 頂点座標をクリッピング座標系に変換する
gl_Position = projectionMatrix * modelviewMatrix * vec4(vertex, 1.0);
// 法線ベクトルを世界座標系に変換する
e_normal = vec3(modelviewMatrix * vec4(normal, 0.0));
}
</script>
<!-- フラグメントシェーダ -->
<script id="fs" type="x-shader/x-fragment">
// 演算精度 highp, mediump, lowp
precision mediump float;
// 頂点シェーダから受け取る変数
varying vec3 e_normal; // 法線ベクトル
void main() {
// 法線ベクトルを正規化する
vec3 n = normalize(e_normal);
// 法線ベクトルと光ベクトル(0, 0, 1) との内積で光量を決定する
float l = abs(dot(n, normalize(vec3(0, 0, 1))));
// このピクセルの色を RGBA(l, l, l, 1) に設定する
gl_FragColor = vec4(l, l, l, 1.0);
}
</script>
</head>
<body>
<canvas id="canvas" width="512" height="512"></canvas>
</body>
</html>
@petamoriken
Copy link
Author

petamoriken commented Jun 25, 2016

tkihira さんの記事を参考にしました。
例によって gl-matrix が必要。

addEventListener で EventListenerOptions を使用しているため、現段階では最新の Chrome でしか動かない(特に使う意味ないけど……)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment