CG関連

【WebGL】入門 わかりやすく【図解】してみた

プログラミングでかっこいい映像を作りたいととりくみ始めた『GLSL(シェーダー)』。

インターネットで『シェーダー』を使うには、
『WebGL(ウェブジーエル)』なる仕組みを使えばいいのですが、

3Dやりたい
『生のWebGL(ウェブジーエル)』難しいっす・・

という意見も多いようで。

実際の現場でも、
『生のWebGL』は記述量が多いので、ライブラリを使うことが多いようです。

WebGLは正式には「WebGL API」のことですが、素のAPIのままだと記述量が膨大になりどうしてもスピード感が出にくいのでライブラリを使うことがほとんどです。
 
WebGLコンテンツの開発フローと抑えどころ

  • 『WebGL』を使うためのライブラリ・・Three.jsなど

『Three.js』参考記事

実際にはライブラリを併用しつつ作り込むことになるんだろうなと思いつつ、

難しいと言われる『生のWebGL』の仕組みも知っておいたほうがいいだろうということで、

ざっくりとまとめてみることにしました。

Sponsored link

【WebGL】入門 描画までの流れ

『WebGL』を調べたことがあれば150%くらいの人がみていると思われるこちらのサイトを参考にまとめています。

wgld.org

『生のWebGL』で画面に描画するための流れは以下。

  1. HTML に canvas エレメントを明記
  2. 初期化処理
  3. シェーダーのコンパイル
  4. シェーダーとプログラムオブジェクトの生成
  5. 頂点バッファ( VBO )の生成と通知
  6. 座標変換行列の生成と通知
  7. 描画命令の発行
  8. canvas を更新してレンダリング

順番に見ていきます。

アオキ
全体のソースは最後にまとめています。

【WebGL】入門その1 HTMLにcanvasエレメントを明記

『WebGL』はホームページなどで表示されるために使われるので、

『HTML』でページを作りつつ、

『canvasタグ』を使って、『canvas』の中に描画していくことになります。

アオキ
minMatrix.js は行列のライブラリです。説明は後ほど・・
// index.html

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>wgld.org WebGL sample 002</title>
        <script src="script.js" type="text/javascript"></script>
        <script src="https://wgld.org/j/minMatrix.js" type="text/javascript"></script>      
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
</html>
Sponsored link

【WebGL】入門その2. 初期化処理

続いて初期化処理。

『JavaScript』ファイルに書いていきます。

getContext で『WebGL』を取得して、色や深度(奥行き)を初期化しています。

// script.js

// canvasエレメントを取得
var c = document.getElementById('canvas');
c.width = 300;
c.height = 300;

// webglコンテキストを取得
var gl = c.getContext('webgl') || c.getContext('experimental-webgl');

// canvasを初期化する色を設定する
gl.clearColor(0.0, 0.0, 0.0, 1.0);

// canvasを初期化する際の深度を設定する
gl.clearDepth(1.0);

// canvasを初期化
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

【WebGL】入門その3. シェーダーのコンパイル

3D画面を描写する役割の『シェーダー(Shader)』には大きく2つの種類があります。

  • 頂点シェーダー(Vertex Shader) ・・頂点情報
  • フラグメントシェーダー(Fragment Shader)・・色情報

書く順番は決まっていて、頂点シェーダー -> フラグメンントシェーダー になります。

『シェーダー(GLSL)』の内容は 『HTML』 側に書いていきます。

アオキ
行列の記述もありますが後ほど・・
// index.html

<html>
    <head>
        <title>WebGL TEST</title>
        <script src="script.js" type="text/javascript"></script>
        <script src="minMatrix.js" type="text/javascript"></script>
        
        <script id="vs" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec4 vColor;

void main(void){
    vColor = color;
    gl_Position = mvpMatrix * vec4(position, 1.0);
}
        </script>
        
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;

void main(void){
    gl_FragColor = vColor;
}
        </script>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
</html>

【WebGL入門】 頂点シェーダー側

