在webgl碎片着色器中按颜色计数像素[英] Count pixels by color in webgl fragment shader

本文是小编为大家收集整理的关于在webgl碎片着色器中按颜色计数像素的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有2D纹理S,并且想要返回3D纹理H,因此Pixel H [r,g,b]等于纹理中的颜色RGB的像素数量.基本上是纹理中的颜色的直方图s.

我知道遮挡查询,但仅在WebGL2中可用,甚至只有布尔效果才能使用,此外,我还需要对每种颜色进行单独的查询.理想情况下,我想在一个碎片着色器通道中这样做.有什么方法可以减少片段着色器中的(折叠)操作?

为什么我需要这个(如果您有兴趣):

我试图在WebGL片段着色器中进行对象和静态地形之间的Perfect-Perfect 2D碰撞检测.

该计划是使用过去的技巧 - 绘制一个精灵4次 - 由(0,0),(0,dy),(dx,0)和(dx,dy)像素移动 - 并计数每次都可以计算物体应移动以尽快反弹的方向,每次都可以计算出代表矢量(NX,纽约)的矢量(NX,NY),从而与地形相撞.只需将矢量添加到物体的速度中,就可以使物体沿着地形(山下,跳到颠簸等)良好地滑动.我在旧的C ++游戏中使用了它,而且效果很好,但是JS的速度太慢.

我想在游戏中绘制所有精灵的整个顶点缓冲区(每个颜色都有不同的颜色以识别哪些对象相撞),每次在它们上绘制黑色地形,然后计算每种颜色的像素在结果的4架框架中.

问题是 - 如何计算片段着色器中的像素?

推荐答案

如何计算片段着色器中的像素?

一通行证可能 - 您可能会击中GPU超时异常或太多命令异常.我最近运行了一些配置文件以查看webGl中的限制:一个片段可以访问WebGL GLSL中的所有纹理像素值吗? (不仅是自己的Texcoord)

基本上是您要使用a for loop(或两个用于x/y的循环)以通过纹理上的每个像素迭代,此示例将所有颜色值添加到一个像素中:

void main() {
    vec4 color_register = 0.0;
    for (float x = 0.0; x < PIXELS_WIDE; x++) 
        for (float y = 0.0; y < PIXELS_TALL; y++) 
            color_register += texture2D(tex0, vec2(x / PIXELS_WIDE, y / PIXELS_TALL));
    gl_FragColor = color_register;
}

然后如果您希望每个像素代表不同颜色的总出现,则需要用C像素呈现到表面,其中C是唯一颜色的数量您想要一个直方图.这需要每个像素都必须意识到其颜色值,这最简单地通过拥有一个包含所有颜色的纹理来完成,并用紫外线(纹理坐标)对其进行采样,然后迭代实际场景中的所有像素,要进行直方图和计数那种颜色:

void main() {
    vec4 this_pixels_unique_color = texture2D(tex_unique_colors, tex_coord);
    int  occurrences_of_this_unique_color = 0;
    for (float x = 0.0; x < SCENE_PIXELS_WIDE; x++) 
        for (float y = 0.0; y < SCENE_PIXELS_TALL; y++) 
            color_register += texture2D(tex_scene_to_histogram, vec2(x / SCENE_PIXELS_WIDE, y / SCENE_PIXELS_TALL));
    gl_FragColor = vec4(occurrences_of_this_unique_color, occurrences_of_this_unique_color, occurrences_of_this_unique_color, 1);
}

将留下一个像素的渲染表面,每种独特的颜色,每个像素的黑暗表示该场景中的颜色的数量.

本文地址:https://www.itbaoku.cn/post/2091093.html

问题描述

I have 2d texture S and want to return 3d texture H, such that pixel H[r,g,b] is equal to number of pixels of color rgb in texture S. Basically histogram of colors in texture S.

I know about occlusion queries, but it's only available in webgl2, and IIUC even there only with boolean results, and besides I would need to do separate query for each color. Ideally I'd like to do this in one fragment shader pass. Is there any way to do reduce (fold) operations in fragment shaders?

Why I need this (if you're interested):

I'm trying to do pixel-perfect 2d collision detection between objects and static terrain in webgl fragment shaders.

The plan is to use trick from old days - drawing a sprite 4 times - moved by (0,0), (0, dy), (dx, 0), and (dx, dy) pixels - and count the pixels of the sprite colliding with terrain each time - from that I can calculate vector (nx, ny) that represents the direction that the object should move to bounce of the terrain as quickly as possible. Simply adding that vector to the velocity of the object makes the object slide nicely along the terrain (down the hills, jumping on the bumps, etc). I've used that in old C++ game and that works great, but it's too slow in js.

I want to draw the whole vertex buffer of all sprites in game (each in different color to be able to recognize which objects collide) 4 times, each time drawing the black terrain over them, and then count the pixels of each color in the resulting 4 framebuffers.

The problem is - how to count the pixels in fragment shader?

推荐答案

how to count the pixels in fragment shader?

In one pass, possibly - you risk hitting either a GPU timeout exception or a too many commands exception. I recently ran some profiles to see the limit in WebGL: Can one fragment access all texture pixel values in WebGL GLSL? (Not just it's own TexCoord)

Basically you want to use a for loop (or two for loops for x/y) to iterate through each pixel on the texture, this example adds all the color value into one pixel:

void main() {
    vec4 color_register = 0.0;
    for (float x = 0.0; x < PIXELS_WIDE; x++) 
        for (float y = 0.0; y < PIXELS_TALL; y++) 
            color_register += texture2D(tex0, vec2(x / PIXELS_WIDE, y / PIXELS_TALL));
    gl_FragColor = color_register;
}

Then if you wanted each pixel to represent the total occurrences of a different color, you would need to render to a surface with C pixels, where C is the number of unique colors you want a histogram of. This requires each pixel to be aware of it's color value, which is most simply done by having a texture containing all colors once, sampling from that with the UV (texture coordinate), then iterating all pixels in the actual scene to be histogramed and tallying that color:

void main() {
    vec4 this_pixels_unique_color = texture2D(tex_unique_colors, tex_coord);
    int  occurrences_of_this_unique_color = 0;
    for (float x = 0.0; x < SCENE_PIXELS_WIDE; x++) 
        for (float y = 0.0; y < SCENE_PIXELS_TALL; y++) 
            color_register += texture2D(tex_scene_to_histogram, vec2(x / SCENE_PIXELS_WIDE, y / SCENE_PIXELS_TALL));
    gl_FragColor = vec4(occurrences_of_this_unique_color, occurrences_of_this_unique_color, occurrences_of_this_unique_color, 1);
}

Leaving you with a rendered surface with one pixel for each unique color, where the darkness of each pixel represents the amount of that color in the scene histogramed.