2012-09-07 118 views
3

我一直在關注html5rocks的一些教程,並且我設法制作了一個javascript程序,它使用webGL在畫布上顯示ONE圖像。我已經發布了下面的代碼。在WebGL中繪製多個2D圖像

問題是,似乎沒有人向您展示如何在webGL中繪製多個對象。我從來沒有直接使用過webGL,所以對我來說不是很直觀。

如何修改此代碼以繪製imageObjectArray中的每個對象? (請注意,我現在只是畫imageObjectArray[0]

function render(canvas, contextGL, imageObjectArray) { 
     vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader"); 
     fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader"); 

     program = createProgram(contextGL, [vertexShader, fragmentShader]); 
     contextGL.useProgram(program); 

     var positionLocation = contextGL.getAttribLocation(program, "a_position"); 

     var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord"); 

     var texCoordBuffer = contextGL.createBuffer(); 
     contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer); 

     contextGL.enableVertexAttribArray(texCoordLocation); 
     contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0); 

     setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0); 

     var texture = contextGL.createTexture(); 
     contextGL.bindTexture(contextGL.TEXTURE_2D, texture); 

     contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE); 
     contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE); 
     contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST); 
     contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST); 

     contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA, contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data); 

     var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution"); 
     contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height); 

     var buffer = contextGL.createBuffer(); 
     contextGL.bindBuffer(contextGL.ARRAY_BUFFER, buffer); 
     contextGL.enableVertexAttribArray(positionLocation); 
     contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0); 

     setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height); 

     // draw 
     contextGL.drawArrays(contextGL.TRIANGLES, 0, 6); 
    } 

function setRectangle(gl, x, y, width, height) { 
    var x2 = x + width; 
    var y2 = y + height; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
             [x, y, 
             x2, y, 
             x, y2, 
             x, y2, 
             x2, y, 
             x2, y2 
             ]), gl.STATIC_DRAW); 
} 

我在這裏的目的是要在(非常基本的)2D精靈的遊戲工作。如果沒有庫的舒適性。(除也許glMatrix.js)

[編輯]我的渲染功能有在它的錯誤,固定

回答

5

下面的代碼將執行以下操作:

  1. 編譯頂點和片段着色器
  2. 把它們鏈接在一起成一個着色器程序
  3. 創建一個頂點緩衝區來存放紋理座標和填充它(texCoordBuffer)
  4. 創建紋理(createTexture)
  5. 配置質地如何採樣(texParameteri)

以上5個步驟只需要運行一次即可。

vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader"); 
    fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader"); 

    program = createProgram(contextGL, [vertexShader, fragmentShader]); 
    contextGL.useProgram(program); 

    var positionLocation = contextGL.getAttribLocation(program, "a_position"); 

    var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord"); 

    var texCoordBuffer = contextGL.createBuffer(); 
    contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer); 

    contextGL.enableVertexAttribArray(texCoordLocation); 
    contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0); 

    var texture = contextGL.createTexture(); 
    contextGL.bindTexture(contextGL.TEXTURE_2D, texture); 

    contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE); 
    contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE); 
    contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST); 
    contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST); 

    setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0); 

代碼必須執行爲要繪製每個圖像的其餘部分,它具有以下功能:

  1. 上傳圖像到紋理(texImage2D)
  2. 創建一個頂點緩衝區堅守陣地並填充它(緩衝區)
  3. 呼叫drawArrays
 
    contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA,contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data); 

    var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution"); 
    contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height); 

    var buffer = contextGL.createBuffer(); 
    contextGL.bindBuffer(contextGL.ARRAY_BUFFER, buffer); 
    contextGL.enableVertexAttribArray(positionLocation); 
    contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0); 

    setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height); 

    // draw 
    contextGL.drawArrays(contextGL.TRIANGLES, 0, 6); 

您需要將步驟2分成不同的步驟。創建頂點緩衝區的第一步應該只執行一次。第二步,填寫圖像的位置,需要爲每個要繪製的圖像執行。

我應該說我的建議不會給出最佳實現,但它會讓你繪製多個圖像。爲了達到最佳效果,你應該考慮:

  • 實現紋理圖像(將所有圖像打包到單個紋理上)。
  • 只上傳一次紋理和位置座標。
  • 使用更好的頂點和片段着色器來接正在繪製哪個圖像(紋理座標偏移),在那裏它被繪製(位置偏移)和它應該多大(寬度&高度縮放)
+0

由於爲偉大的解釋!但是,你說:「你需要將步驟2分成不同的步驟。第一步,創建位置的頂點緩衝區,應該只執行一次」 - 你一次意味着什麼?我不是應該爲每個圖像執行整個第2步嗎? – Spectraljump

+0

你想將'var buffer = contextGL.createBuffer();'移出循環,其餘的依然存在。 – Cutch

+0

不要讓它更混亂,但另一種做法是在步驟2中創建一個單位矩形,並添加一些制服(如矩陣)以將該單位矩陣平移,縮放並旋轉到要繪製圖像的大小和位置。哪個更快或更好,更新每個圖像的緩衝區或爲每個圖像計算不同的矩陣,我不知道。 – gman