この記事の概要
前回の記事では 50 行くらいのコードを書いて、ようやく 1 枚の単色板ポリを生成しました。
しかし現状では描画がボケています。
具体的なグラフィックを作る前に、画面サイズにあわせた描画ができるようにします。
現状の確認
前回作った赤い四角形を拡大してみます。
ボケボケです。
今は単色なのでフチがボケているだけに見えますが、この状態でグラデーションやノイズを実装するとすべてがボケたグラフィックに仕上がります。
しかし、canvas
要素自体のサイズはちゃんと画面いっぱいに広がっています。
スクリーンショットの数値でいうと 1104 x 852
のサイズです。
最初の記事で、canvas
に対して {height: 100dvh; width: 100dvw;}
を指定していたので当然と言えば当然です。
ひとまず、canvas
自体のサイズには問題がないのに中身がボケている、ということをご認識ください。
解決策
- もともと
// 描画の実行
とコメントをつけていた処理を関数にする →drawScene()
- 画面のサイズとcanvasのサイズ(描画バッファサイズ)を一致させる関数を作る →
resizeCanvasToDisplaySize()
-
resize
とDOMContentLoaded
にあわせて動かす
// 描画の実行
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- gl.clear(gl.COLOR_BUFFER_BIT);
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ function drawScene() {
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ }
+
+ // ウィンドウサイズに合わせてcanvasのサイズを変更する
+ function resizeCanvasToDisplaySize() {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ gl.viewport(0, 0, canvas.width, canvas.height);
+ drawScene();
+ }
+
+ // ウィンドウリサイズイベントに対するリスナーを設定
+ window.addEventListener("resize", resizeCanvasToDisplaySize);
+
+ // 初期表示時にもリサイズを実行
+ document.addEventListener("DOMContentLoaded", resizeCanvasToDisplaySize);
これにより、角がちゃんと綺麗になっています。
ポイントは resizeCanvasToDisplaySize()
の部分です。
canvas
要素はサイズの概念に 表示サイズ
と 描画バッファサイズ
があります。
表示サイズ
は通常 CSS で指定するようなサイズのことです。
先ほどのスクリーンショットで言えば 1104 x 852
と表示されていたサイズのことです。
描画バッファサイズ
は canvas
要素の中で実際に描画をするピクセル数です。
1 つ目の記事で WebGL コンテキストを取得した際、次のようになっていました。
WebGL2RenderingContext {
canvas: canvas#webgl-canvas,
drawingBufferWidth: 300,
drawingBufferHeight: 150,
drawingBufferColorSpace: 'srgb',
unpackColorSpace: 'srgb'
}
drawingBufferWidth: 300, drawingBufferHeight: 150
とありました。
つまり 300 x 150
の要素を 1104 x 852
に引き延ばして表示している状態でした。
小さな画像を無理やり引き伸ばしてボケてしまった経験はあると思います。
それと同じことが起きていました。
1104 x 852
の要素を 1104 x 852
のサイズで表示するために、以下の処理を追加していた、というわけです。
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
余談
ちなみに、常にウィンドウサイズと canvas のサイズが一緒になるように変えたため、CSS も少し簡略化できます。
#webgl-canvas {
display: block;
- height: 100dvh;
- width: 100dvw;
}
この程度のコードならあってもなくてもそこまで変わりませんが、CSS と JavaScript の両方からサイズを指定する必要もないので消しました。
もっと言うなら getElementById
するために指定した id
をセレクターとしてスタイルを当てること自体イマイチではありますが、一旦このまま進めます。
最後に
ここまでのコードをすべて合わせると以下のようになります。
// canvas要素の取得とWebGL2コンテキストの取得
const canvas = document.getElementById("webgl-canvas") as HTMLCanvasElement;
const gl = canvas.getContext("webgl2") as WebGL2RenderingContext;
// シェーダープログラムの作成
const vertexShaderSource = `#version 300 es
in vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}`;
const fragmentShaderSource = `#version 300 es
precision mediump float;
out vec4 outColor;
void main() {
outColor = vec4(1.0, 0.0, 0.0, 1.0); // 赤色
}`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER) as WebGLShader;
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) as WebGLShader;
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
const shaderProgram = gl.createProgram() as WebGLProgram;
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
// バッファの作成と設定
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// canvasの幅と高さの半分の大きさの矩形の頂点データ
const positions = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
-0.5, 0.5,
0.5, 0.5,
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
const positionAttributeLocation = gl.getAttribLocation(
shaderProgram,
"aPosition"
);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// 描画の実行
function drawScene() {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
// ウィンドウサイズに合わせてcanvasのサイズを変更する
function resizeCanvasToDisplaySize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
drawScene();
}
// ウィンドウリサイズイベントに対するリスナーを設定
window.addEventListener("resize", resizeCanvasToDisplaySize);
// 初期表示時にもリサイズを実行
document.addEventListener("DOMContentLoaded", resizeCanvasToDisplaySize);
まだ、見た目は「真っ黒い背景に赤い板が浮かんでいるだけ」です。
あと 1, 2 記事したら見た目をいじるステップに進めるはず……。
次の記事はこちらです。