如何使用 three.js 中的深度缓冲区来屏蔽对象?

How do I mask objects using the depth buffer in three.js?

我正在使用 three.js 编写 2D 游戏。首先,我要渲染背景风景。然后,我想渲染一个透明四边形 (opacity === 0),即使您看不到它,它仍然会向深度缓冲区写入值。然后我想渲染后面有一个 z 的对象,将它们的片段放在透明四边形后面,这样任何与透明四边形具有相同屏幕 space 位置的片段都会因深度测试失败而被丢弃。

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

我设置了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)

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

首先,我通过删除 renderer.sortObjects = false 行重新打开排序。其次,我确保要遮罩的对象的 z 位置将它们放在透明四边形后面。

最后,我为每个我想要遮罩的场景对象的 three.Mesh 对象设置 mesh.renderOrder = 1(即在使用 renderOrder < 1 的任何其他网格之后渲染此网格)并且mesh.renderOrder = 0.5 用于透明四边形。 renderOrder 的默认值是 0,所以任何网格的 renderOrder 我没有明确设置渲染为正常,在透明四边形和蒙版对象之前。

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