How does Cesium handle the depth texture?

1. A concise explanation of the problem you're experiencing.

I am working on custom render in Cesium and now I can draw something to framebuffer.

I try to draw the framebuffer to screen with its depth information. The color is drawn to the screen but the depth is incorrect.

I know that Cesium uses log depth by default, but I think it is not the cause of my problem because I merely want to copy the depth to the screen.

BTW, when render to the screen directly(set the option framebuffer : undefined) I get correct depth, but I need to
capture the render result for further process, so I have to render to framebuffer

2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.

Here is what I did, I extract the important parts of my code, you can see my complete code in my Github

1. setup the texture
    var createTexture = function (options, typedArray) {
        if (Cesium.defined(typedArray)) {
            // typed array needs to be passed as source option, this is required by Cesium.Texture
            var source = {};
            source.arrayBufferView = typedArray;
            options.source = source;

        var texture = new Cesium.Texture(options);
        return texture;

        const dataTextureSampler = new Cesium.Sampler({
            // the values of data texture should not be interpolated
            minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
            magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST

        const colorTextureOptions = {
            context: context,
            width: context.drawingBufferWidth,
            height: context.drawingBufferHeight,
            pixelFormat: Cesium.PixelFormat.RGBA,
            pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE,
            sampler: dataTextureSampler

        const depthTextureOptions = {
            context: context,
            width: context.drawingBufferWidth,
            height: context.drawingBufferHeight,
            pixelFormat: Cesium.PixelFormat.DEPTH_COMPONENT,
            pixelDatatype: Cesium.PixelDatatype.UNSIGNED_SHORT,
            sampler: dataTextureSampler

        colorTexture = createTexture(colorTextureOptions);
        depthTexture = createTexture(depthTextureOptions);

2. setup the framebuffer
    var createFramebuffer = function (colorTexture, depthTexture) {
        var framebuffer = new Cesium.Framebuffer({
            context: context,
            colorTextures: [colorTexture],
            depthTexture: depthTexture
        return framebuffer;

framebuffer = createFramebuffer(colorTexture, depthTexture);

3. setup the drawCommand
        var uniformMap = {
            screenColor: function () {
                return colorTexture;
            screenDepth: function () {
                return depthTexture;
new Cesium.DrawCommand({
                owner: this,
                vertexArray: createVertexArray(context),
                primitiveType: primitiveType,
                uniformMap: uniformMap,
                modelMatrix: Cesium.Matrix4.IDENTITY,
                shaderProgram: shaderProgram,
                framebuffer: framebuffer,
                renderState: renderState,
                pass: Cesium.Pass.OPAQUE

4. the glsl code

frag shader:

uniform sampler2D screenColor;
uniform sampler2D screenDepth;

varying vec2 textureCoordinate;

void main() {
    vec4 color = texture2D(screenColor, textureCoordinate);
  float depth = texture2D(screenDepth, textureCoordinate).r;
    gl_FragColor = color;
  gl_FragDepthEXT = depth;

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

I want to make a GPU particle system, you can see the full problem context in my previous threads:!topic/cesium-dev/gjjd9TNeY2A!topic/cesium-dev/7kCcITmGbEA

4. The Cesium version you're using, your operating system and browser.

Cesium 1.53

After several days work, I sort of figure it out.

It seems that Cesium store globeDepthTexture in the UniformState class.

The depth value will be encoded into RGBA unsigned bytes and stored into the globeDepthTexture

After looking into the source code, I think can use the built-in value czm_globeDepthTexture and the method czm_unpackDepth to get the depth value.

But I am not sure it is the right way because I still get incorrect depth in my custom render, maybe it is the problem of my own depth texture?

Anyway, I will continue to locate the problem, and I really hope someone can help me know more about how Cesium handle depth texture. Any help would be appreciated

Now I manage to fix the problem.

"float globeDepth = czm_unpackDepth(texture2D(czm_globeDepthTexture, textureCoordinate));" is the right way to get the depth value of Cesium.

I just did not write the correct depth value into my own texture.

Finally I am able to do a complete custom render in Cesium

Thank you so much for posting your solution here!

Hi: I've been trying to find scene depth maps in custom commands for a week now. I haven't found them yet. I've found you here. I hope to get your reply. It's better to send an email so that we can contact directly. Thank you very much!
If you are Chinese, I hope to get your WeChat.My WeChat is stcaizyl.

I opened on my phone (Safari、Chrome(76.0.3809.100)) and got some error message :frowning:

"RuntimeError: Fragment shader failed to compile. Compile log: ERROR: 0:27:‘gl_FragDepthEXT’ : undeclared identifier

ERROR: 0:27: ‘assign’ : l-value required (can’t modify a const)…"

Does it support mobile?
Sorry for my poor English.

touhou…@gmail.com於 2019年2月28日星期四 UTC+8下午12時58分54秒寫道:

I doubt your device does not support WebGL Extension EXT_frag_depth

You can check your device in

Besides, it is better to discuss such kind of problems on GitHub, because I seldom use Google Group