メインコンテンツへ移動

uniform 変数とフラグメントシェーダー_WebGL ノート 4

無料2015-12-24#JS#WebGL#WebGL uniform#webgl uniform变量#webgl设置颜色#webgl修改颜色

attribute 変数を通じてフラグメントシェーダーに値を渡すことで、点の色を動的に変更できます

はじめに

[前回のノート](/articles/マウスクリック位置に点を描画する-webgl ノート 3/) では、attribute 変数を通じてマウスクリック位置の座標情報を頂点シェーダーに渡し、クリックした位置に点を描画する効果を実現しましたが、描画される点はすべて同じ色でした。点の色を動的に設定したい場合、uniform 変数が必要です。なぜならattribute 変数は頂点シェーダーでのみ使用可能で、色情報はフラグメントシェーダー中にあるからです

一.uniform 変数と attribute 変数

uniform と attribute は類似しており、どちらも記憶限定子です。主な違いは以下の通り:

  • attribute

頂点シェーダーでのみ使用可能。頂点ごとのデータ(各頂点でこの値が異なる)を表すために使用。例えば前面で使用した attribute vec4 a_Position

  • uniform

頂点シェーダーでもフラグメントシェーダーでも使用可能。一貫した、不変のデータ(各頂点でこの値が同じ)を表すために使用。例えば今後テクスチャマッピングで使用する uniform Sampler2D u_Sampler、および私たちがまもなく使用する uniform vec4 u_FragColor

P.S. uniform と attribute には其它の違いもあり、もう 1 つの記憶限定子は varying です。これらの内容はすべて GLSL ES 構文ノートで展開します

二.点の色を設定

座標の設定と類似し、まず uniform 変数を宣言して色情報を受け取り、次に色値を渡して描画します

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

着色のプロセスはフラグメントシェーダー中で行われます。フラグメントシェーダーソースプログラムを修正する必要があります:

// フラグメントシェーダーソースプログラム
//!!! 浮動小数点精度を宣言する必要があります。否则エラー No precision specified for (float) が報告されます
var fsSrc = 'precision mediump float;' +
    'uniform vec4 u_FragColor;' +
    'void main() {' +
    'gl_FragColor = u_FragColor;' + // 色を設定
'}';

用法は attribute 変数と完全に一致しますが、特に注意が必要な点が 1 つあります:浮動小数点精度を宣言する必要があります。否则フラグメントシェーダーはコンパイルに失敗し、以下のエラーを報告します:

ERROR: 0:1: '' : No precision specified for (float)

###2.色を設定

gl.getAttribLocationgl.vertexAttrib3f に類似し、ここでは gl.getUniformLocationgl.uniform4f を使用します:

// 色を設定
// uniform 変数の記憶位置を取得
var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
var color = item.color;
// 色値を uniform 変数に渡す
gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);

色値 rgba はすべて 0.0~1.0 であることに注意。この区間にない数値は自動的に 0.0 または 1.0 に切り捨てられますが、エラーにはなりません

###3.複数の点を描画

ここでは直接 gl.drawArrays(gl.POINTS, 0, 1); をループして実現しました。方法は科学的ではありませんが効果は実現できます。より科学的方法は buffer と配合する必要があります。これは次回のノートの内容で、私たちはまだロックを解除していません

var arrPos = [];
webgl.addEventListener('click', function(e) {
    // 座標を変換
    var x = (e.offsetX - webgl.width / 2) / (webgl.width / 2);
    var y = (webgl.height / 2 - e.offsetY) / (webgl.height / 2);
    console.log(x, y);
    // ランダムな色
    var color = {
        r: Math.random(),
        g: Math.random(),
        b: Math.random(),
        a: Math.random()
    };
    // 座標、色を記録
    arrPos.push({
        x: x,
        y: y,
        color: color
    });

    // canvas をクリア
    gl.clear(gl.COLOR_BUFFER_BIT);
    // 記録したすべての座標位置に点を描画
    arrPos.forEach(function(item) {
        // 2.attribute 変数に値を代入
        // attribute 変数の記憶位置を取得
        var a_Position = gl.getAttribLocation(glUtil.program, 'a_Position');
        if (a_Position < 0) {
            console.log('Failed to get the storage location of a_Position');
            return;
        }
        // 頂点位置を attribute 変数に渡す
        gl.vertexAttrib3f(a_Position, item.x, item.y, 0.0);

        // 色を設定
        // uniform 変数の記憶位置を取得
        var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
        var color = item.color;
        // 色値を uniform 変数に渡す
        gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);

        // 点を描画
        gl.drawArrays(gl.POINTS, 0, 1);
    });
});

新しいものはなく、ただ乱暴なループです。唯一注意が必要な問題はループ前の clear です。前回のノートでこの問題に言及しました:描画完了後、カラーバッファはリセットされ、その中の内容は失われます。効果から見ると、clear は毎回描画前に黒色背景を設定しています。clear がない場合、背景は透明になります(vec4(0.0, 0.0, 0.0, 0.0))

三.DEMO

上記コードを含む完全な例は、以下を参照:http://www.ayqy.net//temp/webgl/uniform/index.html

四.まとめ

私たちは点点点点で燦爛な星空を点き出す効果を実現しました。パフォーマンスを考慮しない場合、このように実現するのは悪くありません。なぜなら次回のノートで紹介する buffer はより面倒に見えるが、利点もあるからです。buffer があれば 1 回で一組のデータを渡すことができ、今後三角形を描画し、三角形に色を塗り、テクスチャを貼るのが非常に便利になります

loop draw a point は結局長久之計ではありません。1 つ 1 つの点で三角形を拼うことはできません。まして 3D モデルもあります。buffer は���常に必要です

参考資料

  • 《WebGL プログラミングガイド》

コメント

コメントはまだありません

コメントを書く