在GPU中聚类对象

时间:2015-10-20 14:50:41

标签: algorithm webgl

我的算法很容易进行聚类,就像这样。

第一个对象按所有其他对象分组,它们之间的距离低于X. 然后我们转到第二个对象,如果没有包含在第一个组中,我们对第一个组中未包含的其他对象运行相同的算法, 等等...

我正在尝试使用片段着色器在GPU中执行此算法。 首先,我将所有位置设置为RGBA浮动纹理。为每个像素设置位置(x,y) - z和w现在是免费的。然后我使用着色器绘制结果纹理我的计算。最后,我将读取结果纹理的像素并执行我的代码。

尝试了许多代码变体,多阶段绘制用于执行我的算法,但我对时间表现不满意。

问题是, 有没有办法在纹理上运行一个来执行我的愿望(单一绘制阶段)?

我最近的尝试是这个算法 - 我的片段着色器

precision highp float;

uniform sampler2D locs;
varying vec2 coord;
uniform float clusterDistance;
const float textureSize = 64.;

void main()
{
    // Getting my location
    vec4 currData = texture2D(locs, coord);
    float offsetPix = 1./textureSize/2.;
    vec2 coordIdx = (coord - offsetPix) * textureSize;
    // Getting the index of my location
    float myIdx = coordIdx.y * textureSize + coordIdx.x;
    int clusterIdx = 0;
    float clusterNum = 0.;
    // Running over all the other locations until me and finding the first close object to me
    for (float i=0.;i<textureSize*textureSize;++i)
    {
        clusterNum = i +1.;
        // Which mean that we didn't find any closed object to me so we stop
        if (i == myIdx)
        {
            break;
        } 
        else
        {
            vec2 pntLoc = vec2(mod(i, textureSize), floor(i/textureSize)) / textureSize+offsetPix;
            vec4 pnt = texture2D(locs, pntLoc);
            if (distance(currData.xy, pnt.xy) <= clusterDistance) 
            {
                break;
            }
        }
    }

    // Print the result
    gl_FragColor = vec4(currData.x, currData.y, clusterNum, 1.);
}

但问题在于结果会导致链聚类。对于前者 如果我们的数据是{0,0},{4,0},{8,0},并且到组的最大距离是4.那么第一个关闭到第二个。然后第三个接近第二个但不是第一个。根据我的算法,它返回第二个的索引,虽然第二个是在图片之外,因为按第一个对象分组,第一个是距离的参考对象。

写入时可以从结果纹理中读取吗?

它会解决我的问题,因为我可以在比较距离时检查结果的z值。

1 个答案:

答案 0 :(得分:0)

不,你不能在相同的传递中读取和写入纹理(使用标准的WebGL,我认为根本不是你想要的)。

你的算法本质上似乎是串行的,不太适合GPU / SIMD执行,但我可能会误解你的意图。请记住,GPU可以同时为多个数据点(在这种情况下为片段/像素)运行着色器程序,不知道其他数据点的结果。 您也无法在SIMD架构上摆脱for循环。 for循环将继续迭代,尽管不会为突破它的片段编写更改。换句话说,没有速度效益。如果中断条件评估所有片段的相同值,则会有不同的故事。

您可能希望了解其他群集方式,例如k-means。