Skip to content

Commit f4e49d7

Browse files
committed
Fixes model-billboard depth interactions
1 parent edceb42 commit f4e49d7

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

packages/engine/Source/Scene/BillboardCollection.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import SDFSettings from "./SDFSettings.js";
3434
import TextureAtlas from "../Renderer/TextureAtlas.js";
3535
import VerticalOrigin from "./VerticalOrigin.js";
3636
import Ellipsoid from "../Core/Ellipsoid.js";
37+
import WebGLConstants from "../Core/WebGLConstants.js";
3738

3839
const SHOW_INDEX = Billboard.SHOW_INDEX;
3940
const POSITION_INDEX = Billboard.POSITION_INDEX;
@@ -2039,7 +2040,8 @@ BillboardCollection.prototype.update = function (frameState) {
20392040
) {
20402041
this._rsOpaque = RenderState.fromCache({
20412042
depthTest: {
2042-
enabled: false,
2043+
enabled: true,
2044+
func: WebGLConstants.LESS,
20432045
},
20442046
depthMask: true,
20452047
});
@@ -2059,7 +2061,10 @@ BillboardCollection.prototype.update = function (frameState) {
20592061
) {
20602062
this._rsTranslucent = RenderState.fromCache({
20612063
depthTest: {
2062-
enabled: false,
2064+
enabled: true,
2065+
func: useTranslucentDepthMask
2066+
? WebGLConstants.LEQUAL
2067+
: WebGLConstants.LESS,
20632068
},
20642069
depthMask: useTranslucentDepthMask,
20652070
blending: BlendingState.ALPHA_BLEND,

packages/engine/Source/Shaders/BillboardCollectionFS.glsl

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ void doThreePointDepthTest(float eyeDepth, bool applyTranslate) {
131131
}
132132
#endif
133133

134-
void doDepthTest() {
134+
// Extra manual depth testing is done to allow more control over how a billboard is occluded
135+
// by the globe when near and far from the camera.
136+
void doDepthTest(float globeDepth) {
135137
float temp = v_compressed.y;
136138
temp = temp * SHIFT_RIGHT1;
137139
float temp2 = (temp - floor(temp)) * SHIFT_LEFT1;
@@ -156,14 +158,10 @@ void doDepthTest() {
156158
}
157159
#endif
158160

159-
// Automatic depth testing of billboards is disabled (@see BillboardCollection#update).
160-
// Instead, we do one of two types of manual depth tests (potentially in addition to the test above), depending on the camera's distance to the billboard fragment.
161161
// If we're far away, we just compare against a flat, camera-facing depth-plane at the ellipsoid's center.
162162
// If we're close, we compare against the globe depth texture (which includes depth from the 3D tile pass).
163-
vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;
164-
float globeDepth = getGlobeDepthAtCoords(fragSt);
165-
if (globeDepth == 0.0) return; // Not on globe
166-
163+
164+
if (globeDepth == 0.0) return; // Not on globe
167165
float distanceToEllipsoidCenter = -length(czm_viewerPositionWC); // depth is negative by convention
168166
float testDistance = (eyeDepth > -u_coarseDepthTestDistance) ? globeDepth : distanceToEllipsoidCenter;
169167
if (eyeDepth < testDistance) {
@@ -175,7 +173,10 @@ void main()
175173
{
176174
if (v_splitDirection < 0.0 && gl_FragCoord.x > czm_splitPosition) discard;
177175
if (v_splitDirection > 0.0 && gl_FragCoord.x < czm_splitPosition) discard;
178-
doDepthTest();
176+
177+
vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;
178+
float globeDepth = getGlobeDepthAtCoords(fragSt);
179+
doDepthTest(globeDepth);
179180

180181
vec4 color = texture(u_atlas, v_textureCoordinates);
181182

@@ -243,6 +244,18 @@ void main()
243244
out_FragColor = color;
244245

245246
#ifdef LOG_DEPTH
246-
czm_writeLogDepth();
247+
// If we've made it here, we passed our manual depth test, above. But the automatic depth test will
248+
// still run, and some fragments of the billboard may clip against the globe. To prevent that,
249+
// ensure the depth value we write out is in front of the globe depth.
250+
float depthArg = v_depthFromNearPlusOne;
251+
252+
if (globeDepth != 0.0) { // On the globe
253+
float globeDepthFromNearPlusOne = (-globeDepth - czm_currentFrustum.x) + 1.0;
254+
float nudge = max(globeDepthFromNearPlusOne * 5e-6, czm_epsilon7);
255+
float globeOnTop = max(1.0, globeDepthFromNearPlusOne - nudge);
256+
depthArg = min(depthArg, globeOnTop);
257+
}
258+
259+
czm_writeLogDepth(depthArg);
247260
#endif
248261
}

0 commit comments

Comments
 (0)