独自のWebGLエンジン。 記事番号1。 キャンバス

一連の記事を通じて、webglでエンジンを解析します。



基本的な要件は、最小限のデータ入力です。 実際、大まかに言って、エンジンはタスクを簡素化するために作成されたモデルです。 この教材は、webglの基本を読み、始めようとする人向けの初心者向けに設計されています。 私のように。



最初のもの。 指のタスクの説明


一連のポイントであるオブジェクト(プリミティブ)のクラスを作成する必要があります。 この場合、プリミティブは互いに独立している必要があります。 各プリミティブは、中心または任意の点を中心に移動、回転できます。

これらのオブジェクトの概要を説明するメカニズムを作成する必要があります。

最後に、オブジェクトをインストールし、自由に移動できるマップのようなものを作成する必要があります。



二番目。 機構の概要


アウトラインのメカニズム、アーティストのためのキャンバスとペイント。 キャンバスを準備するために、エンジンのユーザーが入力しなければならない最小最小値は何ですか? 私の意見では、これはDOMのキャンバスへの単なるリンクです。 そして、色とサイズの両方を設定できます。



var scene = new Scene("webglID"); scene.setBackgroundColor([0.1,0.5,0.6,0.2]); scene.setViewPort(300, 300);
      
      







最初の行だけが必要だと考えると、もっと簡単になるでしょうか?

「WebglID」は、描画が行われるキャンバス要素のIDです。

また、このメカニズムの実装は、描画が発生しないため、複雑なものを構成しません。



 function Scene(canvasID) { this.backgroundColor = {red:1.0, green:1.0, blue:1.0, alpha:1.0}; this.canvas = document.getElementById(canvasID); this.getContext(); } Scene.prototype = { setViewPort: function(width,height){ this.gl.viewportWidth = width; this.gl.viewportHeight = height; }, setBackgroundColor: function(colorVec){ if (colorVec){ if (colorVec.length > 0) { this.backgroundColor.red = colorVec[0]; } if (colorVec.length > 1) { this.backgroundColor.green = colorVec[1]; } if (colorVec.length > 2) { this.backgroundColor.blue = colorVec[2]; } if (colorVec.alpha > 3) { this.backgroundColor.red = colorVec[3]; } } }, getContext:function(){ var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; this.gl = null; for (var ii = 0; ii < names.length; ++ii) { try { this.gl = this.canvas.getContext(names[ii]); } catch(e) {} if (this.gl) { break; } } } }
      
      







