質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

WebGL

WebGL(ウェブジーエル)は、ウェブブラウザで 3次元コンピュータグラフィックスを表示させるための標準仕様です。

Q&A

解決済

1回答

2546閲覧

texImage2Dを実行するとエラーが発生する

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

WebGL

WebGL(ウェブジーエル)は、ウェブブラウザで 3次元コンピュータグラフィックスを表示させるための標準仕様です。

0グッド

0クリップ

投稿2019/02/04 09:13

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の範囲内で対応したいと考えています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんばんは。

ピュア WebGL でガリガリ書いていてすごいですね!
ただ、動かすためにはちょっとおかしなところがありそうでした……
私も、コードを拝見しただけで完璧に修正箇所がわかるわけではないので、僭越ながら、ご提供いただいたコードを使って組み直しをして、動かしてみました。

変更箇所には ★ をつけてあります。
参考になれば幸いです。

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <canvas id="sheet"></canvas> <canvas id="gl"></canvas> <input type="file" id="image"> <script> class Filter{ constructor(shader){ this.canvas=document.querySelector("#gl"); this.canvas.width=512; this.canvas.height=512; this.gl=this.canvas.getContext("webgl"); this.gl.viewport(0,0,512,512); this.gl.clearColor(0,0,0,1); let prog=this.gl.createProgram(); let vs=this.gl.createShader(this.gl.VERTEX_SHADER); this.gl.shaderSource(vs,` attribute vec2 position; varying vec2 vTexCoord; void main(){ vTexCoord = (position + 1.0).xy / 2.0; vTexCoord = vec2(vTexCoord.s, 1.0 - vTexCoord.t); // ★縦方向を反転 gl_Position = vec4(position,0.0,1.0); } `); this.gl.compileShader(vs); if (!this.gl.getShaderParameter(vs, this.gl.COMPILE_STATUS)) { console.log(this.gl.getShaderInfoLog(vs)); } this.gl.attachShader(prog,vs); let fs=this.gl.createShader(this.gl.FRAGMENT_SHADER); this.gl.shaderSource(fs,shader); this.gl.compileShader(fs); this.gl.attachShader(prog,fs); this.gl.linkProgram(prog); if (!this.gl.getProgramParameter(prog, this.gl.LINK_STATUS)) { console.log(this.gl.getProgramInfoLog(prog)); } this.prog=prog; } draw(canvas,option={}){ this.gl.useProgram(this.prog); this.gl.clear(this.gl.COLOR_BUFFER_BIT); let vertexPosAttr=this.gl.getAttribLocation(this.prog,"position"); let vertexBuf=this.gl.createBuffer(); let texture=this.gl.createTexture(); if(option.uniform){ Object.keys(option.uniform).forEach((k)=>{ let l=this.gl.getUniformLocation(this.prog,k); switch(option.uniform[k].length){ case 1: this.gl.uniform1f(l,option.uniform[k]); break; case 2: this.gl.uniform2f(l,option.uniform[k]); break; case 3: this.gl.uniform3f(l,option.uniform[k]); break; case 4: this.gl.uniform4f(l,option.uniform[k]); break; } }); } this.gl.bindTexture(this.gl.TEXTURE_2D,texture); this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,canvas); //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])); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); // ★テクスチャの uniform ロケーションに 0 を送る // ※これはたぶん省略しても問題ないけど一応 this.gl.uniform1i(this.gl.getUniformLocation(this.prog, 'texture'), 0); // ★テクスチャのバインドは解除しない // this.gl.bindTexture(this.gl.TEXTURE_2D,null); this.gl.bindBuffer(this.gl.ARRAY_BUFFER,vertexBuf); this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([ // ★ position が vec2 になってたので修正 // ★ あと並び順も TRIANGLE_STRIP 対応になってなかったので変えた -1.0, 1.0, 0.0, 1.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0 ]),this.gl.STATIC_DRAW); // ★ enableVertexAttribArray を追加 this.gl.enableVertexAttribArray(vertexPosAttr); this.gl.vertexAttribPointer(vertexPosAttr,3,this.gl.FLOAT,false,0,0); this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4); return this.canvas; } } let sepire=new Filter(` precision mediump float; varying vec2 vTexCoord; uniform sampler2D texture; void main(void){ vec4 color=texture2D(texture,vTexCoord); float g=color.r*0.03+color.g*0.59+color.b*0.11; gl_FragColor=vec4(g*0.94,g*0.78,g*0.57,color.a); } `); let image=new Image(); image.onload=()=>{ let canvas=document.querySelector("#sheet"); let ctx=canvas.getContext("2d"); canvas.width=512; canvas.height=512; ctx.drawImage(image,0,0,512,512,0,0,512,512); let s=sepire.draw(canvas); } document.querySelector("#image").onchange=(e)=>{ image.src=URL.createObjectURL(e.target.files[0]); } </script> </body> </html>

投稿2019/02/04 09:57

編集2019/02/04 10:06
doxas

総合スコア112

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/02/04 11:18

ご丁寧に添削までしていただき、ありがとうございます。無事期待通りの出力がされました。 いつもdoxasさんのQiitaの記事を見ています。わかりやすいのでこれからも参考にさせていただきますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問