2015/06/25 現在執筆中。このページの情報はまだ不完全です。Please skip thie page.

WebGL (9)


シェーダ

頂点シェーダやフラグメントシェーダのプログラムを扱うためにWebGLでは次のようなオブジェクトを使います。

教科書のプログラムでは、頂点シェーダやフラグメントシェーダのプログラムを扱うために cuon-utils.jsの中の initShaders() 関数を使っていました。 これが行っているのは次のような一連の処理です。

  1. シェーダオブジェクトを作成する。 --- gl.createShader()
  2. シェーダオブジェクトにシェーダのプログラムのソースコードを格納する。--- gl.shaderSource()
  3. シェーダオブジェクトをコンパイルする。--- gl.compileShader()
  4. プログラムオブジェクトを作成する。--- gl.createProgram()
  5. プログラムオブジェクトにシェーダオブジェクトを設定する。 --- gl.attachShader()
  6. プログラムオブジェクトをリンクする。 --- gl.linkProgram()
  7. 使用するプログラムオブジェクトをWebGLシステムに伝える。 --- gl.useProgram()
シェーダのプログラムを扱う関数
gl.createShader(type)
  指定されたタイプのシェーダオブジェクトを作成する。
  @param type  gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
  @return      シェーダオブジェクト or null(エラー時)
  @error       INVALID_ENUM
gl.deleteShader(shader)
  シェーダオブジェクトを削除する。
  @param shader 削除すべきシェーダオブジェクト
  @return なし
  @error なし
gl.shaderSource(shader,source)
  シェーダオブジェクト shader に、ソースコード source を格納する。
  @param shader シェーダオブジェクト
  @param source ソースコード
  @return なし
  @error なし
gl.compileShader(shader)
  シェーダオブジェクト shader に格納されたソースコードをコンパイルする。
  @param shader シェーダオブジェクト
  @return なし
  @error なし
gl.げtSはでrPあらめて(shader、pname)
  シェーダオブジェクト shader から pname に関する情報を得る。
  @param shader シェーダオブジェクト
  @param pname  取得したい情報の種類。gl.SHADER_TYPE, gl.DELETE_STATUS or gl.COMPILE_STATUS
  @return 
    シェーダの種類 gl.VERTEX_SHADER or gl.FRAGMENT_SHADER   (pname がgl.SHADER_TYPE の場合)
    成功かどうか true or false    (pnameが gl.DELETE_STATUS の場合)
    成功かどうか true of false    (pnameが gl.COMPILE_STATUS の場合)
  @error INVALID_ENUM  間違ったpnameを指定した場合
gl.ge4tShaderInfoLog(shader)
  シェーダオブジェクト shader の情報ログを得る。
  @param shader シェーダオブジェクト
  @return 情報ログの文字列 or null
  @error なし
gl.createProgram()
  プログラムオブジェクトを作成する。
  @param なし
  @return プログラムオブジェクト or null
  @error なし
gl.deleteProgram(program)
  プログラムオブジェクト program を削除する。
  @param proguram 削除するプログラムオブジェクト
  @return なし
  @error なし
gl.attatchShader(program, shader)
  プログラムオブジェクト program をシェーダ shader に設定する。
  @param proguram プログラムオブジェクト
  @param shader   シェーダオブジェクト
  @return なし
  @error INVALID_OPERATION(既にシェーダにプログラムが設定されている場合)
gl.detatchShader(program, shader)
  プログラムオブジェクト program をシェーダ shader から取り外す。
  @param program プログラムオブジェクト
  @param shader   シェーダオブジェクト
  @return なし
  @error INVALID_OPERATION(shaderに設定されていない場合)
gl.linkProgram(program)
  プログラムオブジェクト program をリンクする。次のようなチェックを行う。
  「uniform変数の名前が正しいか」
  「頂点シェーダとフラグメントシェーダでvarying変数名が同じか」
  「頂点シェーダでvarying変数に値を書き込んでいるか」
  「使用しているattribute変数、uniform変数, varying変数が上限を越えていないか」
  @param program プログラムオブジェクト
  @return なし
  @error なし
gl.getProgramParameter(program,pname)
  プログラムオブジェクト program のpnameに関する情報を返す。
  @param program プログラムオブジェクト
  @param pname   gl.DELETE_STATUS, gl.LINK_STATUS, gl.VALIDAATE_STATUS,
                 gl.ATTACHED_SHADERS, gl.ACTIVE_ATTRIBUTES, gl.ACTIE_UNIFORMS
  @return true, false, or 数
  @error INVALID_ENUM (pnameの指定間違いの場合)
gl.getProgramInfoLog(program)
  プログラムオブジェクト program の情報ログを取り出す。pnameに関する情報を返す。
  @param program プログラムオブジェクト
  @return 情報ログを表す捩れつ or null
  @error なし
gl.useProgram(program)
  プログラムオブジェクト program を使用することを WebGL システムに伝える。
  @param program プログラムオブジェクト
  @return なし
  @error なし

