如何使用 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
renderOrder
和 position
属性是解决方案。
首先,我通过删除 renderer.sortObjects = false
行重新打开排序。其次,我确保要遮罩的对象的 z
位置将它们放在透明四边形后面。
最后,我为每个我想要遮罩的场景对象的 three.Mesh
对象设置 mesh.renderOrder = 1
(即在使用 renderOrder < 1
的任何其他网格之后渲染此网格)并且mesh.renderOrder = 0.5
用于透明四边形。 renderOrder
的默认值是 0
,所以任何网格的 renderOrder
我没有明确设置渲染为正常,在透明四边形和蒙版对象之前。
请注意,必须为每个网格设置 renderOrder
。此 属性 不会传播到子 Object3D
对象。
我正在使用 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
renderOrder
和 position
属性是解决方案。
首先,我通过删除 renderer.sortObjects = false
行重新打开排序。其次,我确保要遮罩的对象的 z
位置将它们放在透明四边形后面。
最后,我为每个我想要遮罩的场景对象的 three.Mesh
对象设置 mesh.renderOrder = 1
(即在使用 renderOrder < 1
的任何其他网格之后渲染此网格)并且mesh.renderOrder = 0.5
用于透明四边形。 renderOrder
的默认值是 0
,所以任何网格的 renderOrder
我没有明确设置渲染为正常,在透明四边形和蒙版对象之前。
请注意,必须为每个网格设置 renderOrder
。此 属性 不会传播到子 Object3D
对象。