问题描述
问题描述
嗨!在我们的 WebGL 应用程序中,我们绘制了许多(甚至数十万)个形状,我们想发现当前鼠标下方的形状.我正在寻找一种有效的方法.
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.
详情
形状由有符号距离函数定义.每个形状都是通过将预定义的 sdf 片段着色器应用于方形多边形(2 个三角形)来绘制的.每个形状都在 Rust 端分配了一个唯一的 ID (uint
)(我们在这里使用 WASM).这个想法是将场景渲染两次(在 WebGL 1.0 中)或一次到多个渲染目标(在 WebGL 2.0 中),其中一个目标是编码为颜色的 ID.然后我们可以使用readPixels
来查询颜色并获取鼠标下的形状的ID.不幸的是,我们尝试的每个解决方案都有一些缺点.
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.
要求
- 我们需要为每个形状编码 2 个整数(一个告诉我们它是什么形状,比如它是一个按钮,或者可能是一个滑块),第二个告诉我们它是哪个对象实例(例如第 5 个滑块).
- 舞台上将有很多形状(和实例),因此对于每个 int,我们至少需要 24 位精度,最好是 32 位精度.
他迄今为止的尝试
- 将 ID 信息渲染为
RGBA32UI
纹理类型.在这个解决方案中,我们每个通道使用 32 位,因此我们可以使用 2 个通道来表示我们的 ID.不幸的是,混合仅适用于 RGBA 模式,并且仅当颜色缓冲区具有定点或浮点格式时才适用.我们需要某种形式的混合,因为在绘制形状(如圆形)时,某些部分需要透明.在 ID 颜色输出的情况下,我们的 alpha 始终为 0 或 1. - 将 ID 信息渲染为
RGBA
纹理并将uint
转换为 GLSL 中的float
使用 intBitsToFloat 然后返回float
到uint
在锈.不幸的是,这在 GLSL 330 中可用,而我们仅限于 WebGL 中的 GLSL 300. - 将 ID 信息渲染到
RGB32UI
纹理,并使用discard
处理一些像素.这可行,但会导致性能问题,我们宁愿不使用它. - 将 Rust 端的 ID 信息转换为
float
,使用它代替uint
,并将其渲染为RGBA
纹理,然后将其转换回来到 Rust 端的uint
.这个解决方案的问题是它非常复杂,我们不能使用所有的 32 位(我们需要特别小心可能的 NAN 编码),我们觉得应该有更好的方法来做到这一点.
- 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 convertinguint
tofloat
in GLSL by using intBitsToFloat and then backfloat
touint
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 usediscard
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 ofuint
, and rendering it toRGBA
texture, and converting it back touint
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.
推荐答案
Blending 被认为是需要浮点值的 per-fragment 函数的一部分,因此它在渲染到非规范化整数纹理时不起作用.
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.
来自规范第 4.1 节列出了像素/片段发生的 9 种操作.
From the spec section 4.1 lists 9 operations that happen with pixel/fragments.
第 4.1.7 节混合是 9 个操作中的第 7 个操作说
Section 4.1.7 Blending which is operation 7 of the 9 operations says
混合仅适用于颜色缓冲区具有定点格式的情况.如果颜色缓冲区为整数格式,进行下一步操作.
换句话说,如果您使用的是整数格式,则会跳过混合操作.
In other words, the blending operation is skipped if you're using an integer format.
相反,如果 alpha 值低于给定阈值,您可以简单地丢弃
片段.
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);
这篇关于用于对象拾取的 Alpha 混合与整数纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!