我想在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);
}