2019年8月5日 星期一

解決多個 WebGLRenderContext 之間無法共享資源的問題

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

沒有留言:

張貼留言