2

手头的任务是向 Dart WebGL 应用程序添加波段选择工具。该工具将用于通过拖动鼠标在多个对象上绘制一个矩形。因此,可以在单个用户操作中选择/挑选多个对象。我目前正在使用 gl.readPixels() 从屏幕外渲染缓冲区中读取颜色。问题是,当一个大区域被波段选择时, gl.readPixels() 会发出数百万像素。扫描如此大量的颜色会浪费宝贵的时间来定位少数物体。

请任何人指出使用 Dart+WebGL 对多个对象进行波段选择的可能更快的方法。

作为参考,我在下面显示了波段选择工具的当前主要部分。

Uint8List _color = new Uint8List(4);

void bandSelection(int x, y, width, height, PickerShader picker, RenderingContext gl, bool shift) {

  if (picker == null) {
    err("bandSelection: picker not available");
    return;
  }

  int size = 4 * width * height;
  if (size > _color.length) {
    _color = new Uint8List(size);
  }

  gl.bindFramebuffer(RenderingContext.FRAMEBUFFER, picker.framebuffer);
  gl.readPixels(x, y, width, height, RenderingContext.RGBA, RenderingContext.UNSIGNED_BYTE, _color);

  if (!shift) {
    // shift is released
    _selection.clear();
  }

  for (int i = 0; i < size; i += 4) {

    if (_selection.length >= picker.numberOfInstances) {
      // selected all available objects, no need to keep searching
      break;
    }

    PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
    if (pi == null) {
      continue;
    }

    _selection.add(pi);
  }

  debug("bandSelection: $_selection");  
}

// findInstanceByColor is method from PickerShader
PickerInstance findInstanceByColor(int r, g, b) {
  return colorHit(_instanceList, r, g, b);
}

PickerInstance colorHit(Iterable<Instance> list, int r,g,b) {

  bool match(Instance i) {
    Float32List f = i.pickColor;
    return (255.0*f[0] - r.toDouble()).abs() < 1.0 &&
        (255.0*f[1] - g.toDouble()).abs() < 1.0 &&
        (255.0*f[2] - b.toDouble()).abs() < 1.0;
  }

  Instance pi;

  try {
    pi = list.firstWhere(match);
  } catch (e) {
    return null;
  }

  return pi as PickerInstance;
}
4

1 回答 1

1

现在我可以看到一些小的解决方案,它们可能会加快你的算法,以限制尽可能多地迭代你的所有元素,

您可以做的第一件事是使用默认颜色。当您看到该颜色时,您知道您不需要遍历整个元素数组。它将加速人口稀少的大片地区。很容易实现,只需要加一个if。

对于更密集的区域,您可以实现某种颜色缓存。这意味着您存储遇到的颜色数组。当您检查一个像素时,您首先检查缓存,然后遍历整个元素列表,如果找到该元素,则将其添加到缓存中。它应该加速包含少量大元素的案例,但如果你有很多小元素,这会很糟糕,如果你选择了这不太可能......你可以加速你的缓存购买按最后一次命中或/和数量排序你的缓存元素命中,很可能在连续的原始像素中找到相同的元素。它的工作量更大,但实施起来相对容易且时间短。

最后的优化是实现一个空间分区算法来过滤你想要检查的元素。那将是更多的工作,但从长远来看会得到更好的回报。

编辑:我不是飞镖专家,但这就是以基本方式实现前两个优化的样子:

var cache = new Map<UInt32, PickerInstance>();

for (int i = 0; i < size; i += 4) {
  UInt32 colour = _color[i] << 24 | _color[i+1] << 16 | _color[i+2] << 8 | 0; // I guess we can just skip transparency.

  if (_selection.length >= picker.numberOfInstances) {
    // selected all available objects, no need to keep searching
    break;
  }

  // black is a good default colour.
  if(colour == 0) {
    // if the pixel is black we didn't hit any element :(
    continue;
  }

  // check the cache
  if(cache[colour] != null) {
    _selection.add(cache[colour]);    
    continue;
  }

  // valid colour and cache miss, we can't avoid iterating the list.
  PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
  if (pi == null) {
    continue;
  }

  _selection.add(pi);
  // update cache
  cache[colour] = pi;
}
于 2013-12-23T14:01:17.533 回答