diff --git a/WickedEngine/copytexture2D_unorm4_borderexpandCS.hlsl b/WickedEngine/copytexture2D_unorm4_borderexpandCS.hlsl index 3e14211b2..94e62b9c7 100644 --- a/WickedEngine/copytexture2D_unorm4_borderexpandCS.hlsl +++ b/WickedEngine/copytexture2D_unorm4_borderexpandCS.hlsl @@ -18,51 +18,69 @@ void main(int3 DTid : SV_DispatchThreadID) output[writecoord] = input.Load(int3(readcoord, xCopySrcMIP)); - // wrapped borders: + // border expansion: + const bool wrap = xCopyBorderExpandStyle == 1; + int2 readoffset; // left if (readcoord.x == 0) { - output[writecoord + int2(-1, 0)] = input.Load(int3(readcoord + int2(xCopySrcSize.x - 1, 0), xCopySrcMIP)); + readoffset = wrap ? int2(xCopySrcSize.x - 1, 0) : 0; + + output[writecoord + int2(-1, 0)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); // top left if (readcoord.y == 0) { - output[writecoord + int2(-1, -1)] = input.Load(int3(readcoord + int2(xCopySrcSize.x - 1, xCopySrcSize.x - 1), xCopySrcMIP)); + readoffset = wrap ? int2(xCopySrcSize.x - 1, xCopySrcSize.x - 1) : 0; + + output[writecoord + int2(-1, -1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); } } // right if (readcoord.x == xCopySrcSize.x - 1) { - output[writecoord + int2(1, 0)] = input.Load(int3(readcoord + int2(-xCopySrcSize.x + 1, 0), xCopySrcMIP)); + readoffset = wrap ? int2(-xCopySrcSize.x + 1, 0) : 0; + + output[writecoord + int2(1, 0)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); // bottom right if (readcoord.y == xCopySrcSize.y - 1) { - output[writecoord + int2(1, 1)] = input.Load(int3(readcoord + int2(-xCopySrcSize.x + 1, -xCopySrcSize.x + 1), xCopySrcMIP)); + readoffset = wrap ? int2(-xCopySrcSize.x + 1, -xCopySrcSize.x + 1) : 0; + + output[writecoord + int2(1, 1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); } } // top if (readcoord.y == 0) { - output[writecoord + int2(0, -1)] = input.Load(int3(readcoord + int2(0, xCopySrcSize.x - 1), xCopySrcMIP)); + readoffset = wrap ? int2(0, xCopySrcSize.x - 1) : 0; + + output[writecoord + int2(0, -1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); // top right if (readcoord.x == xCopySrcSize.x - 1) { - output[writecoord + int2(1, -1)] = input.Load(int3(readcoord + int2(-xCopySrcSize.x + 1, xCopySrcSize.x - 1), xCopySrcMIP)); + readoffset = wrap ? int2(-xCopySrcSize.x + 1, xCopySrcSize.x - 1) : 0; + + output[writecoord + int2(1, -1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); } } // bottom if (readcoord.y == xCopySrcSize.y - 1) { - output[writecoord + int2(0, 1)] = input.Load(int3(readcoord + int2(0, -xCopySrcSize.x + 1), xCopySrcMIP)); + readoffset = wrap ? int2(0, -xCopySrcSize.x + 1) : 0; + + output[writecoord + int2(0, 1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); // bottom left if (readcoord.x == 0) { - output[writecoord + int2(-1, 1)] = input.Load(int3(readcoord + int2(xCopySrcSize.x - 1, -xCopySrcSize.x + 1), xCopySrcMIP)); + readoffset = wrap ? int2(xCopySrcSize.x - 1, -xCopySrcSize.x + 1) : 0; + + output[writecoord + int2(-1, 1)] = input.Load(int3(readcoord + readoffset, xCopySrcMIP)); } } } diff --git a/WickedEngine/objectHF.hlsli b/WickedEngine/objectHF.hlsli index 8338f087a..180237aa0 100644 --- a/WickedEngine/objectHF.hlsli +++ b/WickedEngine/objectHF.hlsli @@ -289,7 +289,7 @@ inline void TiledLighting(in float2 pixel, inout Surface surface, inout float3 d // mipmapping needs to be performed by hand: float2 decalDX = mul(P_dx, (float3x3)decalProjection).xy * decal.texMulAdd.xy; float2 decalDY = mul(P_dy, (float3x3)decalProjection).xy * decal.texMulAdd.xy; - float4 decalColor = texture_decalatlas.SampleGrad(sampler_objectshader, uvw.xy*decal.texMulAdd.xy + decal.texMulAdd.zw, decalDX, decalDY); + float4 decalColor = texture_decalatlas.SampleGrad(sampler_linear_clamp, uvw.xy*decal.texMulAdd.xy + decal.texMulAdd.zw, decalDX, decalDY); // blend out if close to cube Z: float edgeBlend = 1 - pow(saturate(abs(clipSpacePos.z)), 8); decalColor.a *= edgeBlend; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index a475874dc..ff4048d71 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -6907,7 +6907,7 @@ void wiRenderer::DrawTracedScene(Camera* camera, wiGraphicsTypes::Texture2D* res std::vector bins; if (pack(out_rects, (int)storedTextures.size(), 16384, bins)) { - assert(bins.size() == 1 && "Tracing atlas packing into single texture failed!"); + assert(bins.size() == 1 && "The regions won't fit into the texture!"); SAFE_DELETE(atlasTexture); @@ -7306,6 +7306,8 @@ void wiRenderer::ManageDecalAtlas(GRAPHICSTHREAD threadID) } static Texture2D* atlasTexture = nullptr; + bool repackAtlas = false; + const int atlasClampBorder = 1; using namespace wiRectPacker; static std::map storedTextures; @@ -7321,67 +7323,73 @@ void wiRenderer::ManageDecalAtlas(GRAPHICSTHREAD threadID) if (storedTextures.find(tex) == storedTextures.end()) { // we need to pack this decal texture into the atlas - rect_xywhf newRect = rect_xywhf(0, 0, tex->GetDesc().Width, tex->GetDesc().Height); + rect_xywhf newRect = rect_xywhf(0, 0, tex->GetDesc().Width + atlasClampBorder * 2, tex->GetDesc().Height + atlasClampBorder * 2); storedTextures[tex] = newRect; - rect_xywhf** out_rects = new rect_xywhf*[storedTextures.size()]; - int i = 0; - for (auto& it : storedTextures) - { - out_rects[i] = &it.second; - i++; - } - - std::vector bins; - if (pack(out_rects, (int)storedTextures.size(), 16384, bins)) - { - assert(bins.size() == 1 && "Decal atlas packing into single texture failed!"); - - SAFE_DELETE(atlasTexture); - - TextureDesc desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Width = (UINT)bins[0].size.w; - desc.Height = (UINT)bins[0].size.h; - desc.MipLevels = 6; - desc.ArraySize = 1; - desc.Format = FORMAT_R8G8B8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = USAGE_DEFAULT; - desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - atlasTexture = new Texture2D; - atlasTexture->RequestIndependentUnorderedAccessResourcesForMIPs(true); - - device->CreateTexture2D(&desc, nullptr, &atlasTexture); - - for (UINT mip = 0; mip < atlasTexture->GetDesc().MipLevels; ++mip) - { - for (auto& it : storedTextures) - { - if (mip < it.first->GetDesc().MipLevels) - { - //device->CopyTexture2D_Region(atlasTexture, mip, it.second.x >> mip, it.second.y >> mip, it.first, mip, threadID); - - // This is better because it implements format conversion so we can use multiple decal source texture formats in the atlas: - CopyTexture2D(atlasTexture, mip, it.second.x >> mip, it.second.y >> mip, it.first, mip, threadID); - } - } - } - } - else - { - wiBackLog::post("Decal atlas packing failed!"); - } - - SAFE_DELETE_ARRAY(out_rects); + repackAtlas = true; } } - // 3.) Assign atlas buckets to decals: + // 3.) Update atlas texture if it is invalidated: + if (repackAtlas) + { + rect_xywhf** out_rects = new rect_xywhf*[storedTextures.size()]; + int i = 0; + for (auto& it : storedTextures) + { + out_rects[i] = &it.second; + i++; + } + + std::vector bins; + if (pack(out_rects, (int)storedTextures.size(), 16384, bins)) + { + assert(bins.size() == 1 && "The regions won't fit into the texture!"); + + SAFE_DELETE(atlasTexture); + + TextureDesc desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = (UINT)bins[0].size.w; + desc.Height = (UINT)bins[0].size.h; + desc.MipLevels = 0; + desc.ArraySize = 1; + desc.Format = FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = USAGE_DEFAULT; + desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + atlasTexture = new Texture2D; + atlasTexture->RequestIndependentUnorderedAccessResourcesForMIPs(true); + + device->CreateTexture2D(&desc, nullptr, &atlasTexture); + + for (UINT mip = 0; mip < atlasTexture->GetDesc().MipLevels; ++mip) + { + for (auto& it : storedTextures) + { + if (mip < it.first->GetDesc().MipLevels) + { + //device->CopyTexture2D_Region(atlasTexture, mip, it.second.x >> mip, it.second.y >> mip, it.first, mip, threadID); + + // This is better because it implements format conversion so we can use multiple decal source texture formats in the atlas: + CopyTexture2D(atlasTexture, mip, (it.second.x >> mip) + atlasClampBorder, (it.second.y >> mip) + atlasClampBorder, it.first, mip, threadID, BORDEREXPAND_CLAMP); + } + } + } + } + else + { + wiBackLog::post("Decal atlas packing failed!"); + } + + SAFE_DELETE_ARRAY(out_rects); + } + + // 4.) Assign atlas buckets to decals: for (Model* model : GetScene().models) { if (model->decals.empty()) @@ -7391,8 +7399,16 @@ void wiRenderer::ManageDecalAtlas(GRAPHICSTHREAD threadID) { if (decal->texture != nullptr) { + const TextureDesc& desc = atlasTexture->GetDesc(); + rect_xywhf rect = storedTextures[decal->texture]; - TextureDesc desc = atlasTexture->GetDesc(); + + // eliminate border expansion: + rect.x += atlasClampBorder; + rect.y += atlasClampBorder; + rect.w -= atlasClampBorder * 2; + rect.h -= atlasClampBorder * 2; + decal->atlasMulAdd = XMFLOAT4((float)rect.w / (float)desc.Width, (float)rect.h / (float)desc.Height, (float)rect.x / (float)desc.Width, (float)rect.y / (float)desc.Height); } else