(getContextメソッドは記事から取られています(それ以前は、this.gl = this.canvas.getContext( "webgl");と書きました)。



作成されたキャンバス


エンジンに描画する機能を追加する前に、以下を決定する必要があります。

  1. 頂点またはインデックスを使用して描画します。
  2. プリミティブはどのような数字で構成されますか。






エンジンの場合、インデックスによる描画を選択しましたが、これは明らかです。 そして、図のタイプは三角形です。 ここでは、それほど明白ではありませんが、説明しようとします。



すべてのオブジェクト、したがって、すべての頂点とインデックスに1つのバッファーを使用します。 将来、複数のバッファを使用できるようになる場合、図形のタイプはプリミティブオブジェクト自体に配置されます。 (すでにそのような機会がある場合は、コメントに記入してください。)同時に、オブジェクトは互いに独立している必要があるため、LINES、TRIANGLES、POINTSから選択できます。 内側を埋める図として三角形を選びました。



描画プロセス自体は2つの段階で構成されます-シーンにオブジェクトを追加し、シーン全体を描画します。 実際、将来的には、描画する必要があるオブジェクトの検出、シーンへの追加、シーン全体の描画の3つの段階になります。



 var vertex = [ -50,50,50, 50,50,50, 50,-50,50, -50,-50,50 ]; var indices = [0,1,3,1,2,3]; var obj = new botuObject(vertex,indices); scene.AddObject(obj); scene.draw();
      
      







botuObjectは最初のプリミティブです。 最もエレガントではなく、まあ、それは何ですか。 単に渡される頂点とインデックスが含まれています。 概して、すべてのプリミティブには頂点とインデックスが含まれ、初期化中に他のプリミティブのみがこれらの頂点を計算します。 それらについては、後続の記事で詳しく説明します。



プリミティブ実装:



 function botuObject(vertex,indices){ this.vertex = vertex; this.indices = indices; this.vertex.size = 3; }
      
      







Canvas最終バージョン:

 /*.  WebGl. canvasID - id  canvas  html */ function Scene(canvasID) { /*    */ this.backgroundColor = {red:1.0, green:1.0, blue:1.0, alpha:1.0}; /* */ this.canvas = document.getElementById(canvasID); /* webgl Context*/ this.getContext(); /*   */ this.indicBuffer = null; /* */ this.vecVertex = []; /* */ this.vecIndices = []; this.initProgram("vertexShader", "fragmentShader"); } Scene.prototype = { /* ,     */ clear: function(){ this.indicBuffer = null; this.vecVertex = []; this.vecIndices = []; }, /* WebGl Context,    */ getContext:function(){ var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; this.gl = null; for (var ii = 0; ii < names.length; ++ii) { try { this.gl = this.canvas.getContext(names[ii]); } catch(e) {} if (this.gl) { break; } } }, /*   .        vertex,   2  ,         2-  */ initBuffers: function (vertex, indices) { /*  */ this.vertexBuffer = this.gl.createBuffer(); /* */ this.vertexBuffer.size = vertex.size; /*  */ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer); /*   - botuPosition*/ this.program.botuPositionAttr = this.gl.getAttribLocation(this.program, "botuPosition"); /* ,        - this.program.botuPositionAttr*/ this.gl.enableVertexAttribArray(this.program.botuPositionAttr); /*  ,    Float32,    */ this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array(vertex), this.gl.STATIC_DRAW); /*    this.program.botuPositionAttr,   - this.vertexBuffer.size   */ this.gl.vertexAttribPointer(this.program.botuPositionAttr,this.vertexBuffer.size,this.gl.FLOAT,false,0,0); /*   */ if(indices) { /*  */ this.indicBuffer = this.gl.createBuffer(); /* -   - */ this.indicBuffer.numberOfItems = indices.length; /*  */ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indicBuffer); /*  ,     Uint16,    indices*/ this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW); } }, /*  , vxShaderDom - id  script      , frShaderDom - id  script       */ initProgram: function (vxShaderDom, frShaderDom) { /* */ var vxShader = document.getElementById(vxShaderDom).textContent; /* */ var frShader = document.getElementById(frShaderDom).textContent; /*    this.gl  :   vxShader    - frShader*/ this.program = createProgram(this.gl,vxShader, frShader); /*     */ this.gl.useProgram(this.program); /*     - vxs    - frs     context*/ function createProgram(context, vxs, frs) { /* */ var prg = context.createProgram(); /*  */ var VertexShader = createShader(context, context.VERTEX_SHADER, vxs); /*  */ var FragmentShader = createShader(context, context.FRAGMENT_SHADER, frs); /*  */ context.attachShader(prg,VertexShader); /*  */ context.attachShader(prg,FragmentShader); /*    - context*/ context.linkProgram(prg); /*  */ if (!context.getProgramParameter(prg, context.LINK_STATUS)) { /*  */ alert(context.getProgramInfoLog(prg)); } /*  */ return prg; } /*    context   type,    - shader*/ function createShader(context,type,shader) { /*    - type*/ var sh = context.createShader(type); /*  - shader*/ context.shaderSource(sh, shader); /*  */ context.compileShader(sh); /*   */ if (!context.getShaderParameter(sh, context.COMPILE_STATUS)) { /*   */ alert(context.getShaderInfoLog(sh)); } //   return sh; } }, /*  - width   - height */ setViewPort: function(width,height){ this.gl.viewportWidth = width; this.gl.viewportHeight = height; }, /*     colorVec*/ setBackgroundColor: function(colorVec){ if (colorVec){ if (colorVec.length > 0) { /* */ this.backgroundColor.red = colorVec[0]; } if (colorVec.length > 1) { /*- */ this.backgroundColor.green = colorVec[1]; } if (colorVec.length > 2) { /*- */ this.backgroundColor.blue = colorVec[2]; } } }, /*  botuObj  */ AddObject: function(botuObj){ /*   */ this.vecVertex.size = botuObj.vertex.size; /*-    */ var next = Math.max(this.vecVertex.length / this.vecVertex.size,0); /*  */ this.vecVertex = this.vecVertex.concat(botuObj.vertex); /*  ,              */ this.vecIndices = this.vecIndices.concat(botuObj.indices.map(function(i){return i + next})); /* */ this.vecVertex.size = botuObj.vertex.size; }, /**/ draw: function () { /*  */ this.gl.viewport(0, 0, this.gl.viewportWidth, this.gl.viewportHeight); /*  */ this.gl.clearColor(this.backgroundColor.red,this.backgroundColor.green,this.backgroundColor.blue,this.backgroundColor.alpha); /*- */ this.gl.clear(this.gl.COLOR_BUFFER_BIT); /*         this.vecVertex    this.vecIndices*/ this.initBuffers(this.vecVertex, this.vecIndices); /*    - DEPTH_TEST*/ this.gl.enable(this.gl.DEPTH_TEST); /*   -  - TRIANGLES, -  - this.indicBuffer.numberOfItems*/ this.gl.drawElements(this.gl.TRIANGLES, this.indicBuffer.numberOfItems, this.gl.UNSIGNED_SHORT, 0); } }
      
      







他の人のコードを読むことは、マスターのコードである場合を除いて、最も恩知らずなことです。 したがって、このコードは、すべてのメソッドについて簡単に説明しているわけではありません。







したがって、エンジンの最初の明らかな「欠陥」はシェーダーです。 次のようにインストールします。



  <script type="x-shader" id="vertexShader"> attribute vec3 botuPosition; varying vec4 colorPos; void main(){ colorPos = abs(vec4(botuPosition.x, botuPosition.y, botuPosition.z,200.0) / 200.0); gl_Position = vec4(botuPosition,200); } </script> <script type="x-shader" id="fragmentShader"> precision highp float; varying vec4 colorPos; void main(){ gl_FragColor = colorPos; } </script>
      
      







これは一時的なオプションです。 テクスチャリングを追加する場合-シェーダーを少し修正する必要があります。



次は何ですか



次の記事では、「自己記述型」マトリックスの説明。 また、最初の「通常の」プリミティブ-キューブ。



All Articles