『頂点シェーダー』側に3種類の変数が設定されています。

  • attribute変数 ・・ 頂点毎に異なる情報を設定
  • uniform変数 ・・全ての頂点に対しまとめて処理
  • varying変数 ・・頂点シェーダからフラグメントシェーダへの受け渡し

『シェーダー』はとにかく『頂点(Vertex)』が大事で、

『頂点』にいろんな『属性(attribute)』をくっつけることができます。

  • 座標位置
  • 法線(光の反射で使う)
  • テクスチャ座標

などなど。

今回は 座標位置 と 色 をそれぞれ指定しています。

  • 座標位置は(x, y, z)と3つの値があるので vec3 (ベクトル3)
  • 色情報は( r, g, b, a)(赤緑青と透過度のアルファ)で4つなので vec4 (ベクトル4)です。

ベクトル関連記事

『unifrom』変数は頂点全体に関わる処理で、移動や回転をするための『行列(Matrix)』を指定しています。

『行列』は(x,y,z)の3つの値と思いがちですが、

視界よりも外にあるかどうかを判定するための『w』を含めて、
4×4の『行列』になるので、『mat4』とつけるようになっています。

  • w ・・ 同次座標系。視界よりも外にあるかどうか

同次座標系の関連記事
深度値と座標系について理解する | wgld.org

『varying』変数を使うことで、

色情報など、頂点シェーダー -> フラグメントシェーダーに移すことができます。

最後に 『gl_Position』 を指定して『頂点シェーダ』側は完了です。

アオキ
gl_Position の指定は必須です。

【WebGL入門】 フラグメントシェーダー側

precision mediump は、描画の精度を指定しています。

  • lowp ・・精度低
  • mediump ・・精度中
  • highp ・・精度高

フラグメントシェーダー側にも『varying』変数を使うことで、

頂点シェーダー -> フラグメンントシェーダー の色情報を受け渡ししています。

最後に 『gl_FragColor』 で色情報を指定して完了です。

アオキ
gl_FragColor は必須ではないそうです。(けどよく見るなぁ。)
Sponsored link

【WebGL】入門その4. シェーダーとプログラムオブジェクトの生成

『JavaScript』側でも『シェーダー』の記載が必要です。

// script.js

// 頂点シェーダとフラグメントシェーダの生成
var v_shader = create_shader('vs');
var f_shader = create_shader('fs');
    
// プログラムオブジェクトの生成とリンク
var prg = create_program(v_shader, f_shader);
    
// attributeLocationを配列に取得
var attLocation = new Array(2);
attLocation[0] = gl.getAttribLocation(prg, 'position');
attLocation[1] = gl.getAttribLocation(prg, 'color');
    
// attributeの要素数を配列に格納
var attStride = new Array(2);
attStride[0] = 3;
attStride[1] = 4;
アオキ
create_shader と create_program は自前でつくられた『ユーザー関数』になります。(後ほど記載します。)
  • プログラムオブジェクト・・『頂点シェーダ』と『フラグメントシェーダ』の紐付け

頂点に紐づける属性(情報)は、順番を指定しています。

  • attLocation ・・ 頂点に紐づける順番。何番目のデータかを指定
  • attStride ・・データがいくつの要素からなるか。(座標は3で色は4)

【WebGL】シェーダー作成

『シェーダー』を生成する自作関数がこちら。

 // シェーダを生成する関数
    function create_shader(id){
        // シェーダを格納する変数
        var shader;
        
        // HTMLからscriptタグへの参照を取得
        var scriptElement = document.getElementById(id);
        
        // scriptタグが存在しない場合は抜ける
        if(!scriptElement){return;}
        
        // scriptタグのtype属性をチェック
        switch(scriptElement.type){
            
            // 頂点シェーダの場合
            case 'x-shader/x-vertex':
                shader = gl.createShader(gl.VERTEX_SHADER);
                break;
                
            // フラグメントシェーダの場合
            case 'x-shader/x-fragment':
                shader = gl.createShader(gl.FRAGMENT_SHADER);
                break;
            default :
                return;
        }
        
        // 生成されたシェーダにソースを割り当てる
        gl.shaderSource(shader, scriptElement.text);
        
        // シェーダをコンパイルする
        gl.compileShader(shader);
        
        // シェーダが正しくコンパイルされたかチェック
        if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
            
            // 成功していたらシェーダを返して終了
            return shader;
        }else{
            
            // 失敗していたらエラーログをアラートする
            alert(gl.getShaderInfoLog(shader));
        }
    }
  • gl.createShader でシェーダーをつくって、
  • g.shaderSource でソース? を割り当てて、
  • gl.compileShader でコンパイルして
  • gl.getShaderParameter でチェックして

