2014-02-17 166 views
0

我試圖在WebGL中實現拾取。我有很多物品(大約500),我希望每個人都被允許被選中。爲了做到這一點,我做了一個環,其獨特的顏色分配給每個對象(參見採摘原理):WebGL:使用幀緩衝區來拾取多個對象

for (var i = 0, len = objects.length; i < len; i++) { 
    framecolors[count++] = i % 256/256; //Red 
    framecolors[count++] = Math.floor(i/256)/256; //Green 
    framecolors[count++] = Math.floor(i/(256*256))/256; //Blue 
} 

framecolors然後在古典緩衝用來檢查每一個對象是否具有不同色調紅。有效。

現在,我想使用我的對象的原始顏色,並在背景中使用紅色陰影的幀緩衝區。我已經通過了一些代碼,並且我有點困惑。

這是我到目前爲止嘗試過的。所謂

//Creates texture 
colorTexture = gl.createTexture(); 
gl.bindTexture(gl.TEXTURE_2D, colorTexture); 
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 400, 400, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 

//Creates framebuffer 
fb = gl.createFramebuffer(); 
gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0); 
gl.bindTexture(gl.TEXTURE_2D, colorTexture); 
gl.enable(gl.DEPTH_TEST); 

gl.bindFramebuffer(gl.FRAMEBUFFER, fb); 
gl.clear(gl.DEPTH_BUFFER_BIT); 
gl.drawArrays(gl.POINTS, 0, vertexPositionBuffer.numItems); 

功能後:

功能採摘之前調用

gl.bindFramebuffer(gl.FRAMEBUFFER, null); 
gl.bindTexture(gl.TEXTURE_2D, colorTexture); 
gl.drawArrays(gl.POINTS, 0, vertexPositionBuffer.numItems); 

正如你可能會明白,我不是很舒服的幀緩衝區,我真的不明白他們怎麼工作,即使我讀了很多關於他們。我不知道如何將framecolors鏈接到幀緩衝區。有沒有辦法?

謝謝, R.

回答

2

甲幀緩衝器是附件(renderbuffers和/或紋理)的集合。它的工作原理類似於沒有幀緩衝區的渲染。 (實際上瀏覽器在內部使用framebuffer來實現WebGL的畫布)

在你的情況下,你錯過了幾件事情。您最有可能需要附加深度緩衝區,否則當您渲染場景時,您將無法獲得zBuffering,並且錯誤的對象將出現在前面。

// create renderbuffer 
depthBuffer = gl.createRenderbuffer(); 
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); 

// allocate renderbuffer 
gl.renderbufferStorage(
     gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); 

// attach renderebuffer 
gl.framebufferRenderbuffer(
     gl.FRAMEBUFFER, 
     gl.DEPTH_ATTACHMENT, 
     gl.RENDERBUFFER, 
     depthBuffer); 

一般來說,你也應該檢查你的framebuffer的作品。連接所有的附件後,您撥打gl.checkFramebufferStatus

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { 
    alert("this combination of attachments does not work"); 
    return; 
} 

幀緩衝可以是不完整的任何原因。最常見的是附件大小不一樣,或者GPU不支持這些附件組合。注意:在WebGL中,某些組合需要工作,但是由於您稍後可能會更改代碼以使用不同的格式,因此檢查可能仍是一個好主意。

無論何時切換幀緩衝區,您還需要通過調用gl.viewport來設置視口。

gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer); 
gl.viewport(0, 0, someFramebufferWidth, someFramebufferHeight); 

,包括把它設置回東西的時候回到畫布

gl.bindFramebuffer(gl.FRAMEBUFFER, null); // render to canvas 
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 

最後有一個在上面的代碼中的錯誤你只清除其中調用幀緩衝的深度緩衝gl.clear。你想打電話給

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 

既然你要去讀顏色,否則舊的顏色將被留下。

最後,我想你知道這一點。你找出哪些像素對應於鼠標點擊,並呼籲

var colorPicked = new Uint8Array(4); 
gl.readPixels(pickX, pickY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, colorPicked); 

需要注意的是,當你調用gl.readPixels您必須在幀緩存gl.bindFramebuffergl.readPixels勢必會從畫布讀取。

1

非常感謝gman。只是爲了完成你的答案,關於如何在我的幀緩衝區中使用framecolors,這很簡單。在着色器,我添加了一個專用於幀緩衝的顏色變量:

if (!offscreen) { 
    gl_FragColor = normalColors; 
} 
else { 
    gl_FragColor = frameColors; 
} 

現在,determing我選擇得益於readPixels()功能哪個對象之前,我使用切換回幀緩衝器:

function renderFrame() { 
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb); //fb = framebuffer 
    gl.uniform1i(shaderProgram.uOffscreen, true); //uOffscreen = uniform boolean in shader 
    draw(); //function called to draw objects (contains gl.clear and gl.viewport) 
} 

同樣,我在調用該函數後切換回通常的緩衝區。

我試圖顯示幀緩衝區,而不是通常的緩衝區,當鼠標點擊。我有麻煩,但如果我找到它,我會在後面發佈解決方案。

編輯:解決方案:只需刪除與幀緩衝區關聯的深度緩衝區(渲染緩衝區)。然後按照以下說明顯示緩衝區:WebGL display framebuffer?