diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index c7851eeb4..de192382c 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -94,6 +94,9 @@ Renderer::Renderer(Tempest::Swapchain& swapchain) settings.swrEnabled = Gothic::options().swRenderingPreset>0; settings.swrtEnabled = Gothic::options().doSoftwareRT; + sky.sampler = Tempest::Sampler::bilinear(); + sky.sampler.vClamp = ClampMode::ClampToEdge; + sky.cloudsLut = device.image2d (sky.lutRGBAFormat, 2, 1); sky.transLut = device.attachment(sky.lutRGBFormat, 256, 64); sky.multiScatLut = device.attachment(sky.lutRGBFormat, 32, 32); @@ -368,6 +371,22 @@ ZBuffer& Renderer::usesZBuffer(Tempest::ZBuffer& ret, Tempest::TextureFormat frm return ret; } +Attachment& Renderer::usesAttachment(Tempest::Attachment& ret, Tempest::TextureFormat frm, Tempest::Size size) { + if(textureCast(ret).format()==frm && ret.size()==size) + return ret; + Resources::recycle(std::move(ret)); + ret = Resources::device().attachment(frm, size); + return ret; + } + +Attachment& Renderer::usesAttachment(Tempest::Attachment& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h) { + if(textureCast(ret).format()==frm && uint32_t(ret.w())==w && uint32_t(ret.h())==h) + return ret; + Resources::recycle(std::move(ret)); + ret = Resources::device().attachment(frm, w, h); + return ret; + } + StorageBuffer& Renderer::usesSsbo(Tempest::StorageBuffer& ret, size_t size) { if(ret.byteSize()==size) return ret; @@ -416,7 +435,8 @@ void Renderer::resetShadowmap() { for(int i=0; i& cmd, WorldVi sz = Vec2(float(sky.multiScatLut.w()), float(sky.multiScatLut.h())); cmd.setFramebuffer({{sky.multiScatLut, Tempest::Discard, Tempest::Preserve}}); - cmd.setBinding(0, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(0, sky.transLut, sky.sampler); cmd.setPushData(&sz, sizeof(sz)); cmd.setPipeline(shaders.skyMultiScattering); cmd.draw(nullptr, 0, 3); @@ -519,8 +539,8 @@ void Renderer::prepareSky(Tempest::Encoder& cmd, WorldVi auto sz = Vec2(float(sky.viewLut.w()), float(sky.viewLut.h())); cmd.setFramebuffer({{sky.viewLut, Tempest::Discard, Tempest::Preserve}}); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(1, sky.transLut, sky.sampler); + cmd.setBinding(2, sky.multiScatLut, sky.sampler); cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setPushData(&sz, sizeof(sz)); cmd.setPipeline(shaders.skyViewLut); @@ -529,7 +549,7 @@ void Renderer::prepareSky(Tempest::Encoder& cmd, WorldVi sz = Vec2(float(sky.viewCldLut.w()), float(sky.viewCldLut.h())); cmd.setFramebuffer({{sky.viewCldLut, Tempest::Discard, Tempest::Preserve}}); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.viewLut); + cmd.setBinding(1, sky.viewLut, sky.sampler); cmd.setBinding(2, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear()); cmd.setBinding(3, *wview.sky().cloudsDay() .lay[1], Sampler::trillinear()); cmd.setBinding(4, *wview.sky().cloudsNight().lay[0], Sampler::trillinear()); @@ -579,8 +599,7 @@ void Renderer::dbgDraw(Tempest::Painter& p) { //tex.push_back(&textureCast(shadowMap[0])); //tex.push_back(&textureCast(vsm.pageData)); //tex.push_back(&textureCast(swrt.outputImage)); - tex.push_back(&textureCast(surf.dbgImage)); - //tex.push_back(&textureCast(surf.irrImage)); + tex.push_back(&textureCast(surf.irrImage)); static int size = 400; int left = 10; @@ -905,7 +924,7 @@ void Renderer::drawSunMoon(Tempest::Encoder& cmd, const cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, isSun ? wview.sky().sunImage() : wview.sky().moonImage()); - cmd.setBinding(2, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(2, sky.transLut, sky.sampler); cmd.setPushData(push); cmd.setPipeline(shaders.sun); cmd.draw(nullptr, 0, 6); @@ -1648,7 +1667,7 @@ void Renderer::drawReflections(Encoder& cmd, const WorldView& wvi cmd.setBinding(3, gbufNormal, Sampler::nearest (ClampMode::ClampToEdge)); cmd.setBinding(4, zbuffer, Sampler::nearest (ClampMode::ClampToEdge)); cmd.setBinding(5, sceneDepth, Sampler::nearest (ClampMode::ClampToEdge)); - cmd.setBinding(6, sky.viewCldLut); + cmd.setBinding(6, sky.viewCldLut, sky.sampler); cmd.setPipeline(pso); if(Gothic::options().doMeshShading) { cmd.dispatchMeshThreads(gbufDiffuse.size()); @@ -1773,8 +1792,8 @@ void Renderer::drawSky(Encoder& cmd, const WorldView& wview) { cmd.setDebugMarker("Sky"); if(sky.quality==PathTrace) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(1, sky.transLut, sky.sampler); + cmd.setBinding(2, sky.multiScatLut, sky.sampler); cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setBinding(4, zbuffer, Sampler::nearest()); cmd.setBinding(5, shadowMap[1], Resources::shadowSampler()); @@ -1785,10 +1804,10 @@ void Renderer::drawSky(Encoder& cmd, const WorldView& wview) { auto& skyShader = sky.quality==VolumetricLQ ? shaders.sky : shaders.skySep; cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(3, sky.viewLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(4, sky.fogLut3D); + cmd.setBinding(1, sky.transLut, sky.sampler); + cmd.setBinding(2, sky.multiScatLut, sky.sampler); + cmd.setBinding(3, sky.viewLut, sky.sampler); + cmd.setBinding(4, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge)); if(sky.quality!=VolumetricLQ) cmd.setBinding(5, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setBinding(6, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear()); @@ -1840,12 +1859,12 @@ void Renderer::prepareFog(Encoder& cmd, WorldView& wview auto& shader = sky.quality==VolumetricLQ ? shaders.fogViewLut3d : shaders.fogViewLutSep; cmd.setFramebuffer({}); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(1, sky.transLut, sky.sampler); + cmd.setBinding(2, sky.multiScatLut, sky.sampler); cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(4, sky.fogLut3D); + cmd.setBinding(4, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge)); if(sky.quality==VolumetricHQ || sky.quality==Epipolar) - cmd.setBinding(5, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(5, sky.fogLut3DMs); cmd.setPipeline(shader); cmd.dispatchThreads(uint32_t(sky.fogLut3D.w()), uint32_t(sky.fogLut3D.h())); } @@ -1898,7 +1917,7 @@ void Renderer::prepareFog(Encoder& cmd, WorldView& wview cmd.setBinding(2, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(3, epipolar.epipoles); cmd.setBinding(4, zbuffer); - cmd.setBinding(5, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(5, sky.transLut, sky.sampler); cmd.setBinding(6, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setBinding(7, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.vsmFogTrace); @@ -1943,19 +1962,18 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(settings.giMethod!=GiMethod::IrrC || !settings.zCloudShadowScale) return; - const uint32_t maxSurfels = surf.maxSurfels; - const int32_t tileSize = 128; - const int32_t DefaultCoverage = 128; - const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); + const uint32_t maxSurfels = surf.maxSurfels; + const int32_t TileSize = 96; + const int32_t LargeTile = 128; + const auto binCount = tileCount(zbuffer.size(), TileSize); - auto& scene = wview.sceneGlobals(); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); + auto& scene = wview.sceneGlobals(); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); - auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); - auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); + auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); struct Push { Vec3 originLwc; @@ -1963,11 +1981,19 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor uint32_t pass; } push = {}; push.originLwc = scene.originLwc; - push.tileSize = uint32_t(tileSize); + push.tileSize = uint32_t(TileSize); push.pass = 0; cmd.setDebugMarker("Surfels"); + if(surf.gbuffFree.isEmpty()) { + auto& gbuffFree = usesSsbo(surf.gbuffFree, shaders.surfFList.sizeofBuffer(0, maxSurfels)); + cmd.setPushData(surf.gbufTilesX); + cmd.setBinding(0, gbuffFree); + cmd.setPipeline(shaders.surfFList); + cmd.dispatchThreads(maxSurfels); + } + // prev-frame { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); @@ -1976,35 +2002,20 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfUpdate); cmd.dispatchThreads(maxSurfels); - } - - static bool gc = true; - if(gc) { - surfelsBinning(cmd, wview, tileSize, false); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, hiz.hiZ); cmd.setBinding(2, zbuffer); cmd.setBinding(3, surfels); - // - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, surfList); - + cmd.setBinding(4, surf.gbuffFree); cmd.setPushData(scene.znear); - cmd.setPipeline(shaders.surfCulling); - cmd.dispatchThreads(maxSurfels); - cmd.setPushData(push); - cmd.setPipeline(shaders.surfBinSort); // assist with stable GC - cmd.dispatch(surfBins.size()); - - cmd.setPipeline(shaders.surfDecimate); + cmd.setPipeline(shaders.surfCulling); cmd.dispatchThreads(maxSurfels); cmd.setPipeline(shaders.surfCompact); cmd.dispatch(1); - } + } static bool rays = true; if(rays) { @@ -2013,23 +2024,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor static bool apply = true; if(apply) { - surfelsBinning(cmd, wview, tileSize, false); - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage); - cmd.setBinding(2, gbufNormal); - cmd.setBinding(3, zbuffer); - cmd.setBinding(4, surfels); - // - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, surfList); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfApply); - cmd.dispatchThreads(zbuffer.size()); + surfelsBinning(cmd, wview, TileSize, false); + surfelsApply(cmd, wview, TileSize, false); } // current-frame @@ -2041,16 +2037,31 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(2, gbufNormal); cmd.setBinding(3, zbuffer); cmd.setBinding(4, surfels); + cmd.setBinding(5, surf.gbuffFree); + + const auto tc = tileCount(zbuffer.size(), LargeTile); + cmd.setPipeline(shaders.surfAlloc); + cmd.dispatch(tc); + } + + static bool gc = true; + if(gc) { + surfelsBinning(cmd, wview, TileSize, false); + + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(3, surfels); // cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfList); - // - cmd.setBinding(11, dbgImage); - const auto tc = tileCount(zbuffer.size(), 128); - cmd.setPipeline(shaders.surfAlloc); - cmd.dispatch(tc); + //cmd.setPushData(push); + //cmd.setPipeline(shaders.surfBinSort); // assist with stable GC + //cmd.dispatch(surfBins.size()); + + cmd.setPushData(push); + cmd.setPipeline(shaders.surfDecimate); + cmd.dispatchThreads(maxSurfels); } if(rays) { @@ -2058,25 +2069,45 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } if(apply) { - surfelsBinning(cmd, wview, tileSize, true); + surfelsBinning(cmd, wview, TileSize, true); + surfelsApply(cmd, wview, TileSize, true); + } + } - push.pass = 1; - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage); - cmd.setBinding(2, gbufNormal); - cmd.setBinding(3, zbuffer); - cmd.setBinding(4, surfels); - // - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, surfList); - // - cmd.setBinding(11, dbgImage); +void Renderer::surfelsApply(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass) { + auto& scene = wview.sceneGlobals(); - cmd.setPipeline(shaders.surfApply); - cmd.dispatchThreads(zbuffer.size()); - } + auto& irrImage = surf.irrImage; + auto& surfels = surf.surfels; + auto& surfCnts = surf.surfCnts; + auto& surfBins = surf.surfBins; + auto& surfList = surf.surfList; + + // auto& irrImage2 = usesAttachment(surf.irrImage2, TextureFormat::RGBA16F, zbuffer.size()); + // (void)irrImage2; + + struct Push { + Vec3 originLwc; + uint32_t tileSize; + uint32_t pass; + } push = {}; + push.originLwc = scene.originLwc; + push.tileSize = uint32_t(tileSize); + push.pass = postPass ? 1 : 0; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, irrImage); + cmd.setBinding(2, gbufNormal); + cmd.setBinding(3, zbuffer); + cmd.setBinding(4, surfels); + // + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfList); + + cmd.setPipeline(shaders.surfApply); + cmd.dispatchThreads(zbuffer.size()); } void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass) { @@ -2123,25 +2154,48 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor } void Renderer::surfelsTrace(Tempest::Encoder& cmd, WorldView& wview, StorageBuffer& surfels, bool postPass) { + static int giMethod = 0; + auto& scene = wview.sceneGlobals(); + const Tempest::ComputePipeline* pso = &shaders.surfRaycast; + if(giMethod==1) + pso = &shaders.surfPathtrace; + + const uint32_t gbufX = surf.gbufTilesX * uint32_t(surf.gbufTile.x); + const uint32_t gbufY = surf.gbufTilesY * uint32_t(surf.gbufTile.y); + + auto& gbuffDiff = usesImage2d(surf.gbuffDiff, TextureFormat::RGBA8, gbufX, gbufY); + auto& gbuffNorm = usesImage2d(surf.gbuffNorm, TextureFormat::RGBA8, gbufX, gbufY); + auto& gbuffHitT = usesImage2d(surf.gbuffHitT, TextureFormat::R16, gbufX, gbufY); + const uint32_t pass = postPass ? 1 : 0; cmd.setPushData(pass); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, surfels); - cmd.setBinding(2, sky.viewCldLut); - // + cmd.setBinding(2, sky.viewCldLut, sky.sampler); + cmd.setBinding(3, gbuffDiff); + cmd.setBinding(4, gbuffNorm); + cmd.setBinding(5, gbuffHitT); cmd.setBinding(6, scene.rtScene.tlas); cmd.setBinding(7, Sampler::trillinear()); cmd.setBinding(8, scene.rtScene.tex); cmd.setBinding(9, scene.rtScene.vbo); cmd.setBinding(10,scene.rtScene.ibo); cmd.setBinding(11,scene.rtScene.rtDesc); + cmd.setBinding(12,shadowMap[1]); - cmd.setPipeline(shaders.surfPathtrace); - //cmd.dispatchThreads(maxSurfels); + cmd.setPipeline(*pso); const uint32_t offset = postPass ? sizeof(uint32_t) : 0; - cmd.dispatchIndirect(surfels, offset); + if(!(giMethod==0 && postPass==false)) { + cmd.dispatchIndirect(surfels, offset); + // cmd.dispatchThreads(maxSurfels); + } + + if(giMethod==0) { + cmd.setPipeline(shaders.surLighting); + cmd.dispatchIndirect(surfels, offset); + } } void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { @@ -2151,7 +2205,7 @@ void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) cmd.setFramebuffer({}); cmd.setBinding(0, sky.irradianceLut); cmd.setBinding(1, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(2, sky.viewCldLut); + cmd.setBinding(2, sky.viewCldLut, sky.sampler); cmd.setPipeline(shaders.irradiance); cmd.dispatch(1); } @@ -2271,7 +2325,7 @@ void Renderer::prepareGi(Encoder& cmd, WorldView& wview) { cmd.setBinding(2, probesGBuffDiff, Sampler::nearest()); cmd.setBinding(3, probesGBuffNorm, Sampler::nearest()); cmd.setBinding(4, probesGBuffRayT, Sampler::nearest()); - cmd.setBinding(5, sky.viewCldLut, Sampler::bilinear()); + cmd.setBinding(5, sky.viewCldLut, sky.sampler); cmd.setBinding(6, shadowMap[1], Sampler::bilinear()); cmd.setBinding(7, probesLightingPrev, Sampler::nearest()); cmd.setBinding(8, hashTable); @@ -2300,9 +2354,9 @@ void Renderer::prepareExposure(Encoder& cmd, WorldView& wview) { cmd.setDebugMarker("Exposure"); cmd.setFramebuffer({}); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, sky.viewCldLut); - cmd.setBinding(2, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); - cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(1, sky.viewCldLut, sky.sampler); + cmd.setBinding(2, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge)); + cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge)); cmd.setBinding(4, sky.irradianceLut); cmd.setPushData(&push, sizeof(push)); cmd.setPipeline(shaders.skyExposure); @@ -2366,7 +2420,7 @@ void Renderer::drawPathtrace(Tempest::Encoder& cmd, Worl cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); //cmd.setBinding(1, zbuffer); cmd.setBinding(2, sky.irradianceLut); - cmd.setBinding(3, sky.viewCldLut); + cmd.setBinding(3, sky.viewCldLut, sky.sampler); //cmd.setBinding(4, shadowMap[1], Sampler::bilinear()); cmd.setBinding(4, Resources::fallbackBlack(), Sampler::bilinear()); // @@ -2428,7 +2482,7 @@ void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wvie if(settings.giMethod!=GiMethod::IrrC) return; - static bool enable = false; + static bool enable = true; if(!enable) return; diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index e47b9bcb6..64f0bc189 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -49,6 +49,8 @@ class Renderer final { Tempest::StorageImage& usesImage2d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, Tempest::Size sz, bool mips = false); Tempest::StorageImage& usesImage3d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h, uint32_t d, bool mips = false); Tempest::ZBuffer& usesZBuffer(Tempest::ZBuffer& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h); + Tempest::Attachment& usesAttachment(Tempest::Attachment&ret, Tempest::TextureFormat frm, Tempest::Size sz); + Tempest::Attachment& usesAttachment(Tempest::Attachment&ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h); Tempest::StorageBuffer& usesSsbo(Tempest::StorageBuffer& ret, size_t size); Tempest::StorageBuffer& usesSsboInit(Tempest::StorageBuffer& ret, size_t size); Tempest::StorageBuffer& usesScratch(Tempest::StorageBuffer& ret, size_t size); @@ -66,6 +68,7 @@ class Renderer final { void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); + void surfelsApply (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass); void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass); void surfelsTrace (Tempest::Encoder& cmd, WorldView& wview, Tempest::StorageBuffer& surfels, bool postPass); @@ -169,6 +172,8 @@ class Renderer final { Tempest::TextureFormat lutRGBFormat = Tempest::TextureFormat::R11G11B10UF; Tempest::TextureFormat lutRGBAFormat = Tempest::TextureFormat::RGBA16F; + Tempest::Sampler sampler = Tempest::Sampler::bilinear(); + bool lutIsInitialized = false; Tempest::Attachment transLut, multiScatLut, viewLut, viewCldLut; Tempest::StorageImage cloudsLut, fogLut3D, fogLut3DMs; @@ -210,14 +215,18 @@ class Renderer final { } gi; struct { - const uint32_t maxSurfels = 16*1024; + const Tempest::IVec2 gbufTile = {8, 8}; + const uint32_t gbufTilesX = 256; + const uint32_t gbufTilesY = 256; + const uint32_t maxSurfels = gbufTilesX*gbufTilesY; Tempest::StorageBuffer surfels; Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; Tempest::StorageBuffer surfBinsCtrl, surfList; - Tempest::StorageImage dbgImage; + Tempest::StorageBuffer gbuffFree; + Tempest::StorageImage gbuffDiff, gbuffNorm, gbuffHitT; } surf; struct { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 19aa4a299..76fc88d2e 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -261,8 +261,11 @@ void Shaders::compileShaders() { surfAlloc = computeShader("surf_alloc.comp.sprv"); surfApply = computeShader("surf_apply.comp.sprv"); + surfFList = computeShader("surf_freelist.comp.sprv"); surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); + surfRaycast = computeShader("surf_raycast.comp.sprv"); + surLighting = computeShader("surf_lighting.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 1d2f50e79..d6e774c68 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -90,10 +90,10 @@ class Shaders { Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfBinClear, surfBinPass, surfBinAlloc, surfBinSort; - Tempest::ComputePipeline surfAlloc, surfApply; + Tempest::ComputePipeline surfAlloc, surfApply, surfFList; Tempest::ComputePipeline surfUpdate, surfCulling, surfDecimate, surfCompact; - Tempest::ComputePipeline surfPathtrace; + Tempest::ComputePipeline surfPathtrace, surfRaycast, surLighting; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index ec2f3736a..be5fc299e 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -319,6 +319,7 @@ add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) +add_shader(surf_freelist.comp lighting/surfels/surf_freelist.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) @@ -326,6 +327,8 @@ add_shader(surf_bin_pass.comp lighting/surfels/surf_bin_pass.comp) add_shader(surf_bin_sort.comp lighting/surfels/surf_bin_sort.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) +add_shader(surf_raycast.comp lighting/surfels/surf_raycast.comp) +add_shader(surf_lighting.comp lighting/surfels/surf_lighting.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/common.glsl b/shader/common.glsl index 27b2ca928..f5624a51c 100644 --- a/shader/common.glsl +++ b/shader/common.glsl @@ -72,6 +72,12 @@ float fresnel(const vec3 incident, const vec3 normal, const float ior) { return kr; } +vec3 waterTransmittance(float raylen) { + const float depth = raylen / 5000.0; // 50 meters + const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); + return transmittance; + } + float safeacos(const float x) { return acos(clamp(x, -1.0, 1.0)); } diff --git a/shader/lighting/ambient_light.frag b/shader/lighting/ambient_light.frag index 1ad95cbf9..8d73eecd4 100644 --- a/shader/lighting/ambient_light.frag +++ b/shader/lighting/ambient_light.frag @@ -16,7 +16,7 @@ layout(binding = 2) uniform usampler2D gbufNormal; #if defined(SURFEL_GI) layout(binding = 3) uniform sampler2D surfGi; layout(binding = 4) uniform sampler2D ssao; -layout(binding = 5, std430) readonly buffer SB0 { uint count; } surf; +layout(binding = 5, std430) readonly buffer SB0 { uint count, one1, one2, added; } surf; #elif defined(SSAO) layout(binding = 3) uniform texture2D irradiance; layout(binding = 4) uniform sampler2D ssao; @@ -97,6 +97,10 @@ void main() { outColor = vec4(1); return; } + if(drawInt(fragCoord.xy-ivec2(100,120), int(surf.added))>0) { + outColor = vec4(1); + return; + } #endif outColor = vec4(color, 1); diff --git a/shader/lighting/light.frag b/shader/lighting/light.frag index e4450a1a6..eed07306c 100644 --- a/shader/lighting/light.frag +++ b/shader/lighting/light.frag @@ -21,9 +21,9 @@ layout(push_constant, std140) uniform Pbo { layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; +layout(binding = 1) uniform texture2D gbufDiffuse; +layout(binding = 2) uniform utexture2D gbufNormal; +layout(binding = 3) uniform texture2D depth; #if defined(VIRTUAL_SHADOW) layout(binding = 5, std430) readonly buffer Omni { uint pageTblOmni[]; }; diff --git a/shader/lighting/pt/pathtrace.frag b/shader/lighting/pt/pathtrace.frag index ce0220662..279a2197c 100644 --- a/shader/lighting/pt/pathtrace.frag +++ b/shader/lighting/pt/pathtrace.frag @@ -1,6 +1,5 @@ #version 460 -#define LIGHTING 1 #define RAY_QUERY #define RAY_QUERY_AT @@ -201,9 +200,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection) { } if(underWater) { - const float depth = hit.rayT / 5000.0; // 50 meters - const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); - thruput *= transmittance; + thruput *= waterTransmittance(hit.rayT); } if(hit.water) { diff --git a/shader/lighting/pt/pathtrace_common.glsl b/shader/lighting/pt/pathtrace_common.glsl index 7a537a4bd..e338578eb 100644 --- a/shader/lighting/pt/pathtrace_common.glsl +++ b/shader/lighting/pt/pathtrace_common.glsl @@ -3,7 +3,7 @@ #include "random.glsl" -const float TMax = 1e30f; +const float TMax = 500*100; struct HitResolve { vec4 diff; @@ -40,7 +40,7 @@ float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout rayQueryEXT rayQuery; rayQueryInitializeEXT(rayQuery, topLevelAS, flags, CM_ShadowCaster, - rayOrigin, tMin, rayDirection, 500*100); + rayOrigin, tMin, rayDirection, TMax); rayQueryProceedAlphaTest(rayQuery); // rayQueryProceedAlphaTest(rayQuery, rngState); if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) @@ -48,19 +48,22 @@ float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout return 0; } -HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout Random rngState) { +HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, uint mask, inout Random rngState) { // CullBack due to vegetation uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; float tMin = 2; rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, - rayOrigin, tMin, rayDirection, 500*100); + rayQueryInitializeEXT(rayQuery, topLevelAS, flags, mask, + rayOrigin, tMin, rayDirection, TMax); rayQueryProceedAlphaTest(rayQuery); // rayQueryProceedAlphaTest(rayQuery, rngState); if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { HitResolve ret; - ret.rayT = TMax; + ret.rayT = TMax; + ret.diff = vec4(0); + ret.norm = vec3(0); + ret.water = false; return ret; } @@ -98,4 +101,8 @@ HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, return ret; } +HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout Random rngState) { + return rayQueryProceedPrimary(rayOrigin, rayDirection, mipOverride, 0xFF, rngState); + } + #endif \ No newline at end of file diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 8a680cdbb..73f8ef3db 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -8,14 +8,12 @@ layout(local_size_x = 16, local_size_y = 16) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -const float NormalBias = 0.0030; const uint Salt = 0x9D; const float MaxAttempts = 1; const int MaxQueue = 256; layout(std140, push_constant) uniform Push { vec3 originLwc; - uint tileSize; }; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; @@ -24,34 +22,22 @@ layout(binding = 1) uniform texture2D irradiance; layout(binding = 2) uniform utexture2D gbufNormal; layout(binding = 3) uniform texture2D depth; layout(binding = 4, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; } surf; -// -layout(binding = 6, r32ui) uniform uimage2D surfCnts; -layout(binding = 7, r32ui) uniform uimage2D surfBins; -layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; +layout(binding = 5, std430) buffer SB1 { uint count; uint ids[]; } freelist; shared Candidate pointQueue[MaxQueue]; shared int pointQueueSize; shared uint fragVote; -vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { +vec3 worldPos(float z, ivec2 fragCoord) { const mat4 inv = scene.viewProjectLwcInv; const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return (pos.xyz + normal*NormalBias)/pos.w + originLwc; + return pos.xyz/pos.w + originLwc; } float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - - float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; - float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; - - float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; - float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; - return min(worldRadiusX, worldRadiusY); + return pixelToWorld(scene, pixelRadius, z); } float calculteWeight(const Candidate s, const vec3 wpos, const vec3 norm) { @@ -85,6 +71,13 @@ void fragCoverageVote(float wSum) { atomicMin(fragVote, b); } +uint allocPayload() { + uint i = atomicAdd(freelist.count, 1); + if(i= SKY_DEPTH); const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + const vec3 wpos = worldPos(z, fragCoord); float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); @@ -169,8 +162,6 @@ void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) coverage += amendCoverage(fragCoord, wpos, norm); } - - imageStore(dbgImage, fragCoord, vec4(coverage)); } ivec2 remap(ivec2 subtile, ivec2 tileCnt) { @@ -196,10 +187,10 @@ void main() { barrier(); const ivec2 screenSize = ivec2(textureSize(depth,0)); - const ivec2 tileCount = ivec2(tileSize)/ivec2(gl_WorkGroupSize.xy); + const ivec2 tileCount = ivec2(LargeTile)/ivec2(gl_WorkGroupSize.xy); for(int y=0; y= cnt) return; @@ -62,9 +92,10 @@ void pullSurfels(ivec2 bboxMin, ivec2 bboxMax, uint ptr, uint cnt, uint i) { return; const uint id = atomicAdd(surfelCount, 1); - surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); + if(id>=tSurfels.length()) + return; + + tSurfels[id] = packSurfel(s); } void main() { @@ -96,7 +127,7 @@ void main() { surfelCount = 0; vec4 clr = vec4(0); - for(uint i=0; i=cnt) + break; + + barrier(); surfelCount = 0; } @@ -115,7 +150,6 @@ void main() { if(sky) { imageStore(irradiance, fragCoord, vec4(0,0,0,1)); - imageStore(dbgImage, fragCoord, vec4(1)); return; } @@ -130,10 +164,9 @@ void main() { // post pass const vec4 pre = imageLoad(irradiance, fragCoord); clr += vec4(pre.rgb*pre.a, pre.a); + //clr += vec4(pre.rgb, pre.a); if(clr.a>0) clr.rgb /= clr.a; imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); } - - imageStore(dbgImage, fragCoord, vec4(clr.a)); } diff --git a/shader/lighting/surfels/surf_bin_pass.comp b/shader/lighting/surfels/surf_bin_pass.comp index 5609cf938..d67c645df 100644 --- a/shader/lighting/surfels/surf_bin_pass.comp +++ b/shader/lighting/surfels/surf_bin_pass.comp @@ -21,6 +21,49 @@ layout(binding = 3, r32ui) uniform uimage2D surfCnts; layout(binding = 4, r32ui) uniform readonly uimage2D surfBins; layout(binding = 5, std430) buffer SB2 { uint surfelIds[]; }; +vec3 mkTangent(vec3 norm) { + // Pick axis least parallel to n + vec3 up = abs(norm.z) < 0.999f ? vec3(0.0f, 0.0f, 1.0f) : vec3(1.0f, 0.0f, 0.0f); + return normalize(cross(norm, up)); + } + +ivec4 projectSurfel(const Surfel s) { + vec3 n = decodeNormal(s.norm); + vec3 c = s.pos; + float r = s.radius; + + vec3 t = mkTangent(n); + vec3 bt = cross(n, t); + + vec2 mn = vec2( 100); + vec2 mx = vec2(-100); + + // center + ellipse axes + vec3 points[5]; + points[0] = c; + points[1] = c + t * r; + points[2] = c - t * r; + points[3] = c + bt * r; + points[4] = c - bt * r; + + for(int i=0; i pixel coordinates + vec2 screen = scene.screenRes; + ivec2 minXY = ivec2((mn * 0.5 + 0.5) * screen); + ivec2 maxXY = ivec2((mx * 0.5 + 0.5) * screen); + + return ivec4(minXY, maxXY); + } + void main() { const uint surfelId = gl_GlobalInvocationID.x; if(surfelId>=surf.header.count) @@ -32,11 +75,17 @@ void main() { const ivec2 fragCoord = p.fragCoord; const int radiusPix = DefaultCoverage; - if(p.radius==0) + if(!isSurfelAlive(p)) return; +#if 0 ivec2 pos0 = ivec2(fragCoord-radiusPix)/tileSize; ivec2 pos1 = ivec2(fragCoord+radiusPix)/tileSize + 1; +#else + ivec4 aabb = projectSurfel(p); + ivec2 pos0 = ivec2(aabb.xy)/tileSize; + ivec2 pos1 = ivec2(aabb.zw)/tileSize + 1; +#endif ivec2 sz = imageSize(surfCnts); pos0 = max(ivec2(0), pos0); diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 60430db83..86ae10e9e 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -2,11 +2,15 @@ #define SURF_COMMON_GLSL #include "common.glsl" +#include "scene.glsl" const float SKY_DEPTH = 0.999995; -const int MinCoverage = 8; // in pixels -const int DefaultCoverage = 128; // in pixels -const uint MaxInTile = 512; // ~32px (~6x6) per surfel +const int MinCoverage = 8; // in pixels +const int DefaultCoverage = 96; // in pixels +const int LargeTile = 128; // in pixels +const uint MaxInTile = 1024; // ~32px (~6x6) per surfel + +const float rEffScale = 0.5; struct SurfHeader { uint count; @@ -22,7 +26,7 @@ struct Surfel { float radius; float radiusMean; vec3 irradiance; - int radiusPix; + uint payload; }; struct Candidate { @@ -30,9 +34,23 @@ struct Candidate { vec4 norm; // norm, padd }; +uint packAtlassPos(uint x, uint y) { + return (x) | (y << 12) | 0x80000000; + } + +ivec2 unpackAtlassPos(uint ptr) { + uint x = ((ptr >> 0) & 0xFFF); + uint y = ((ptr >> 12) & 0xFFF); + return ivec2(x, y); + } + +bool isSurfelAlive(const Surfel s) { + return s.radius >= 0; + } + bool isSurfelVisible(const Surfel s, ivec2 bboxMin, ivec2 bboxMax) { const ivec2 at = s.fragCoord; - const int radius = s.radiusPix; + const int radius = DefaultCoverage; if(bboxMax.x < at.x-radius || bboxMax.y < at.y-radius) return false; @@ -101,48 +119,41 @@ uint surfHash(vec3 pos, float cellSize, uint inorm) { #endif } -float calculteWeight(const vec3 spos, const vec3 snorm, float rEff, float rMax, const vec3 wpos, const vec3 wnorm) { +float pixelToWorld(const SceneDesc scene, float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + +float calculteWeight(const vec3 spos, const vec3 snorm, float rEff, float rMax, float rDiffInv, const vec3 wpos, const vec3 wnorm) { // An Approximate Global Illumination System for Computer Generated Films // https://www.tabellion.org/et/paper/siggraph_2004_gi_for_films.pdf // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf - vec3 ldir = wpos - spos; - float dist = length(ldir); - float dotN = dot(wnorm, snorm); + float dotN = dot(wnorm, snorm); + if(dotN <= 0) + return 0; + + vec3 ldir = wpos - spos; + float dist = length(ldir); dist = max(dist, 0.0001); -#if 0 - float ePos = dist/rEff; - float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/6.0)); // Eq. 4 - float w = 1.0 - max(ePos, eNorm); // Eq. 2 - - float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion - //float eOccl = 1.0 - clamp(-dot(ldir, wnorm), 0, 1)*0.5; // allow small occlusion - //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; - return w*eOccl; -#elif 1 // Wendland C2 inspired falloff - rEff = min(rEff, rMax*0.5); - float q = max(min(dist,rMax)-rEff, 0)/(rMax-rEff); + float q = max(min(dist,rMax)-rEff, 0)*rDiffInv; float wPos = pow(1-q, 4.0)*(4.0*q + 1.0); - float wNorm = pow(max(dotN, 0.0), 2.0); - float wOccl = 1.0 - max(dot((ldir/dist), snorm), 0.0); - return wPos * wNorm * wOccl; -#elif 0 - float wPos = 1.0 - smoothstep(min(rEff,rMax*0.6), rMax, dist); - float wNorm = pow(max(dotN, 0.0), 2.0); - float wOccl = 1.0 - max(dot((ldir/dist), snorm), 0.0); - return wPos * wNorm * wOccl; -#elif 0 - float wPos = max(1.0 - dist/rMax, 0.0)*(rEff/dist); - float wNorm = pow(max(dotN, 0.0), 2.0); - float wOccl = dot((ldir/dist), snorm)*0.5+0.5; // allow small occlusion + float wNorm = dotN * dotN; + float wOccl = 1.0 - max(dot(ldir, snorm)/dist, 0.0); return wPos * wNorm * wOccl; -#else - float ePos = max(dist/rEff, 0.0); - float eNorm = sqrt(max(1 - 1*dotN, 0)); - float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion - return (1.0*eOccl)/max(ePos + eNorm, 0.0001) - 1.0; -#endif + } + +float calculteWeight(const vec3 spos, const vec3 snorm, float rEff, float rMax, const vec3 wpos, const vec3 wnorm) { + rMax = min(rMax, 65000); + rEff = min(rEff, rMax*rEffScale); + return calculteWeight(spos, snorm, rEff, rMax, 1.0/(rMax-rEff), wpos, wnorm); } vec3 surfDebugColor(Surfel s, uint sId) { diff --git a/shader/lighting/surfels/surf_compact.comp b/shader/lighting/surfels/surf_compact.comp index e7b06d16f..373cff50e 100644 --- a/shader/lighting/surfels/surf_compact.comp +++ b/shader/lighting/surfels/surf_compact.comp @@ -9,9 +9,19 @@ layout(local_size_x = 256) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; layout(binding = 3, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; } surf; +layout(binding = 4, std430) buffer SB1 { int count; uint ids[]; } freelist; shared uint wPtr; +void freeGBuf(uint id) { + if(id==0) + return; + uint i = atomicAdd(freelist.count, -1) - 1; + if(i<0) + return; + freelist.ids[i] = id; + } + void main() { const uint laneID = gl_LocalInvocationIndex; @@ -21,10 +31,13 @@ void main() { Surfel sx; for(uint ix=0; ix0; + const bool keep = i radiusMean) { - // TODO: two-sided HiZ - return false; - } - } -#endif - #if 1 vec4 aabb = vec4(0); float depthMin=0, depthMax=0; - if(!projectSphere(viewPos, p.w, aabb, depthMin, depthMax)) + if(!projectSphere(viewPos, radius, aabb, depthMin, depthMax)) return false; + // TODO: two-sided HiZ if(!hiZTest(aabb, depthMin)) return false; #endif @@ -133,8 +128,8 @@ void main() { return; const Surfel s = surfels[surfelId]; - if(isSurfelVisible(vec4(s.pos, s.radius), s.radiusMean, s.fragCoord)) + if(isSurfelVisible(s.pos, s.radiusMean, s.radius, s.fragCoord)) return; - surfels[surfelId].radius = 0; + surfels[surfelId].radius = -1; } diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index 7e2ba6364..5022b2dd2 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -7,7 +7,7 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 1, std430) readonly buffer SB0 { SurfHeader header; Surfel surfels[]; }; layout(binding = 2) uniform usampler2D gbufNormal; layout(binding = 3) uniform sampler2D depth; @@ -44,8 +44,11 @@ void main(void) { ;//discard; //vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); - //vec3 clr = 3.0 * p.irradiance * (1.0-qDist) * scene.exposure; - vec3 clr = p.irradiance * (1.0-qDist); + vec3 clr = 4.0 * p.irradiance * (1.0-qDist) * scene.exposure; + if(instanceIndex >= header.count-header.added) + clr = vec3(0,1,0); + if(!isSurfelAlive(p)) + clr = vec3(1,0,0); outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); } diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index 81f0c72ea..4f69d7e37 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -7,7 +7,7 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 1, std430) readonly buffer SB0 { SurfHeader header; Surfel surfels[]; }; layout(binding = 3) uniform sampler2D depth; layout(location = 0) out vec3 center; @@ -42,15 +42,12 @@ vec3 hasGridPos(vec3 wpos, float cellSize) { } float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; - float worldRadius = (clipRadius * z) / scene.project[1][1]; - return worldRadius; + return pixelToWorld(scene, pixelRadius, z); } void main() { const uint surfelId = gl_InstanceIndex; - if(surfelId>=count.x) { + if(surfelId>=header.count) { gl_Position = vec4(0); return; } diff --git a/shader/lighting/surfels/surf_decimate.comp b/shader/lighting/surfels/surf_decimate.comp index 1c6707f18..085310047 100644 --- a/shader/lighting/surfels/surf_decimate.comp +++ b/shader/lighting/surfels/surf_decimate.comp @@ -31,13 +31,15 @@ void main() { const Surfel p = surfels[surfelId]; const ivec2 sz = scene.screenRes; - if(p.radius==0) + if(!isSurfelAlive(p)) return; // disabled +#if 0 if(!(-DefaultCoverage <= p.fragCoord.x && p.fragCoord.x < sz.x+DefaultCoverage)) return; if(!(-DefaultCoverage <= p.fragCoord.y && p.fragCoord.y < sz.y+DefaultCoverage)) return; +#endif const vec3 wpos = p.pos; const vec3 norm = decodeNormal(p.norm); @@ -48,25 +50,34 @@ void main() { const uint cnt = imageLoad(surfCnts, cTileId).x; const uint ptr = imageLoad(surfBins, cTileId).x; + /* + if(cnt>1024) { + // too many + surfels[surfelId].radius = -1; + return; + } + */ + float weight = 0; for(uint i=0; i=surfelId) - break; // surfels are sorted + if(sId==surfelId) + break; const Surfel s = surfels[sId]; const ivec2 sTileId = (s.fragCoord/int(tileSize)); + if(sTileId.x!=tileId.x && tileId.x%2==0) continue; if(sTileId.y!=tileId.y && tileId.y%2==0) continue; - const float w = calculteWeight(s.pos, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); + const float w = calculteWeight(s.pos, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); weight += w; if(weight>edge) { // too dense - can be removed - surfels[surfelId].radius = 0; + surfels[surfelId].radius = -1; return; } } diff --git a/shader/lighting/surfels/surf_freelist.comp b/shader/lighting/surfels/surf_freelist.comp new file mode 100644 index 000000000..289a02795 --- /dev/null +++ b/shader/lighting/surfels/surf_freelist.comp @@ -0,0 +1,19 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" + +layout(local_size_x = 64) in; + +layout(std140, push_constant) uniform Push { + uint gbufTileX; + }; +layout(binding = 0, std430) buffer SB0 { int count; uint idx[]; }; + +void main() { + const uint id = gl_GlobalInvocationID.x; + if(id==0) + count = 0; + + if(id < idx.length()) + idx[id] = packAtlassPos(id%gbufTileX, id/gbufTileX); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_lighting.comp b/shader/lighting/surfels/surf_lighting.comp new file mode 100644 index 000000000..5fd974f6c --- /dev/null +++ b/shader/lighting/surfels/surf_lighting.comp @@ -0,0 +1,183 @@ +#version 460 + +#define LIGHTING 1 +#define RAY_QUERY +#define RAY_QUERY_AT + +#include "lighting/rt/rt_common.glsl" +#include "lighting/pt/pathtrace_common.glsl" +#include "lighting/surfels/surf_common.glsl" +#include "lighting/tonemapping.glsl" + +#include "scene.glsl" +#include "common.glsl" +#include "random.glsl" + +layout(local_size_x = 8, local_size_y = 8) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(std140, push_constant) uniform Push { + uint pass; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; +layout(binding = 2) uniform sampler2D skyLUT; +layout(binding = 3) uniform texture2D gbufDiff; +layout(binding = 4) uniform texture2D gbufNorm; +layout(binding = 5) uniform texture2D gbufHit; +layout(binding = 12) uniform sampler2D textureSm1; + +struct GBuf { + vec3 diff; + vec3 norm; + float rayT; + float rayW; + }; + +shared vec4 reduction[NumThreads]; + +float shadowResolve(in vec4 sh, float z) { + z = clamp(z,0,0.99); + sh = step(sh,vec4(z)); + return 0.25*(sh.x+sh.y+sh.z+sh.w); + } + +vec4 shadowSample(in sampler2D shadowMap, vec2 shPos) { + shPos.xy = shPos.xy*vec2(0.5,0.5)+vec2(0.5); + return textureGather(shadowMap,shPos); + } + +float calcShadow(vec3 shPos1) { + vec4 lay1 = shadowSample(textureSm1,shPos1.xy); + float v1 = shadowResolve(lay1,shPos1.z); + return v1; + } + +mat3 toTangent(vec3 norm) { + mat3 tangent; + // Compute a tangent frame and rotate the half vector to world space + vec3 up = abs(norm.z) < 0.999f ? vec3(0.0f, 0.0f, 1.0f) : vec3(1.0f, 0.0f, 0.0f); + tangent[0] = normalize(cross(up, norm)); + tangent[1] = cross(norm, tangent[0]); + tangent[2] = norm; + return tangent; + } + +float pixelToWorld(float pixelRadius, float z) { + return pixelToWorld(scene, pixelRadius, z); + } + +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection) { + float lamb = max(dot(norm, rayDirection), 0); + if(lamb==0) + return lamb; + + vec4 shCoord = scene.viewShadow[1]*vec4(rayOrigin,1); + if(abs(shCoord.x)>=shCoord.w && abs(shCoord.y)>=shCoord.w) { +#if 1 + return 1; +#else + Random rngState = Random(0); + float shadow = rayQueryProceedShadow(rayOrigin, rayDirection, rngState); + return (lamb * shadow); +#endif + } + float shadow = calcShadow(shCoord.xyz/shCoord.w); + return (lamb * shadow); + } + +vec3 evalLight(vec3 rayOrigin, vec3 rayDirection, GBuf hit) { + vec3 thruput = vec3(1.0); + vec3 color = vec3(0); + + if(hit.rayW > 0) { + thruput *= waterTransmittance(hit.rayW); + } + + if(hit.rayT==TMax) { + vec3 sky = textureSkyLUT(skyLUT, vec3(0,RPlanet+max(rayOrigin.y*0.01,0),0), rayDirection, scene.sunDir) * scene.GSunIntensity; + color += sky; + color += (vec3(0.3, 0.26, 1)*0.15); //HACK for the night sky + return thruput*color; + } + + thruput *= min(textureAlbedo(hit.diff.rgb), 0.95); + rayOrigin = (rayOrigin + rayDirection * hit.rayT); + + vec3 direct = vec3(0); + direct += sampleDirectLight(hit.norm, rayOrigin, scene.sunDir) * scene.sunColor; + color += thruput*direct*Fd_Lambert; + + return color; + } + +GBuf loadGBuf(uint ptr) { + uint x = ((ptr >> 0) & 0xFFF); + uint y = ((ptr >> 12) & 0xFFF); + + ivec2 at = ivec2(x,y)*8 + ivec2(gl_LocalInvocationID.xy); + vec4 d = texelFetch(gbufDiff, at, 0); + vec4 n = texelFetch(gbufNorm, at, 0); + + GBuf hit; + hit.diff = d.rgb; + hit.norm = n.xyz*2.0-1.0; + hit.rayT = texelFetch(gbufHit, at, 0).x * TMax; + hit.rayW = n.w * hit.rayT; + + return hit; + } + +void reduceIrr() { + uint laneID = gl_LocalInvocationIndex; + + for(uint stride = NumThreads/2; stride > 0; stride >>= 1) { + if(laneID < stride) { + reduction[laneID] += reduction[laneID + stride]; + } + barrier(); + } + } + +void main() { + const float eps = 0.0001; + const uint numPaths = NumThreads; + const uint surfelId = pass==0 ? gl_WorkGroupID.x : (header.count-gl_WorkGroupID.z-1); + + const Surfel p = surfels[surfelId]; + if(!isSurfelAlive(p)) { + surfels[surfelId].irradiance = vec3(1,1,0) / scene.exposure; + return; + } + + const mat3 tbn = toTangent(decodeNormal(p.norm)); + + Random rngState = Random(pcgHash(gl_LocalInvocationIndex)); + + const uint i = gl_LocalInvocationIndex; + const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0); + + const GBuf hit = loadGBuf(p.payload); + const vec3 pt = evalLight(p.pos, ray, hit); + + float hitInv = 1.0/clamp(hit.rayT*0.4, 10.0, p.radius); + reduction[i] = vec4(pt.rgb, hitInv); + barrier(); + + reduceIrr(); + + if(gl_LocalInvocationIndex==0) { + const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); + const float rMin = pixelToWorld(MinCoverage, pos4.z/pos4.w); + const float rMax = min(pixelToWorld(DefaultCoverage, pos4.z/pos4.w), 65000); + + const float hitMean = float(numPaths)/max(reduction[0].w, eps); //harmonic mean + surfels[surfelId].radius = rMax; + surfels[surfelId].radiusMean = min(max(hitMean, rMin), rMax * rEffScale); + + surfels[surfelId].irradiance = (reduction[0].rgb/float(numPaths)); + } + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index 4ba6596d0..a0db0e041 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -78,7 +78,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { return vec4(color, depth); } - HitResolve hit = rayQueryProceedPrimary(rayOrigin, rayDirection, (bounce==0 ? 0 : -1), rngState); + HitResolve hit = rayQueryProceedPrimary(rayOrigin, rayDirection, -1, rngState); if(bounce==0) depth = abs(hit.rayT); @@ -100,9 +100,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { /* if(underWater) { - const float depth = hit.rayT / 5000.0; // 50 meters - const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); - thruput *= transmittance; + thruput *= waterTransmittance(hit.rayT); } if(hit.water) { @@ -138,7 +136,6 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { } shared vec4 reduction[NumThreads]; -shared uint hitCnt; void reduceIrr() { uint laneID = gl_LocalInvocationIndex; @@ -173,16 +170,10 @@ void main() { // const vec3 ray = randCosWeightedHemisphereDirection(decodeNormal(p.norm), rngState); const vec4 pt = pathtrace(p.pos, ray, rngState); - hitCnt = 0; - barrier(); - - if(pt.a!=TMax) - atomicAdd(hitCnt, 1); - #if defined(USE_MIN_HIT_DIST) reduction[i] = vec4(pt.rgb, pt.a); #else - reduction[i] = vec4(pt.rgb, 1.0/clamp(pt.a*0.4, 10.0, 1*p.radius)); + reduction[i] = vec4(pt.rgb, 1.0/clamp(pt.a*0.4, 10.0, p.radius)); #endif barrier(); @@ -192,9 +183,6 @@ void main() { #if defined(USE_MIN_HIT_DIST) const float hitMin = max(4, reduction[0].a); surfels[surfelId].radiusMean = hitMin; -#elif 0 - const float hitMean = float(hitCnt)/max(reduction[0].a, eps); //harmonic mean - surfels[surfelId].radiusMean = hitCnt > 0 ? hitMean : p.radius; #else const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean surfels[surfelId].radiusMean = hitMean; diff --git a/shader/lighting/surfels/surf_raycast.comp b/shader/lighting/surfels/surf_raycast.comp new file mode 100644 index 000000000..47d49383a --- /dev/null +++ b/shader/lighting/surfels/surf_raycast.comp @@ -0,0 +1,95 @@ +#version 460 + +#define RAY_QUERY +#define RAY_QUERY_AT + +#include "lighting/rt/rt_common.glsl" +#include "lighting/pt/pathtrace_common.glsl" +#include "lighting/surfels/surf_common.glsl" +#include "lighting/tonemapping.glsl" + +#include "scene.glsl" +#include "common.glsl" +#include "random.glsl" + +layout(local_size_x = 8, local_size_y = 8) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; +const float NormalBias = 0.0015; + +layout(std140, push_constant) uniform Push { + uint pass; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; +layout(binding = 2) uniform sampler2D skyLUT; +layout(binding = 3, rgba8) uniform image2D gbufDiff; +layout(binding = 4, rgba8) uniform image2D gbufNorm; +layout(binding = 5, r16) uniform image2D gbufHit; + +mat3 toTangent(vec3 norm) { + mat3 tangent; + // Compute a tangent frame and rotate the half vector to world space + vec3 up = abs(norm.z) < 0.999f ? vec3(0.0f, 0.0f, 1.0f) : vec3(1.0f, 0.0f, 0.0f); + tangent[0] = normalize(cross(up, norm)); + tangent[1] = cross(norm, tangent[0]); + tangent[2] = norm; + return tangent; + } + +HitResolve raycast(vec3 rayOrigin, vec3 rayDirection, inout float wHit) { + Random rngState = Random(0); // inactive + HitResolve hit = rayQueryProceedPrimary(rayOrigin, rayDirection, -1, rngState); + if(hit.rayT<0) { + hit.rayT = -hit.rayT; // backfaces are fine + hit.norm = -hit.norm; + } + if(hit.water) { + //NOTE: probably need to trace a 'helper' ray from surfel + // to top/sun to determinate if surfel is underwater or now + wHit = hit.norm.y<0 ? hit.rayT : 0; // heuristic to track only underwater hits + + const uint CM_Level = CM_Opaque | CM_Transparent; + hit = rayQueryProceedPrimary(rayOrigin, rayDirection, -1, CM_Level, rngState); + } + if(hit.rayT==TMax) + hit.diff = vec4(0,0,1,1); + return hit; + } + +void storeGBuf(uint ptr, const HitResolve hit, const float wHit) { + if(ptr==0) + return; //error + + float wHitUNorm = (hit.rayT>0) ? (wHit / hit.rayT) : 0; + + ivec2 at = unpackAtlassPos(ptr)*8 + ivec2(gl_LocalInvocationID.xy); + imageStore(gbufDiff, at, vec4(hit.diff.rgb, 1)); + imageStore(gbufNorm, at, vec4(hit.norm.xyz*0.5+0.5, wHitUNorm)); + imageStore(gbufHit, at, vec4(hit.rayT/TMax)); + } + +void main() { + const float eps = 0.0001; + const uint numPaths = NumThreads; + const uint surfelId = pass==0 ? gl_WorkGroupID.x : (header.count-gl_WorkGroupID.z-1); + // if(surfelId>=header.count) + // return; + + const Surfel p = surfels[surfelId]; + if(!isSurfelAlive(p)) + return; + + const vec3 norm = decodeNormal(p.norm); + const mat3 tbn = toTangent(norm); + const vec3 pos = p.pos; + + const uint i = gl_LocalInvocationIndex; + const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0); + + float wHit = 0; + const HitResolve hit = raycast(pos, ray, wHit); + storeGBuf(p.payload, hit, wHit); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_update.comp b/shader/lighting/surfels/surf_update.comp index bdfefd2e7..fc1eb32d1 100644 --- a/shader/lighting/surfels/surf_update.comp +++ b/shader/lighting/surfels/surf_update.comp @@ -12,16 +12,8 @@ layout(binding = 0, std140) uniform UboScene { layout(binding = 1) uniform texture2D depth; layout(binding = 2, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; - float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - - float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; - float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; - - float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; - float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; - return min(worldRadiusX, worldRadiusY); + return pixelToWorld(scene, pixelRadius, z); } void main() { @@ -31,16 +23,18 @@ void main() { const Surfel s = surfels[surfelId]; + if(!isSurfelAlive(s)) + return; // disabled + const vec4 pos4 = scene.viewProject * vec4(s.pos, 1.0); const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + const float rMin = pixelToWorld(MinCoverage, pos4.z/pos4.w); const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); - const float radiusMean = max(rMin, min(s.radiusMean, rMax)); - const int radiusPix = DefaultCoverage; //min(worldToPixel(s.pos, s.radiusMean), DefaultCoverage); + const float radiusMean = max(rMin, min(s.radiusMean, rMax * rEffScale)); surfels[surfelId].fragCoord = fragCoord; - surfels[surfelId].radiusPix = radiusPix; surfels[surfelId].radius = rMax; surfels[surfelId].radiusMean = radiusMean; } diff --git a/shader/materials/main.frag b/shader/materials/main.frag index 10a84a477..f672893ac 100644 --- a/shader/materials/main.frag +++ b/shader/materials/main.frag @@ -268,8 +268,7 @@ vec4 underWaterColorDepth(vec3 normal) { } vec3 waterScatter(vec3 back, vec3 normal, float len) { - float depth = len / 5000.0; // 50 meters - vec3 transmittance = exp(-depth * vec3(4,2,1)*1.25); + vec3 transmittance = waterTransmittance(len); // note: less sun light and less obsevable light transmittance = transmittance*transmittance; diff --git a/shader/sky/sky.frag b/shader/sky/sky.frag index 3bf4d074a..9b5020048 100644 --- a/shader/sky/sky.frag +++ b/shader/sky/sky.frag @@ -31,6 +31,13 @@ vec3 inverse(vec3 pos) { return (ret.xyz/ret.w)/100.f; } +vec3 viewVec() { + const vec2 uv = gl_FragCoord.xy*scene.screenResInv; + const vec3 pos = vec3(uv*2.0-1.0, 1.0); + vec4 ret = scene.viewProjectInv*vec4(pos,1.0); + return normalize(ret.xyz/ret.w - scene.camPos); //TODO: LWC + } + vec3 atmosphere(vec3 view, vec3 sunDir) { const vec3 viewPos = vec3(0.0, RPlanet + scene.plPosY, 0.0); return textureSkyLUT(skyLUT, viewPos, view, sunDir); @@ -89,11 +96,9 @@ vec3 applyClouds(vec3 skyColor) { } void main() { - const vec2 uv = gl_FragCoord.xy*scene.screenResInv; - const vec2 inPos = (2.0*gl_FragCoord.xy)*scene.screenResInv - 1.0; - - vec3 view = normalize(inverse(vec3(inPos,1.0))); - vec3 sunDir = scene.sunDir; + const vec2 uv = gl_FragCoord.xy*scene.screenResInv; + const vec3 view = viewVec(); + const vec3 sunDir = scene.sunDir; // accounted in additive fog later vec3 maxFog = textureLod(fogLut, vec3(uv, textureSize(fogLut,0).z-1), 0).rgb; diff --git a/shader/sky/sky_common.glsl b/shader/sky/sky_common.glsl index db3a84424..d0344a640 100644 --- a/shader/sky/sky_common.glsl +++ b/shader/sky/sky_common.glsl @@ -80,7 +80,7 @@ vec3 textureLUT(sampler2D tex, vec3 pos, vec3 sunDir) { vec2 uv; uv.x = 0.5 + 0.5*cosAngle; uv.y = (height - RPlanet)/(RAtmos - RPlanet); - return texture(tex, uv).rgb; + return textureLod(tex, uv, 0).rgb; } #endif diff --git a/shader/water/underwater.frag b/shader/water/underwater.frag index f8dd31862..cf6424dd0 100644 --- a/shader/water/underwater.frag +++ b/shader/water/underwater.frag @@ -14,8 +14,7 @@ layout(binding = 1) uniform sampler2D zbuffer; // fixme: copy-paste vec4 waterScatter(vec3 back, vec3 normal, const float len) { - const float depth = len / 5000.0; // 50 meters - const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); + const vec3 transmittance = waterTransmittance(len); #if defined(SCATTERING) const float f = fresnel(scene.sunDir,normal,IorWater); const vec3 scatter = f * scene.sunColor * (1-exp(-len/20000.0)) * scene.exposure;