OKなら『シェーダー』返して、NGならログを出すと。

  • gl.getShaderInfoLog ログを出す

関数名が英語そのままなので読んでいくとわかりやすいかもです。

【WebGL】プログラムオブジェクトの作成

  • プログラムオブジェクト・・『頂点シェーダ』と『フラグメントシェーダ』の橋渡し

コードは以下。

  // プログラムオブジェクトを生成しシェーダをリンクする関数
    function create_program(vs, fs){
        // プログラムオブジェクトの生成
        var program = gl.createProgram();
        
        // プログラムオブジェクトにシェーダを割り当てる
        gl.attachShader(program, vs);
        gl.attachShader(program, fs);
        
        // シェーダをリンク
        gl.linkProgram(program);
        
        // シェーダのリンクが正しく行なわれたかチェック
        if(gl.getProgramParameter(program, gl.LINK_STATUS)){
        
            // 成功していたらプログラムオブジェクトを有効にする
            gl.useProgram(program);
            
            // プログラムオブジェクトを返して終了
            return program;
        }else{
            
            // 失敗していたらエラーログをアラートする
            alert(gl.getProgramInfoLog(program));
        }
    }
  • gl.createProgram でプログラムオブジェクトつくって
  • gl.attachShader でシェーダーをくっつけて
  • gl.linkProgram でシェーダーをリンクさせて
  • gl.getProgramParameter でリンクのチェックして
  • OKなら gl.useProgram で有効にして返す
  • NGなら gl.getProgramInfoLog でエラーだす

という流れで。

アオキ
よくみるとシェーダーの流れと似ていたりします。

【WebGL】入門その5. 頂点バッファ( VBO )の生成と通知

『WebGL』はとにかく『頂点』が大事で、

頂点にいろんな属性(情報)をくっつけて処理します。

  • 座標位置
  • 法線(光の反射で使う)
  • テクスチャ座標

などなど。

で、それぞれの属性毎に、
『VBO(頂点バッファオブジェクト)』なるものをつくって情報を渡すそうです。

『VBO』生成の流れがイメージしづらなかったので図をつくってみました。

  1. バッファ(入れ物)をつくって
  2. WebGLにバインドして(くっつけて)
  3. 属性データ(配列)をセットして
  4. VBO として生成されるようです。

これを頂点の属性毎に繰り返すそうです。

コードは以下。

   // VBOを生成する関数
    function create_vbo(data){
        // バッファオブジェクトの生成
        var vbo = gl.createBuffer();
        
        // バッファをバインドする
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
        
        // バッファにデータをセット
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
        
        // バッファのバインドを無効化
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        
        // 生成した VBO を返して終了
        return vbo;
    }
  • gl.createBuffer でバッファをつくって
  • gl.bindBuffer でバッファをWebGLにバインドして
  • gl.bufferData で配列データをセットして・・ここでVBO生成
  • gl.bindBuffer でバインドを無効化して
  • VBOを返して終わり

になります。

アオキ
図を書いてようやくわかった感があります。。

『VBO』を生成するユーザー定義関数を使って、

頂点の属性情報(配列)をつくって、『VBO』を生成しています。

