Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alpha Blending with Integer Texture for Object Picking

Problem Description

Hi! In our WebGL application, we are drawing many (even hundreds of thousands) shapes and we want to discover which shape is currently under the mouse. I'm looking for a way to do it in an efficient manner.

Details

The shapes are defined with Signed Distance Functions. Each shape is drawn by applying a predefined sdf fragment shader to a square polygon (2 triangles). Each shape is assigned with a unique ID (uint) on the Rust side (we're using WASM here). The idea is to render the scene twice (in WebGL 1.0) or once to multiple render targets (in WebGL 2.0), where one of the targets would be the ID encoded as a color. Then we can use readPixels to query the color and get the ID of the shape under the mouse. Unfortunately, every solution that we try has some downsides.

Requirements

  • We need to encode 2 ints per shape (one to tell us what shape it was, like if it was a button, or maybe a slider), and second to tell us which instance of object it was (e.g. 5th slider).
  • We will have a lot of shapes (and instances) on the stage, so for each int we would need at least 24-bit, preferably 32-bit precision.

What he have tried so far

  • Rendering ID information to RGBA32UI texture type. In this solution we are using 32 bits per channel, so we can use 2 channels to represent our IDs. Unfortunately, blending applies only in RGBA mode and only if the color buffer has a fixed-point or floating-point format. We need some form of blending because when drawing shapes, like circles, some parts need to be transparent. In the case of ID color output our alpha is always 0 or 1.
  • Rendering ID information to RGBA texture and converting uint to float in GLSL by using intBitsToFloat and then back float to uint in Rust. Unfortunately, this is available in GLSL 330 and we are limited to GLSL 300 in WebGL.
  • Rendering ID information to RGB32UI texture and use discard for some pixels. This would work but it can cause performance problems and we would rather not like to use it.
  • Converting ID information on Rust side to float, using it instead of uint, and rendering it to RGBA texture, and converting it back to uint on Rust side. The problem with this solution is that it is pretty complex, we cannot use all of 32-bits (we need to be extra careful about possible NAN-encoding) and we feel there should be a better way to do it.
like image 335
Michael Mauderer Avatar asked Nov 06 '22 08:11

Michael Mauderer


1 Answers

Blending is considered to be part of the per-fragment functions that require floating point values, hence it has no effect when rendering to unnormalized integer textures.

From the spec section 4.1 lists 9 operations that happen with pixel/fragments.

Section 4.1.7 Blending which is operation 7 of the 9 operations says

Blending applies only if the color buffer has a fixed-point format. If the color buffer has an integer format, proceed to the next operation.

In other words, the blending operation is skipped if you're using an integer format.

Instead you can simply discard the fragment if the alpha value is below a given threshold.

if(alpha < 0.5) discard;
output_id = uvec4(input_symbol_id,input_instance_id,0,1);
like image 74
LJᛃ Avatar answered Nov 11 '22 09:11

LJᛃ