簡體   English   中英

平鋪渲染計算着色器光的剔除和着色

[英]Tiled rendering compute shader light culling and shading

我正在嘗試在OpenGL / GLSL中實現延遲平鋪渲染,但我堅持進行光剔除。

我的GPU較舊(AMD Radeon 6490m),由於奇怪的原因,當在共享變量上調用原子操作進行原子操作時,計算着色器會無限循環地運行,因此我無法使用計算着色器來計算最小和最大深度。 無論如何,這不是很費時的操作,因此我在片段着色器中進行操作。

然后,對於每個可見光(在視圖空間中),我計算屏幕空間邊界四邊形。 現在,我想使用單個計算着色器進行光剔除和着色。 問題是如上所述,我無法在共享變量上使用原子操作,因此無法構建圖塊燈光列表並存儲圖塊的燈光計數。

問題是我找不到其他方法可以做到這一點。任何想法如何使用非原子來剔除並建立瓷磚燈光列表?

這是我的計算着色器的偽代碼:

#version 430

#define MAX_LIGHTS  1024
#define TILE_SIZE   32
#define RX  1280
#define RY  720

struct Light {
    vec4 position;
    vec4 quad;
    vec3 color;
    float radius;
}

uint getTilesXCount(){
    return uint(( RX + TILE_SIZE - 1) / TILE_SIZE);
}

uint getTilesYCount(){
    return uint((RY + TILE_SIZE - 1) / TILE_SIZE);
}

layout (binding = 0, rgba16f) uniform readonly image2D minMaxTex;
layout (binding = 1, rgba16f) uniform readonly image2D diffTex;
layout (binding = 2, rgba16f) uniform readonly image2D specTex;

layout (std430, binding = 3) buffer pointLights {
    Light Lights[];
};


//tile light list & light count
shared uint lightIDs[MAX_LIGHTS];
shared uint lightCount = 0;

uniform uint totalLightCount;

layout (local_size_x = TILE_SIZE, local_size_y = TILE_SIZE) in;

void main(void){

        ivec2 pixel = ivec2(gl_GlobalInvocationID.xy);
        vec2 tile = vec2(gl_WorkGroupID.xy * gl_WorkGroupSize.xy) / vec2(1280, 720);

        //get minimum & maximum depth for tile
        vec2 minMax = imageLoad(minMax, tile).xy;

        uint threadCount = TILE_SIZE * TILE_SIZE;
        uint passCount = (totalLightCount + threadCount - 1) / threadCount; 

        for(uint i = 0; i < passCount; i++){

            uint lightIndex = passIt * threadCount + gl_LocalInvocationIndex;

            // prevent overrun by clamping to a last ”null” light
            lightIndex = min(lightIndex, numActiveLights);

            Light l = pointLights[lightIndex];

            if(testLightBounds(pixel, l.quad)){

                if ((minMax.y < (l.position.z + l.radius))
                    && 
                    (minMax.x > (l.position.z - l.radius))){


                    uint index;
                    index = atomicAdd(lightCount, 1);
                    pointLightIndex[index] = lightIndex;
                }
            }
        }

    barrier();

    //do lighting for actual tile
    color = doLight();

    imageStore(out, pos, color);
}

我還沒有真正實現平鋪延遲,但是我認為您可以采用類似於為模擬構建粒子相鄰列表的方式來實現。

  • 讓您的計算着色器構建一個包含光源和單元格ID的元組,並使用當前線程作為索引將其存儲在緩沖區中。
  • 使用您喜歡的GPU算法(基數排序或雙音排序)按單元ID對緩沖區進行排序。
  • 對緩沖區進行排序后,構建直方圖並進行前綴和掃描,以查找每個單元格在緩沖區中的起始位置。

例如

 (Cell, Light) 1st pass: Cell Buffer -> [ 23, 0 ] [ 7, 1 ] [ 9, 2 ] .... 2nd pass: Cell Buffer -> [ 7, 1 ] [ 9, 2 ] [ 23, 0 ] .... (Start, End) 3rd pass: Index Buffer -> [0 0] [0 0] [0 0] [0 0] [0 0] [0 0] [0 1] [1 1] [1 2] ... 

有關更多詳細信息,請參見Simon Green的“使用CUDA進行粒子仿真”中的方法: http : //idav.ucdavis.edu/~dfalcant/downloads/dissertation.pdf

原始方法假定粒子只能放置在單個單元格中,但是您應該能夠通過使用更大的工作量輕松解決此問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM