解決多個 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

沒有留言:
張貼留言