解決多個 WebGLRenderContext 之間無法共享資源的問題
前言
在 多個 WebGLRenderContext 的問題 說過 WebGLRenderContext 之間的資源無法共享的問題,這樣像遊戲編輯器需要同時要繪製遊戲結果也要繪製資源(如Texture)的話該如何解決,目前想到這個方案"可能"可以解決,在此做個紀錄。內容
解決的方案是利用 WebGLRenderContext 先繪製資源後再輸出成 ImageElement ,接著在繪製遊戲結果,由於都是使用同一個 WebGLRenderContext 來繪製,所以不會有資源共享的問題,但有個問題,問題會發生在繪製資源時 CanvasElement 的大小與繪製遊戲結果時CanvasElement 的大小如果"不一樣",如果不一樣是否會在畫面上看到 CanvasElement 大小不斷變化的結果?目前在 Chrome 與 Firefox 實驗的結果是不會看到 CanvasElement 忽大忽小的過程,這樣雖然解決問題,但我目前還找不到也類似的範例與教學這樣使用 CanvasElement ,也就是說這個行為可能不是被保證可以用的。雖然這個方案不保證可以用,但它是目前唯一可以用的方案,留下這個方案的範例方便以後實驗與研究。具體的範例如下
HTML 的部分
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <canvas id="myCanvas" width="400px" height="300px"></canvas> <hr> <img id='myImage'></img> </body> </html>
JavaScript 的部分
let canvas = document.getElementById('myCanvas'); let glCTX = canvas.getContext('webgl'); let vertShader = glCTX.createShader(glCTX.VERTEX_SHADER); glCTX.shaderSource( vertShader , 'attribute vec3 pos;void main(void){gl_Position=vec4(pos, 1.0);}' ); glCTX.compileShader(vertShader); let fragShader = glCTX.createShader(glCTX.FRAGMENT_SHADER); glCTX.shaderSource( fragShader, 'precision mediump float;uniform vec4 myColor;void main(void){gl_FragColor=myColor;}' ); glCTX.compileShader(fragShader); let prog = glCTX.createProgram(); glCTX.attachShader(prog, vertShader); glCTX.attachShader(prog, fragShader); glCTX.linkProgram(prog); // let vertexBuf1 = glCTX.createBuffer(); glCTX.bindBuffer(glCTX.ARRAY_BUFFER, vertexBuf1); glCTX.bufferData( glCTX.ARRAY_BUFFER, new Float32Array([ 0.0,-0.9,0.0, -0.9,0.9,0.0, 0.9,0.9,0.0 ]), glCTX.STATIC_DRAW ); let vertexBuf2 = glCTX.createBuffer(); glCTX.bindBuffer(glCTX.ARRAY_BUFFER, vertexBuf2); glCTX.bufferData( glCTX.ARRAY_BUFFER, new Float32Array([ 0.0,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0 ]), glCTX.STATIC_DRAW ); let timeRad=0.0; let colorValue=[0.0, 0.0, 0.0, 1.0]; function simpleDraw(glContext,vbo,colorArray){ glContext.useProgram(prog); // glContext.viewport(0,0,glContext.canvas.width,glContext.canvas.height); glContext.clearColor(0, 0, 1, 1); glContext.clear(glContext.COLOR_BUFFER_BIT); glContext.bindBuffer(glContext.ARRAY_BUFFER, vbo); // let posLoc = glContext.getAttribLocation(prog, "pos"); glContext.vertexAttribPointer(posLoc, 3, glContext.FLOAT, false, 0, 0); glContext.enableVertexAttribArray(posLoc); let colorLoc = glContext.getUniformLocation(prog, 'myColor'); glContext.uniform4f(colorLoc,colorArray[0],colorArray[1],colorArray[2], colorArray[3] ); glContext.drawArrays(glContext.TRIANGLES, 0, 3); } function myRender(){ timeRad+=0.05; colorValue[0]=Math.sin(timeRad); glCTX.canvas.width = 400; glCTX.canvas.height = 300; simpleDraw(glCTX,vertexBuf1,colorValue); let imgEle = document.getElementById('myImage'); imgEle.src=glCTX.canvas.toDataURL(); // glCTX.canvas.width=200; glCTX.canvas.height=150; simpleDraw(glCTX,vertexBuf2,[1.0,1.0,1.0,1.0]); // window.requestAnimationFrame(myRender); } window.onload = function(){ window.requestAnimationFrame(myRender); }
執行結果如下
執行結果 |
這次的範例由 多個 WebGLRenderContext 的問題 更改而來, simpleDraw()會依據輸入 VBO 與 顏色繪製圖形,在 myRender() 會先將 CanvasElement 放大成 400*300,接著繪製 vertexBuf1與輸入的顏色, vertexBuf1 是一個倒三角,顏色的部分會依據時間從黑變紅,再由紅變黑持續轉變,接著將 CanvasElement 結果輸出圖片到 ImageElement ,也就是執行結果圖片下方的部分,如果對輸出圖片有疑問請參考 將canvas的結果輸出到image ,緊接著把 CanvasElement 放大成 200*150 ,繪製 vertexBuf2 ,顏色是白色。這次特地使用 requestAnimationFrame() 來更新畫面,主要是為了實驗在畫面持續更新下會不會發生 CanvasElement 忽大忽小的問題。
參考資料
Drawing a triangle with WebGL相關文章
多個 WebGLRenderContext 的問題將canvas的結果輸出到image
沒有留言:
張貼留言