コードは以下。

 // 頂点の位置情報を格納する配列
    var vertex_position = [
         0.0, 1.0, 0.0,
         1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0
    ];
    
    // 頂点の色情報を格納する配列
    var vertex_color = [
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0
    ];
    
    // VBOの生成
    var position_vbo = create_vbo(vertex_position);
    var color_vbo = create_vbo(vertex_color);
    
    // VBOをバインドし登録する(位置情報)
    gl.bindBuffer(gl.ARRAY_BUFFER, position_vbo);
    gl.enableVertexAttribArray(attLocation[0]);
    gl.vertexAttribPointer(attLocation[0], attStride[0], gl.FLOAT, false, 0, 0);
    
    // VBOをバインドし登録する(色情報)
    gl.bindBuffer(gl.ARRAY_BUFFER, color_vbo);
    gl.enableVertexAttribArray(attLocation[1]);
    gl.vertexAttribPointer(attLocation[1], attStride[1], gl.FLOAT, false, 0, 0);
  • gl.bindBuffer
  • gl.enableVertexAttribArray
  • gl.vertexAttribPointer

の3つはセットで使うと思ってればいいのかなと思います。

アオキ
ここまで長かった・・あと一息・・
Sponsored link

【WebGL】入門その6. 座標変換行列の生成と通知

3D空間で物体を回転させるには、『回転行列』を使う必要があります。

参考記事

『回転行列』は書く内容が決まっているので、

