OpenGL / WebGL - 渲染到纹理/帧缓冲两次时深度不正确?

时间:2017-12-26 13:24:19

标签: webgl

我正在尝试使用webgl在简单模型上实现体积渲染。为了实现这一点,我需要在单独的纹理中使用背面,只需通过渲染一个简单的纹理传递到这样:

var tx = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tx);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.RGBA, gl.FLOAT, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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);
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tx, 0);
//setup viewport
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
//setup culling and depth testing
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.FRONT);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LESS);
//render elements
if (model.index) {
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.drawElements(gl.TRIANGLES, numItems, gl.UNSIGNED_SHORT, 0);
}
else {
    gl.drawArrays(gl.TRIANGLES, numItems, 0);
}

这就像预期的那样,片段着色器只是一个:

gl_FragColor = vec4((0.5 * v_pos) + 1.0, 1.0);

enter image description here

然而,当我尝试将这个纹理从帧缓冲区传递到一个新的着色器时,我希望像这样执行实际的光线追踪/体积渲染:

//2nd renderpass to canvas
//switch program
//set current shader
context.shader = volPrgr;
//activate the shader
context.gl.useProgram(volPrgr);
var gl = context.gl;
var shader = context.shader;
if (!shader) {
    return;
}
init(gl);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
//setup viewport
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);

//init buffers
.
.
.

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tx);
//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
var textureLoc = gl.getUniformLocation(context.shader, 'u_back');
if (isValidUniformLocation(textureLoc) ){
    gl.uniform1i(textureLoc, 0);
}else{
    console.log(textureLoc + " is not a valid texturelocation.");
}
//send screensize needed for texture lookup
gl.uniform1i(gl.getUniformLocation(context.shader, 'u_screenRexX'), gl.drawingBufferWidth);
gl.uniform1i(gl.getUniformLocation(context.shader, 'u_screenRexY'), gl.drawingBufferHeight);
gl.disable(gl.CULL_FACE);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LESS);
//setup viewport
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//render elements
if (model.index) {
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.drawElements(gl.TRIANGLES, numItems, gl.UNSIGNED_SHORT, 0);
}
else {
    gl.drawArrays(gl.TRIANGLES, numItems, 0);
}

并在着色器中:

vec2 lookup = (vec2(gl_FragCoord.x/float(u_screenRexX), gl_FragCoord.y/float(u_screenRexY)));
vec3 back = vec3(texture2D(u_back, lookup)).rgb;
gl_FragColor = vec4(back.rgb, 1.0);

当我尝试使用屏幕空间坐标将纹理渲染到模型上时,我得到了这个:

enter image description here

这怎么可能?我可以更改体积着色器的深度顺序,以便正确地模拟模型/纹理(机翼前方的鸟头)吗?谢谢

1 个答案:

答案 0 :(得分:0)

我忘了为我的帧缓冲添加一个深度纹理,这就是诀窍:

  gl.getExtension( "WEBKIT_WEBGL_depth_texture" );
  gl.getExtension( "MOZ_WEBGL_depth_texture" );
  
  .
  .
  .
  
  var depth = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, depth);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);
    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.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depth, 0);
 
    //setup viewport
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
    gl.clearColor(0.9, 0.9, 0.9, 1.0);
    gl.clearDepth(1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.depthMask(true);
    gl.enable(gl.CULL_FACE);
    gl.cullFace(gl.FRONT);
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LESS);
    
    //render