シェーダを切り換える

Texture2.htmlを変更して、立方体をもう一つ生成してそちらはテクスチャ無しでレンダリングするようにしてみます。 シェーダを切り替えてレンダリングすることになります。

ChangeShader.htmlの変更点
*** Texture2.html	Sat Jun 23 01:19:06 2018
--- ChangeShader.html	Fri Jun 26 14:02:30 2015
***************
*** 10,15 ****
--- 10,16 ----
    <script src="tsuda-webgl.js"></script>
    <script language="JavaScript" type="text/javascript">
      //<![CDATA
+ // テクスチャを描くシェーダ Texture2.html
  var VSHADER_SOURCE = "\
  attribute vec4 a_Position;\n\
  attribute vec4 a_Normal;\n\
***************
*** 40,50 ****
      gl_FragColor = vec4(c.rgb,color.a);\n\
  }\n\
  ";
  function main() {
!     var app = tsuda.initWebGL("mycanvas",VSHADER_SOURCE,FSHADER_SOURCE);
!     if (!app) return;
!     var canvas = app.canvas;
!     var gl = app.gl;
  
      var vertices = tsuda.cube.vertices;
      var indices = tsuda.cube.indices;
--- 41,120 ----
      gl_FragColor = vec4(c.rgb,color.a);\n\
  }\n\
  ";
