JavaScriptで、画像に任意のフラグメントシェーダの処理を行うクラスを作成しています。
HTML
1<!DOCTYPE html> 2<html> 3<head> 4 <meta charset="utf-8"> 5</head> 6<body> 7 <canvas id="sheet"></canvas> 8 <canvas id="gl"></canvas> 9 <input type="file" id="image"> 10 <script> 11 class Filter{ 12 constructor(shader){ 13 this.canvas=document.querySelector("#gl"); 14 this.canvas.width=512; 15 this.canvas.height=512; 16 this.gl=this.canvas.getContext("webgl"); 17 this.gl.viewport(0,0,512,512); 18 this.gl.clearColor(0,0,0,1); 19 let prog=this.gl.createProgram(); 20 let vs=this.gl.createShader(this.gl.VERTEX_SHADER); 21 this.gl.shaderSource(vs,` 22 attribute vec2 position; 23 varying vec2 vTexCoord; 24 25 void main(){ 26 vTexCoord = (position + 1.0).xy / 2.0; 27 gl_Position = vec4(position,0.0,1.0); 28 } 29 `); 30 this.gl.compileShader(vs); 31 if (!this.gl.getShaderParameter(vs, this.gl.COMPILE_STATUS)) { 32 console.log(this.gl.getShaderInfoLog(vs)); 33 } 34 this.gl.attachShader(prog,vs); 35 let fs=this.gl.createShader(this.gl.FRAGMENT_SHADER); 36 this.gl.shaderSource(fs,shader); 37 this.gl.compileShader(fs); 38 this.gl.attachShader(prog,fs); 39 this.gl.linkProgram(prog); 40 if (!this.gl.getProgramParameter(prog, this.gl.LINK_STATUS)) { 41 console.log(this.gl.getProgramInfoLog(prog)); 42 } 43 this.prog=prog; 44 } 45 draw(canvas,option={}){ 46 this.gl.useProgram(this.prog); 47 this.gl.clear(this.gl.COLOR_BUFFER_BIT); 48 let vertexPosAttr=this.gl.getAttribLocation(this.prog,"position"); 49 let vertexBuf=this.gl.createBuffer(); 50 let texture=this.gl.createTexture(); 51 if(option.uniform){ 52 Object.keys(option.uniform).forEach((k)=>{ 53 let l=this.gl.getUniformLocation(this.prog,k); 54 switch(option.uniform[k].length){ 55 case 1: 56 this.gl.uniform1f(l,option.uniform[k]); 57 break; 58 case 2: 59 this.gl.uniform2f(l,option.uniform[k]); 60 break; 61 case 3: 62 this.gl.uniform3f(l,option.uniform[k]); 63 break; 64 case 4: 65 this.gl.uniform4f(l,option.uniform[k]); 66 break; 67 } 68 }); 69 } 70 this.gl.bindTexture(this.gl.TEXTURE_2D,texture); 71 72 this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,canvas); 73 //this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,1,1,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,new Uint8Array([255,0,0,255])); 74 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR); 75 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); 76 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); 77 this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); 78 this.gl.bindTexture(this.gl.TEXTURE_2D,null); 79 this.gl.bindBuffer(this.gl.ARRAY_BUFFER,vertexBuf); 80 this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([ 81 1.0,1.0, 82 -1.0,1.0, 83 -1.0,-1.0, 84 1.0,-1.0 85 ]),this.gl.STATIC_DRAW); 86 this.gl.vertexAttribPointer(vertexPosAttr,3,this.gl.FLOAT,false,0,0); 87 this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4); 88 return this.canvas; 89 } 90 } 91 let sepire=new Filter(` 92 precision mediump float; 93 varying vec2 vTexCoord; 94 uniform sampler2D texture; 95 void main(void){ 96 vec4 color=texture2D(texture,vTexCoord); 97 float g=color.r*0.03+color.g*0.59+color.b*0.11; 98 gl_FragColor=vec4(g*0.94,g*0.78,g*0.57,color.a); 99 } 100 `); 101 let image=new Image(); 102 image.onload=()=>{ 103 let canvas=document.querySelector("#sheet"); 104 let ctx=canvas.getContext("2d"); 105 canvas.width=512; 106 canvas.height=512; 107 ctx.drawImage(image,0,0,512,512,0,0,512,512); 108 let s=sepire.draw(canvas); 109 } 110 document.querySelector("#image").onchange=(e)=>{ 111 image.src=URL.createObjectURL(e.target.files[0]); 112 } 113 </script> 114</body> 115</html> 116
画像ファイルを参照し、ロードが完了するとcanvasに描画され、canvasの内容がWebGLのテクスチャに登録されてシェーダープログラムによってセピア加工され描画されるという動作を期待しているのですが、次のようなエラーが発生します。
RENDER WARNING: there is no texture bound to the unit 0
調べてみるとテクスチャ用の画像のロードが完了していないときに発生するエラーということなのですが、canvasではなくonload発生時の画像を引数に与えても、1x1のArrayBufferの色情報を与えても同じエラーが発生しました。原因はどこでしょうか。
WebGL2.0では対応ブラウザが少ないので、WebGL1.0の範囲内で対応したいと考えています。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2019/02/04 11:18