鳳 技術部

個人製作とか趣味とか備忘録なあれこれ

基本形状の表示について

できてること

  • webglで単純な何かを2Dで出す
  • 何かを出すのにはインデックスバッファを用いる

やりたいこと

  • 効率よくprimitiveな形状を出す
  • primitiveな形状には2D用のものと3D用のものがある
    • 2d Rectangle Circle 等
    • 3d Box Sphere Cylinder 等
  • 2dのものはどう考えても値がいじられまくる
  • 3dのものは明らかに頂点情報を用意してやる以外に方法がない

考えていること

  1. 基本的な形状用の固定バッファを作る?
  2. それとも基本形状のデータはそのままシェーダに渡せる形式にする?

サンプル

共通事項
  • rect は left top rigth bottom にアクセスできる
  • gl には glのコンテキストが入っている
  • 必要に応じてプリミティブ表示のためにrenderRectが呼ばれる
  • gl に渡す position は vec3 であるため z軸に相当する部分は適当に埋めている
  • glソースコンパイルやuseProgramはここより前に完了しているものとして変数programにそのプログラムオブジェクトが入っているとする

    1 の場合

var buffer = { };
var att = {};

buffer.vp = gl.createBuffer();
buffer.vpd = new Float32Array(12);
buffer.index = gl.createBuffer();
buffer.indexd = new Int16Array( [0 , 1 , 2 , 1 , 2 , 3] );

att.position = gl.getAttribLocation( program, "position");  

renderRect = function(rect)
{
    buffer.vpd[0] = rect.left;
    buffer.vpd[1] = rect.top;
    buffer.vpd[2] = 0;
    buffer.vpd[3] = rect.left;
    buffer.vpd[4] = rect.bottom;
    buffer.vpd[5] = 0;
    buffer.vpd[6] = rect.right;
    buffer.vpd[7] = rect.top;
    buffer.vpd[8] = 0;
    buffer.vpd[9] = rect.right;
    buffer.vpd[10] = rect.bottom;
    buffer.vpd[11] = 0;

    gl.bindBuffer( gl.ARRAY_BUFFER , buffer.vp);
    gl.bindData( gl.ARRAY_BUFFER , buffer.vpd, gl.STATIC_DRAW);
    gl.vertexAttribPointer(att.position,3,gl.FLOAT,0,0);

    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER , buffer.index);
    gl.bindData( gl.ELEMENT_ARRAY_BUFFER , buffer.indexd, gl.STATIC_DRAW);
 
    gl.drawElements(gl.TRIANGLES , rectBuf.index.length, gl.UNSIGNED_SHORT, 0);
}
  • 結局毎回書き換えなければならない
  • 但し各形状が持つデータは最小限でよさそう

2 の場合

var buffer = { };
var att = {};

buffer.index = gl.createBuffer();
buffer.indexd = new Int16Array( [0 , 1 , 2 , 1 , 2 , 3] );

att.position = gl.getAttribLocation( program, "position");  

class Rectangle
{
    constructor(left,top,right,bottom)
    {
         this.vpd  =    new Float32Array(12);
         this.vpd[0] = left;
         this.vpd[1] = top;
         this.vpd[2] = 0;
         this.vpd[3] = left;
         this.vpd[4] = bottom;
         this.vpd[5] = 0;
         this.vpd[6] = right;
         this.vpd[7] = top;
         this.vpd[8] = 0;
         this.vpd[9] = right;
         this.vpd[10] = bottom;
         this.vpd[11] = 0;
    }
}
renderRect = function(rect)
{
    gl.bindBuffer( gl.ARRAY_BUFFER , rect.vp);
    gl.bindData( gl.ARRAY_BUFFER , rect.vpd, gl.STATIC_DRAW);
    gl.vertexAttribPointer(att.position,3,gl.FLOAT,0,0);

    gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER , buffer.index);
    gl.bindData( gl.ELEMENT_ARRAY_BUFFER , buffer.indexd, gl.STATIC_DRAW);
 
    gl.drawElements(gl.TRIANGLES , rectBuf.index.length, gl.UNSIGNED_SHORT, 0);
}
  • 明らかにデータ量が増える
  • 明らかにパラメータ変更にかかるコストが増える

まとめ

  1. Rectangleのような2Dの単純な形状では1のほうがよさそうだと感じた
    • RectangleやCircleは2Dでの単純な衝突判定などに用いられるため、単純に更新しやすいほうがよいし、データ量が少ないほうがよいと思われる
  2. それ以外,例えば4頂点すべて を持つ四角形や3Dでの基本形状であれば結局すべての頂点を保持するだろうから、2の形式のほうがよさそうだと思われる
  3. 今回は基本形状で考えたが、3Dモデル等は必然的にモデルが頂点すべてを保持し、管理する2の形式になると思われる