wgld.org サイトの方であらかじめ『行列』用のコードがあるので
まるっとお借りします。

 // minMatrix.js を用いた行列関連処理
    // matIVオブジェクトを生成
    var m = new matIV();
    
    // 各種行列の生成と初期化
    var mMatrix = m.identity(m.create());
    var vMatrix = m.identity(m.create());
    var pMatrix = m.identity(m.create());
    var mvpMatrix = m.identity(m.create());
    
    // ビュー座標変換行列
    m.lookAt([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
    
    // プロジェクション座標変換行列
    m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
    
    // 各行列を掛け合わせ座標変換行列を完成させる
    m.multiply(pMatrix, vMatrix, mvpMatrix);
    m.multiply(mvpMatrix, mMatrix, mvpMatrix);
    
    // uniformLocationの取得
    var uniLocation = gl.getUniformLocation(prg, 'mvpMatrix');
    
    // uniformLocationへ座標変換行列を登録
    gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
    

minMatrix.jsと座標変換行列 | wgld.org

【WebGL】入門その7. 描画命令の発行

最後はサクッと、下記2つで描画されます。

// モデルの描画
gl.drawArrays(gl.TRIANGLES, 0, 3);

// コンテキストの再描画
gl.flush();

描画命令を発行することを『ドローコール』と呼ぶそうで、

『ドローコール』が増えれば増えるほど処理も重くなるようで、

それを回避するために、『インスタンシング』や『GPGPUパーティクルシステム』などありますが、

それは別の記事で。

Sponsored link

【WebGL】入門その8. canvas を更新してレンダリング

ここは恒常ループ処理かな、
JavaScript の setTImeout を使ってずっと描画させる方法かなと思います。

再帰処理と移動・回転・拡大縮小 | wgld.org

【WebGL】入門 全体のコード

全体のコードは以下。

// index.html 

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>wgld.org WebGL sample 003</title>
        <script src="script.js" type="text/javascript"></script>
        <script src="https://wgld.org/j/minMatrix.js" type="text/javascript"></script>
        
        <script id="vs" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec4 color;
uniform   mat4 mvpMatrix;
varying   vec4 vColor;

void main(void){
    vColor = color;
    gl_Position = mvpMatrix * vec4(position, 1.0);
}
        </script>
        
        <script id="fs" type="x-shader/x-fragment">
precision mediump float;

varying vec4 vColor;

void main(void){
    gl_FragColor = vColor;
}
        </script>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
</html>
// script.js

onload = function(){
    // canvasエレメントを取得
    var c = document.getElementById('canvas');
    c.width = 300;
    c.height = 300;

    // webglコンテキストを取得
    var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
    
    // canvasを初期化する色を設定する
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    
    // canvasを初期化する際の深度を設定する
    gl.clearDepth(1.0);
    
    // canvasを初期化
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    // 頂点シェーダとフラグメントシェーダの生成
    var v_shader = create_shader('vs');
    var f_shader = create_shader('fs');
    
    // プログラムオブジェクトの生成とリンク
    var prg = create_program(v_shader, f_shader);
    
    // attributeLocationを配列に取得
    var attLocation = new Array(2);
    attLocation[0] = gl.getAttribLocation(prg, 'position');
    attLocation[1] = gl.getAttribLocation(prg, 'color');
    
    // attributeの要素数を配列に格納
    var attStride = new Array(2);
    attStride[0] = 3;
    attStride[1] = 4;
    
    // 頂点の位置情報を格納する配列
    var vertex_position = [
         0.0, 1.0, 0.0,
         1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0
    ];
    
    // 頂点の色情報を格納する配列
    var vertex_color = [
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0
    ];
    
    // VBOの生成
    var position_vbo = create_vbo(vertex_position);
    var color_vbo = create_vbo(vertex_color);
    
    // VBOをバインドし登録する(位置情報)
    gl.bindBuffer(gl.ARRAY_BUFFER, position_vbo);
    gl.enableVertexAttribArray(attLocation[0]);
    gl.vertexAttribPointer(attLocation[0], attStride[0], gl.FLOAT, false, 0, 0);
    
    // VBOをバインドし登録する(色情報)
    gl.bindBuffer(gl.ARRAY_BUFFER, color_vbo);
    gl.enableVertexAttribArray(attLocation[1]);
    gl.vertexAttribPointer(attLocation[1], attStride[1], gl.FLOAT, false, 0, 0);
    
    // minMatrix.js を用いた行列関連処理
    // matIVオブジェクトを生成
    var m = new matIV();
    
    // 各種行列の生成と初期化
    var mMatrix = m.identity(m.create());
    var vMatrix = m.identity(m.create());
    var pMatrix = m.identity(m.create());
    var mvpMatrix = m.identity(m.create());
    
    // ビュー座標変換行列
    m.lookAt([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
    
    // プロジェクション座標変換行列
    m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
    
    // 各行列を掛け合わせ座標変換行列を完成させる
    m.multiply(pMatrix, vMatrix, mvpMatrix);
    m.multiply(mvpMatrix, mMatrix, mvpMatrix);
    
    // uniformLocationの取得
    var uniLocation = gl.getUniformLocation(prg, 'mvpMatrix');
    
    // uniformLocationへ座標変換行列を登録
    gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
    
    // モデルの描画
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
    // コンテキストの再描画
    gl.flush();
    
    // シェーダを生成する関数
    function create_shader(id){
        // シェーダを格納する変数
        var shader;
        
        // HTMLからscriptタグへの参照を取得
        var scriptElement = document.getElementById(id);
        
        // scriptタグが存在しない場合は抜ける
        if(!scriptElement){return;}
        
        // scriptタグのtype属性をチェック
        switch(scriptElement.type){
            
            // 頂点シェーダの場合
            case 'x-shader/x-vertex':
                shader = gl.createShader(gl.VERTEX_SHADER);
                break;
                
            // フラグメントシェーダの場合
            case 'x-shader/x-fragment':
                shader = gl.createShader(gl.FRAGMENT_SHADER);
                break;
            default :
                return;
        }
        
        // 生成されたシェーダにソースを割り当てる
        gl.shaderSource(shader, scriptElement.text);
        
        // シェーダをコンパイルする
        gl.compileShader(shader);
        
        // シェーダが正しくコンパイルされたかチェック
        if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
            
            // 成功していたらシェーダを返して終了
            return shader;
        }else{
            
            // 失敗していたらエラーログをアラートする
            alert(gl.getShaderInfoLog(shader));
        }
    }
    
    // プログラムオブジェクトを生成しシェーダをリンクする関数
    function create_program(vs, fs){
        // プログラムオブジェクトの生成
        var program = gl.createProgram();
        
        // プログラムオブジェクトにシェーダを割り当てる
        gl.attachShader(program, vs);
        gl.attachShader(program, fs);
        
        // シェーダをリンク
        gl.linkProgram(program);
        
        // シェーダのリンクが正しく行なわれたかチェック
        if(gl.getProgramParameter(program, gl.LINK_STATUS)){
        
            // 成功していたらプログラムオブジェクトを有効にする
            gl.useProgram(program);
            
            // プログラムオブジェクトを返して終了
            return program;
        }else{
            
            // 失敗していたらエラーログをアラートする
            alert(gl.getProgramInfoLog(program));
        }
    }
    
    // VBOを生成する関数
    function create_vbo(data){
        // バッファオブジェクトの生成
        var vbo = gl.createBuffer();
        
        // バッファをバインドする
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
        
        // バッファにデータをセット
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
        
        // バッファのバインドを無効化
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        
        // 生成した VBO を返して終了
        return vbo;
    }

};

こちらの記事にまるっと掲載されています。

ポリゴンに色を塗る(頂点色の指定) | wgld.org

【WebGL】入門 まとめ

wgld.org のページは本当にすごい情報量で、
詳しい分なかなか難しかったりするので、
なんども読みつつ、ノートをとりつつ、
ようやく図にできた感があります。

生の『WebGL』はHTMLとJavaScriptを足してざっくり220行。
対して『Three.js』は約50行。

参考記事

アオキ
『Three.js』って本当は楽だったのね・・(難しいけど

便利ライブラリの助けを借りつつ、
ここぞという場面では『生WebGL』も使いこなせるようになるといいんでしょうね。

アオキ
引き続き鍛錬だなぁ、コツコツがんばります。

『Three.js』関係ではこんな記事も読まれています。

1. 3Dプログラムの基本を【Three.js】でまとめてみた【初心者向け】

2. 【Three.js】で『GLSL(シェーダー)』を使う環境構築の仕方 【初心者向け】

3. 【WebGL】入門 わかりやすく【図解】してみた

4. 【Three.js】用語や関数のまとめ【3Dプログラム】※随時更新

『GLSL(シェーディング)』関係ではこんな記事も読まれています。

1. 【GLSL】プログラムでかっこいい映像をつくりたい! 〜『TouchDesigner』を見据えて

2. 【WebGL】入門 わかりやすく【図解】してみた

3. 【OpenGL】と【DirectX】のバージョンをまとめてみた【シェーダーメイン】【初心者向け】

4. 【GLSL(シェーディング)】でよく使う関数とユーザー関数のまとめ※随時更新

5. 【GLSL】プログラムでかっこいい映像をつくるには『レイマーチング』なるものを覚えればいいらしい

6. 【GLSL】『レイマーチング』入門その1 距離関数とレイとカメラの設定

7. 【GLSL】『レイマーチング』入門(2) 立体的に見せる方法〜光の反射は『内積』で〜

8. 【GLSL】『レイマーチング』入門(3) 距離関数を使ってみる・回転・合成・量産

9. 【TouchDesigner】で『GLSL』を使う方法まとめ【画像あり】

10. 【TouchDesigner】『GLSL MAT』の使い方 3次元でぐりぐり動かしてみる

11. 【GLSL】波のつくり方簡易まとめ。波もプログラムでつくれます【コピペスタイル】

アオキ
ツイッターでも記事ネタ含めちょろちょろ書いていくので、よろしければぜひフォローお願いしますm(_ _ )m

アオキのツイッターアカウント


関連記事一覧 (一部広告あり)

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

CAPTCHA


最近の記事

アーカイブ

  1. オンライン教材

    【AWS】【初心者向け】インフラの基礎からわかる講座をリリースしました【Udem…
  2. 生成AI

    2024/5/14 OpenAI発表 まとめ
  3. 生成AI

    Dify講座をリリースしました【非エンジニア向け】
  4. データベース

    MySQLの講座をリリースしました
  5. オンライン教材

    ChatGPTをビジネス活用する講座をリリースしました【Udemy】
PAGE TOP
Ads Blocker Image Powered by Code Help Pro

広告ブロックを摘出しました!!

ブラウザ拡張を使用して広告をブロックしていることが摘出されました。

ブラウザの広告ブロッカーの機能を無効にするか、
当サイトのドメインをホワイトリストに追加し、「更新」をクリックして下さい。

あなたが広告をブロックする権利があるように、
当方も広告をブロックしている人にコンテンツを提供しない権利と自由があります。

Powered By
100% Free SEO Tools - Tool Kits PRO