Bitshift in GLSL picker fragment shader assumes 32 bit of mediump int on device

GLSL version of GPUPicker’s fragment shader doesn’t specify precision of int, which causes on some mobile devices (Samsung Galaxy ones, A36 in particular, and according to some of my research, probably, Pixel phones too, but not iPhones) to pass blue component into red component with 16-bit shift. For example, mesh referenced by id 4 will be stored as [4,0,4] instead of [0,0,4] and thus not dereferenced back correctly.

I don’t have an ideal reproducable code, but here is something I’ve tried to do to show shader mismatch.

https://playground.babylonjs.com/#ZZW2I4#2

Here three planes should all be blue on PC - first one with mediump int, second with highp int, and third with float representation (like used for WebGL1 devices), and on 16-bit mediump int devices left one should be magenta.

The easiest solution, in my opinion, is to add precision highp int; for WebGL2 devices at the start of the shader

Here’s how playground example is rendered on my device

Thanks for the detailed report and repro. This is an engine bug: the WebGL2 GLSL picking shader was using integer bit shifts for the 24-bit picking ID without explicitly requesting high precision integers, so devices with lower-precision fragment mediump int could encode the ID incorrectly.

I opened a PR that adds precision highp int; to the GPUPicker GLSL fragment shader and includes a regression test to make sure it stays in place: [Collisions] Fix GPUPicker GLSL integer precision by Popov72 · Pull Request #18487 · BabylonJS/Babylon.js · GitHub