readPixels returns all zero

1,460 views
Skip to first unread message

白玉雄

unread,
Jan 13, 2017, 12:07:51 PM1/13/17
to WebGL Dev List
Hi,
I want to read pixels in map which is drown in a webgl canvas.
gl.readPixels returns all zero in chrome console.
codes as follow:


<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
    <title>Map</title>
    <link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
    <script src="http://cache.amap.com/lbs/static/es5.min.js"></script>
    <script src="http://webapi.amap.com/maps?v=1.3&key=123"></script>
    <script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>
</head>
<body>
<div id="container"></div>
<script>
    var map = new AMap.Map('container', {
        resizeEnable: true,
        zoom:11,
        center: [116.397421, 39.80923]
    });

    map.on('moveend', function() {

        var canvas = document.getElementsByClassName("amap-layer")[0];
        var gl = canvas.getContext("webgl");
        //var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

        //gl.clear(gl.COLOR_BUFFER_BIT);

        var fb = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

        var tex = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, tex);
        var width = 10;
        var height = 10;
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

        
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);

        var pixels = new Uint8Array(width * height * 4);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.readPixels(10, 10, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
        console.log(pixels);
    });

</script>
</body>
</html>

Can anyone tell me how to make this work ?
thanks

Jaume Sánchez

unread,
Jan 13, 2017, 12:11:28 PM1/13/17
to webgl-d...@googlegroups.com
Have you tried with preserveDrawingBuffer uncommented?

--
You received this message because you are subscribed to the Google Groups "WebGL Dev List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webgl-dev-list+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

白玉雄

unread,
Jan 13, 2017, 12:14:31 PM1/13/17
to WebGL Dev List
Yes, I tried. not work. all zero.


在 2017年1月14日星期六 UTC+8上午1:11:28,Jaume Sánchez写道:
To unsubscribe from this group and stop receiving emails from it, send an email to webgl-dev-lis...@googlegroups.com.

Jaume Sánchez

unread,
Jan 13, 2017, 12:39:30 PM1/13/17
to webgl-d...@googlegroups.com
You can grab data from a canvas by simply doing:

var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
console.log(pixels); 

If the canvas has been created with preserveDrawingBuffer: true, you'll get values back.

The problem here -I think- is that you're trying to read from a canvas that is not yours, and it hasn't been created with that flag.
It doesn't matter if you try to getContext again on that canvas, you can't change it.

So a solution would be to make getContext to always set preserveDrawing to true.

Try this (even though I don't endorse doing this, ever! just for education purposes:)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>Map</title>
<link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
<script>

var getContext = HTMLCanvasElement.prototype.getContext;

HTMLCanvasElement.prototype.getContext = function(){

if( arguments[ 1 ] ) arguments[ 1 ].preserveDrawingBuffer = true;
var context = getContext.apply( this, arguments );
return context;

}

</script>
<script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>
</head>
<body>
<div id="container"></div>
<script>
var map = new AMap.Map('container', {
resizeEnable: true,
zoom:11,
center: [116.397421, 39.80923]
});

map.on('moveend', function() {

var canvas = document.getElementsByClassName("amap-layer")[0];
var gl = canvas.getContext("webgl");

var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
console.log(pixels);

});

</script>
</body>

This basically forces all getContext to use preserveDrawingBuffer to true. Since it runs before the AMap code, the library will create its WebGL rendering contexts with that flag set, and you'll be able to read it at a later point.

To unsubscribe from this group and stop receiving emails from it, send an email to webgl-dev-list+unsubscribe@googlegroups.com.

Jeff Dash

unread,
Jan 13, 2017, 7:13:47 PM1/13/17
to webgl-d...@googlegroups.com
Your problem is:

    var width = 10;
    var height = 10;
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    ...

    gl.readPixels(10, 10, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);


Since width and height are 10, your texture is 10x10, and your readpixel command is reading pixels between point (10,10) and (20,20). Since this is an out-of-bounds read, it either reads 0, or doesn't change the value of `pixels`. ArrayBuffers are initialized to zero, so either way, you'll only see zeros in the data after calling ReadPixels.


You want to use:
    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

白玉雄

unread,
Jan 14, 2017, 2:41:52 AM1/14/17
to WebGL Dev List
Your are right.

Thanks.

在 2017年1月14日星期六 UTC+8上午1:39:30,Jaume Sánchez写道:
Reply all
Reply to author
Forward
0 new messages