2015-11-17 73 views
0

我正在用three.js写2D游戏。首先,我想渲染背景风景。然后,我想渲染一个透明的四边形(opacity === 0),即使您看不到它,它仍会将值写入深度缓冲区。然后,我想渲染具有z的片段,将它们的片段放置在透明四边形后面,以便由于未通过深度测试而丢弃与透明四边形相同的屏幕空间位置的片段。如何使用three.js中的深度缓冲区遮罩对象?

基于我对OpenGL的理解,这是可能的,但似乎three.js没有为透明四边形写入深度值,当我的透明四边形片段着色器的输出有gl_FragColor.a === 0时。

我已设置renderer.sortObjects = false。我有z = 0的背景,z = 1处的透明四边形以及深度缓冲区将在z = 0.5处遮挡的对象。

对于透明四边形,我设置了material.transparent = false,但不是在透明四边形上显示背景,而是显示清晰的颜色。

下面是我如何创建我的透明四:

let uniforms = { 
    color: { 
     type: 'v4', 
     value: new three.Vector4(0.2, 0.8, 0.8, 1), 
    }, 
    opacity: { 
     type: 'f', 
     value: 1, 
    }, 
    region_left: { 
     type: 'f', 
     value: -1, 
    }, 
    region_right: { 
     type: 'f', 
     value: -1, 
    }, 
    region_top: { 
     type: 'f', 
     value: -1, 
    }, 
    region_bottom: { 
     type: 'f', 
     value: -1, 
    }, 
} 

let vertex_shader = 
`varying vec2 screen_space_position; 

void main() 
{ 
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); 

    screen_space_position = mvPosition.xy; 

    gl_Position = projectionMatrix * mvPosition; 
}` 

let fragment_shader = 
`uniform vec4 color; 
uniform float opacity; 
uniform float region_left; 
uniform float region_right; 
uniform float region_top; 
uniform float region_bottom; 

varying vec2 screen_space_position; 

void main() 
{ 
    // The following just checks a 2D box I've defined in 'screen space' 
    // (really it's camera space, but I'm using an ortho camera where units 
    // are pixels) and sets the opacity to zero if the fragment is inside 
    // it. 
    float final_opacity = opacity; 
    vec2 position = screen_space_position; 
    if (position.x >= region_left && position.x <= region_right && 
     position.y >= region_top && position.y <= region_bottom) 
    { 
     final_opacity = 0.0; 
    } 

    gl_FragColor = vec4(color.rgb, color.a * final_opacity); 

    // I also tried just bypassing the above code and rendering 0 alpha 
    // across the entire quad 
    //gl_FragColor = vec4(1, 1, 1, 0); 
}` 

// Create geometry that represents a quad 
let geometry = new three.PlaneGeometry(1, 1) 

// PlaneGeometry assumes the lower left corner is (0, 0). This makes it 
// so the upper left corner is (0, 0). 
geometry.scale(1, -1, 1) 

let material = new three.ShaderMaterial({ 
    uniforms, 
    vertexShader: vertex_shader, 
    fragmentShader: fragment_shader, 
    transparent: true, 
}) 

let mesh = new three.Mesh(geometry, material) 

// Center the mesh 
mesh.position.set(0.5, 0.5, 0) 

let root = new three.Object3D() 
root.add(mesh) 
+0

也许three.js的默认autoClearDepth = true是由零alpha触发?从文档中不清楚测试是从深度缓冲区中移除一个对象的。 http://threejs.org/docs/#Reference/Renderers/WebGLRenderer – Radio

回答

2

以下作品的r73。解决方案是仔细控制您的three.MeshrenderOrderposition属性。

首先,我通过删除renderer.sortObjects = false行来重新开始排序。其次,我确保要遮罩的物体的位置置于透明四边形后面。

最后,我设置mesh.renderOrder = 1(即呈现任何其他啮合renderOrder < 1后此目)为three.Mesh对象为每个我想要的场景中的对象的被屏蔽并mesh.renderOrder = 0.5用于透明四边形。 renderOrder的默认值为0,所以任何网格的renderOrder我没有明确地将渲染设置为正常,在透明四边形和蒙版对象之前。

请注意,renderOrder必须设置为每个网格。该属性不会传播给子对象Object3D