+ // 点の色で塗るシェーダ ParallelLightCube6.html
+ var VSHADER_SOURCE2 = "\
+ attribute vec4 a_Position;\n\
+ attribute vec4 a_Color;\n\
+ attribute vec4 a_Normal;\n\
+ uniform mat4 u_MvpMatrix;\n\
+ uniform mat4 u_NormalMatrix;\n\
+ uniform vec3 u_LightColor;\n\
+ uniform vec3 u_LightDirection;\n\
+ uniform vec3 u_AmbientLight;\n\
+ varying vec4 v_Color;\n\
+ void main() {\n\
+     gl_Position = u_MvpMatrix * a_Position;\n\
+     vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n\
+     float nDotL = max(dot(u_LightDirection,normal),0.0);\n\
+     vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;\n\
+     vec3 ambient = u_AmbientLight * a_Color.rgb;\n\
+     v_Color = vec4(diffuse+ambient,a_Color.a);\n\
+ }\n\
+ ";
+ var FSHADER_SOURCE2 = "\
+ precision mediump float;\n\
+ varying vec4 v_Color;\n\
+ void main() {\n\
+     gl_FragColor = v_Color;\n\
+ }\n\
+ ";
  function main() {
!     var canvas = document.getElementById("mycanvas");
!     if (!canvas || !canvas.getContext) {
!         console.log("canvas not supported"); return null;
!     }
!     var gl = getWebGLContext(canvas);
!     if (!gl) {
!         console.log("cannot get WebGL Context"); return null;
!     }
!     var solidProgram = createProgram(gl,VSHADER_SOURCE2,FSHADER_SOURCE2);
!     var texProgram = createProgram(gl,VSHADER_SOURCE,FSHADER_SOURCE);
!     if (!solidProgram || !texProgram) {
!         console.log("cannot init shader program"); return null;
!     }
!     solidProgram.a_Position = gl.getAttribLocation(solidProgram, 'a_Position');
!     solidProgram.a_Position = gl.getAttribLocation(solidProgram, 'a_Color);
!     solidProgram.a_Normal = gl.getAttribLocation(solidProgram, 'a_Normal);
!     solidProgram.u_MvpMatrix = gl.getUniformLocation(solidProgram, 'u_MvpMatrix);
!     solidProgram.u_NormalMatrix = gl.getUniformLocation(solidProgram, 'u_NormalMatrix);
!     solidProgram.u_LightColor = gl.getUniformLocation(solidProgram, 'u_LightColor);
!     solidProgram.u_LightDirection = gl.getUniformLocation(solidProgram, 'u_LightDirection');
!     solidProgram.u_AmbientLight = gl.getUniformLocation(solidProgram, 'u_AmbientLight);
! 
!     texProgram.a_Position = gl.getAttribLocation(texProgram, 'a_Position');
!     texProgram.a_Normal = gl.getAttribLocation(texProgram, 'a_Normal);
!     texProgram.a_TexCoord = gl.getAttribLocation(texProgram, 'a_TexCoord);
!     texProgram.u_MvpMatrix = gl.getUniformLocation(texProgram, 'u_MvpMatrix);
!     texProgram.u_NormalMatrix = gl.getUniformLocation(texProgram, 'u_NormalMatrix);
!     texProgram.u_LightColor = gl.getUniformLocation(texProgram, 'u_LightColor);
!     texProgram.u_LightDirection = gl.getUniformLocation(texProgram, 'u_LightDirection');
!     texProgram.u_AmbientLight = gl.getUniformLocation(texProgram, 'u_AmbientLight);
!     texProgram.u_Sampler = gl.getUniformLocation(texProgram, 'u_Sampler);
! 
!     if (solidProgram.a_Position < 0 || solidProgram.a_Position < 0 
!       || solidProgram.a_Normal < 0 || !solidProgram.u_MvpMatrix 
!       || !solidProgram.u_NormalMatrix || !solidProgram.u_LightColor 
!       || !solidProgram.u_LightDirection !! !solidProgram.u_AmbientLight 
!       || texProgram.a_Position < 0 || texProgram.a_Normal < 0
!       || texProgram.a_TexCoord < 0 || !texProgram.u_MvpMatrix
!       || !texProgram.u_NormalMatrix || !texProgram.u_LightColor
!       || !texProgram.u_LightDirection || !texProgram.u_AmbientLight
!       || !texProgram.u_Sampler) {
!         console.log("cannot get attribute or uniform variable"); return null;
!     }
! 
!     tsuda.canvas = canvas;
!     tsuda.gl = gl;
  
      var vertices = tsuda.cube.vertices;
      var indices = tsuda.cube.indices;
***************
*** 52,81 ****
      var texCoord = tsuda.cube.texCoord;
      var texture = gl.createTexture();
  
-     if (! tsuda.initArrayBuffer('a_Position',vertices,3,gl.FLOAT)) return;
-     if (! tsuda.initArrayBuffer('a_Normal',normals,3,gl.FLOAT)) return;
-     if (! tsuda.initArrayBuffer('a_TexCoord',texCoord,2,gl.FLOAT)) return;
  
      if (! tsuda.setElementArrayBuffer(indices)) return;
  
-     var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
-     var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
-     var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
-     var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection');
-     var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
-     var u_Sampler = gl.getUniformLocation(gl.program,'u_Sampler');
- 
-     if (! u_MvpMatrix || ! u_LightColor || ! u_LightDirection || ! u_AmbientLight
-         || ! u_NormalMatrix || ! u_Sampler ) {
-         console.log('failed to get location of uniform variable');
-         return;
-     }
- 
-     gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
-     var lightDirection = new Vector3([1.0, 0.8, 0.5]); // world coordinates
-     lightDirection.normalize();
-     gl.uniform3fv(u_LightDirection, lightDirection.elements);
-     gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
  
      var modelMatrix = new Matrix4();
      var viewMatrix = new Matrix4();
--- 122,130 ----
***************
*** 85,99 ****
  
      viewMatrix.setLookAt(-3.0, 5.0, 5.0, 0, 0, 0, 0, 1, 0);
      projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
!     modelMatrix.setTranslate(0, 0, -1);
!     modelMatrix.scale(0.7, 0.3, 0.6);
      modelMatrix.rotate(45, 0, 0, 1);
      mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
-     gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
      normalMatrix.setInverseOf(modelMatrix);
      normalMatrix.transpose();
      gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
  
      gl.enable(gl.DEPTH_TEST);
      gl.depthFunc(gl.LEQUAL);
  
--- 134,156 ----
  
      viewMatrix.setLookAt(-3.0, 5.0, 5.0, 0, 0, 0, 0, 1, 0);
      projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
! 
!     modelMatrix.setTranslate(0,1,0);
      modelMatrix.rotate(45, 0, 0, 1);
+     modelMatrix.scale(0.7, 0.3, 0.6);
      mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
      normalMatrix.setInverseOf(modelMatrix);
      normalMatrix.transpose();
+ 
+     gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
+     var lightDirection = new Vector3([1.0, 0.8, 0.5]); // world coordinates
+     lightDirection.normalize();
+     gl.uniform3fv(u_LightDirection, lightDirection.elements);
+     gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
+     gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
      gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
  
+ 
      gl.enable(gl.DEPTH_TEST);
      gl.depthFunc(gl.LEQUAL);
  
***************
*** 104,116 ****
--- 161,191 ----
         gl.bindTexture(gl.TEXTURE_2D,texture);
         gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
         gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image);
+ 
+        gl.useProgram(texProgram);
         gl.uniform1i(u_Sampler,0);
+        gl.bindTexture(gl.TEXTURE_2D,null);
+ 
  
         gl.clearColor(0.0, 0.0, 0.0, 1.0); // black
         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
         gl.drawElements(gl.TRIANGLES, indices.length,gl.UNSIGNED_BYTE,0);
      };
      image.src = "./sakura1024.jpg";
+ 
+     function drawTex() {
+       gl.useProgram(texProgram);
+       initAttributeVariable(gl, program.a_Position, o.vertexBuffer);
+   initAttributeVariable(gl, program.a_Normal, o.normalBuffer);    // 法線
+   initAttributeVariable(gl, program.a_TexCoord, o.texCoordBuffer);// テクスチャ座標
+   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, o.indexBuffer); // インデックスをバインドする
+ 
+   // テクスチャユニット0にテクスチャオブジェクトをバインドする
+   gl.activeTexture(gl.TEXTURE0);
+   gl.bindTexture(gl.TEXTURE_2D, texture);
+ 
+ 
+     }
  }
  //]]>
    </script>