diff --git a/Documentation/ScriptingAPI-Documentation.md b/Documentation/ScriptingAPI-Documentation.md index 2439d5fd5..c4ea4eca8 100644 --- a/Documentation/ScriptingAPI-Documentation.md +++ b/Documentation/ScriptingAPI-Documentation.md @@ -132,7 +132,7 @@ You can use the Renderer with the following functions, all of which are in the g - DrawLine(Vector origin,end, opt Vector color) - PutWaterRipple(String imagename, Vector position) - PutDecal(Decal decal) -- PutEnvProbe(Vector pos, opt int resolution = 256) +- PutEnvProbe(Vector pos) - ClearWorld() - ReloadShaders(opt string path) diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index cc1de10b6..471149906 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -1,8 +1,6 @@ #include "stdafx.h" #include "EnvProbeWindow.h" -int resolution = 256; - EnvProbeWindow::EnvProbeWindow(wiGUI* gui) : GUI(gui) { probe = nullptr; @@ -19,15 +17,8 @@ EnvProbeWindow::EnvProbeWindow(wiGUI* gui) : GUI(gui) float x = 250, y = 0, step = 45; - resolutionSlider = new wiSlider(1, 4096, 256, 4096, "Resolution"); - resolutionSlider->SetPos(XMFLOAT2(x, y += step)); - resolutionSlider->OnSlide([](wiEventArgs args) { - resolution = (int)args.fValue; - }); - envProbeWindow->AddWidget(resolutionSlider); - realTimeCheckBox = new wiCheckBox("RealTime: "); - realTimeCheckBox->SetPos(XMFLOAT2(470, y += step)); + realTimeCheckBox->SetPos(XMFLOAT2(x, y += step)); realTimeCheckBox->SetEnabled(false); realTimeCheckBox->OnClick([&](wiEventArgs args) { if (probe != nullptr) @@ -43,7 +34,7 @@ EnvProbeWindow::EnvProbeWindow(wiGUI* gui) : GUI(gui) generateButton->OnClick([](wiEventArgs args) { XMFLOAT3 pos; XMStoreFloat3(&pos, XMVectorAdd(wiRenderer::getCamera()->GetEye(), wiRenderer::getCamera()->GetAt() * 4)); - wiRenderer::PutEnvProbe(pos, resolution); + wiRenderer::PutEnvProbe(pos); }); envProbeWindow->AddWidget(generateButton); diff --git a/Editor/EnvProbeWindow.h b/Editor/EnvProbeWindow.h index f864fc4fa..b95a288c3 100644 --- a/Editor/EnvProbeWindow.h +++ b/Editor/EnvProbeWindow.h @@ -20,7 +20,6 @@ public: wiWindow* envProbeWindow; - wiSlider* resolutionSlider; wiCheckBox* realTimeCheckBox; wiButton* generateButton; wiButton* refreshButton; diff --git a/WickedEngine/ResourceMapping.h b/WickedEngine/ResourceMapping.h index d673001a0..2414a9538 100644 --- a/WickedEngine/ResourceMapping.h +++ b/WickedEngine/ResourceMapping.h @@ -27,9 +27,7 @@ #define TEXSLOT_GBUFFER4 6 #define TEXSLOT_ENV_GLOBAL 7 -#define TEXSLOT_ENV0 8 -#define TEXSLOT_ENV1 9 -#define TEXSLOT_ENV2 10 +#define TEXSLOT_ENVMAPARRAY 8 #define TEXSLOT_DECALATLAS 11 #define TEXSLOT_SHADOWARRAY_2D 12 diff --git a/WickedEngine/ShaderInterop.h b/WickedEngine/ShaderInterop.h index 6da1e4f67..75d194d06 100644 --- a/WickedEngine/ShaderInterop.h +++ b/WickedEngine/ShaderInterop.h @@ -75,6 +75,7 @@ typedef XMINT4 int4; #define ENTITY_TYPE_RECTANGLELIGHT 5 #define ENTITY_TYPE_TUBELIGHT 6 #define ENTITY_TYPE_DECAL 100 +#define ENTITY_TYPE_ENVMAP 101 #define ENTITY_TYPE_FORCEFIELD_POINT 200 #define ENTITY_TYPE_FORCEFIELD_PLANE 201 diff --git a/WickedEngine/cubeMapPS.hlsl b/WickedEngine/cubeMapPS.hlsl index 4abbab8db..8e7e5f250 100644 --- a/WickedEngine/cubeMapPS.hlsl +++ b/WickedEngine/cubeMapPS.hlsl @@ -12,5 +12,5 @@ float4 main(VSOut_Sphere input) : SV_TARGET float3 P = input.pos3D; float3 N = normalize(input.nor); float3 V = normalize(g_xCamera_CamPos - P); - return float4(DEGAMMA(texture_env0.Sample(sampler_linear_clamp,-reflect(V, N)).rgb),1); + return float4(texture_envmaparray.Sample(sampler_linear_clamp, float4(-reflect(V, N), g_xColor.x)).rgb, 1); } \ No newline at end of file diff --git a/WickedEngine/envMapPS.hlsl b/WickedEngine/envMapPS.hlsl index 3ae63e0f0..5f570c622 100644 --- a/WickedEngine/envMapPS.hlsl +++ b/WickedEngine/envMapPS.hlsl @@ -21,7 +21,5 @@ float4 main(PSIn input) : SV_TARGET OBJECT_PS_FOG - OBJECT_PS_GAMMA - OBJECT_PS_OUT_FORWARD_SIMPLE } \ No newline at end of file diff --git a/WickedEngine/envReflectionHF.hlsli b/WickedEngine/envReflectionHF.hlsli index 52fbb86dd..a8ac25e83 100644 --- a/WickedEngine/envReflectionHF.hlsli +++ b/WickedEngine/envReflectionHF.hlsli @@ -5,25 +5,32 @@ // #define ENVMAP_CAMERA_BLEND inline float3 EnvironmentReflection(in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0) { - float2 size0; - float mipLevels0; - texture_env0.GetDimensions(0, size0.x, size0.y, mipLevels0); - float2 size1; - float mipLevels1; - texture_env1.GetDimensions(0, size1.x, size1.y, mipLevels1); +// float2 size0; +// float mipLevels0; +// texture_env0.GetDimensions(0, size0.x, size0.y, mipLevels0); +// float2 size1; +// float mipLevels1; +// texture_env1.GetDimensions(0, size1.x, size1.y, mipLevels1); +// float3 ref = -reflect(V, N); +// float4 envCol0 = DEGAMMA(texture_env0.SampleLevel(sampler_linear_clamp, ref, roughness*mipLevels0)); +// float4 envCol1 = DEGAMMA(texture_env1.SampleLevel(sampler_linear_clamp, ref, roughness*mipLevels1)); +//#ifdef ENVMAP_CAMERA_BLEND +// float dist0 = distance(g_xCamera_CamPos, g_xFrame_GlobalEnvMap0); +// float dist1 = distance(g_xCamera_CamPos, g_xFrame_GlobalEnvMap1); +//#else +// float dist0 = distance(P, g_xFrame_GlobalEnvMap0); +// float dist1 = distance(P, g_xFrame_GlobalEnvMap1); +//#endif +// static const float blendStrength = 0.05f; +// float blend = clamp((dist0 - dist1)*blendStrength, -1, 1)*0.5f + 0.5f; +// float4 envCol = lerp(envCol0, envCol1, blend); + + + float2 size; + float mipLevels; + texture_env_global.GetDimensions(0, size.x, size.y, mipLevels); float3 ref = -reflect(V, N); - float4 envCol0 = DEGAMMA(texture_env0.SampleLevel(sampler_linear_clamp, ref, roughness*mipLevels0)); - float4 envCol1 = DEGAMMA(texture_env1.SampleLevel(sampler_linear_clamp, ref, roughness*mipLevels1)); -#ifdef ENVMAP_CAMERA_BLEND - float dist0 = distance(g_xCamera_CamPos, g_xFrame_GlobalEnvMap0); - float dist1 = distance(g_xCamera_CamPos, g_xFrame_GlobalEnvMap1); -#else - float dist0 = distance(P, g_xFrame_GlobalEnvMap0); - float dist1 = distance(P, g_xFrame_GlobalEnvMap1); -#endif - static const float blendStrength = 0.05f; - float blend = clamp((dist0 - dist1)*blendStrength, -1, 1)*0.5f + 0.5f; - float4 envCol = lerp(envCol0, envCol1, blend); + float4 envCol = DEGAMMA(texture_env_global.SampleLevel(sampler_linear_clamp, ref, roughness*mipLevels)); float f90 = saturate(50.0 * dot(f0, 0.33)); float3 F = F_Schlick(f0, f90, abs(dot(N, V)) + 1e-5f); diff --git a/WickedEngine/globals.hlsli b/WickedEngine/globals.hlsli index 152022c76..37e757bed 100644 --- a/WickedEngine/globals.hlsli +++ b/WickedEngine/globals.hlsli @@ -10,9 +10,7 @@ TEXTURE2D(texture_gbuffer2, float4, TEXSLOT_GBUFFER2) TEXTURE2D(texture_gbuffer3, float4, TEXSLOT_GBUFFER3) TEXTURE2D(texture_gbuffer4, float4, TEXSLOT_GBUFFER4) TEXTURECUBE(texture_env_global, float4, TEXSLOT_ENV_GLOBAL) -TEXTURECUBE(texture_env0, float4, TEXSLOT_ENV0) -TEXTURECUBE(texture_env1, float4, TEXSLOT_ENV1) -TEXTURECUBE(texture_env2, float4, TEXSLOT_ENV2) +TEXTURECUBEARRAY(texture_envmaparray, float4, TEXSLOT_ENVMAPARRAY) TEXTURE2D(texture_decalatlas, float4, TEXSLOT_DECALATLAS) TEXTURE2DARRAY(texture_shadowarray_2d, float, TEXSLOT_SHADOWARRAY_2D) TEXTURECUBEARRAY(texture_shadowarray_cube, float, TEXSLOT_SHADOWARRAY_CUBE) @@ -69,6 +67,8 @@ CBUFFER(WorldCB, CBSLOT_RENDERER_WORLD) bool g_xWorld_AdvancedRefractions; uint3 g_xWorld_EntityCullingTileCount; uint g_xWorld_TransparentShadowsEnabled; + uint g_xWorld_EnvProbeMipCount; + float3 xPadding_WorldCB; }; CBUFFER(FrameCB, CBSLOT_RENDERER_FRAME) { @@ -91,8 +91,6 @@ CBUFFER(FrameCB, CBSLOT_RENDERER_FRAME) float2 xPadding1_FrameCB; float2 g_xFrame_TemporalAAJitter; float2 g_xFrame_TemporalAAJitterPrev; - float3 g_xFrame_GlobalEnvMap0; float xPadding2_FrameCB; - float3 g_xFrame_GlobalEnvMap1; float xPadding3_FrameCB; // The following are per frame properties for the main camera: float4x4 g_xFrame_MainCamera_VP; // View*Projection float4x4 g_xFrame_MainCamera_View; diff --git a/WickedEngine/hairparticlePS_tiledforward.hlsl b/WickedEngine/hairparticlePS_tiledforward.hlsl index e0472505d..df167bd55 100644 --- a/WickedEngine/hairparticlePS_tiledforward.hlsl +++ b/WickedEngine/hairparticlePS_tiledforward.hlsl @@ -1,4 +1,5 @@ #define DISABLE_DECALS +#define DISABLE_LOCALENVPMAPS #include "globals.hlsli" #include "objectHF.hlsli" #include "hairparticleHF.hlsli" diff --git a/WickedEngine/lightCullingCS.hlsl b/WickedEngine/lightCullingCS.hlsl index 7f702a0a6..42de3131b 100644 --- a/WickedEngine/lightCullingCS.hlsl +++ b/WickedEngine/lightCullingCS.hlsl @@ -50,11 +50,13 @@ groupshared uint uDepthMask; // Harada Siggraph 2012 2.5D culling groupshared uint o_ArrayLength; groupshared uint o_Array[LDS_ENTITYCOUNT]; groupshared uint o_decalCount; +groupshared uint o_envmapCount; // Transparent geometry entity lists. groupshared uint t_ArrayLength; groupshared uint t_Array[LDS_ENTITYCOUNT]; groupshared uint t_decalCount; +groupshared uint t_envmapCount; // Add the entity to the visible entity list for opaque geometry. void o_AppendEntity(uint entityIndex) @@ -204,6 +206,8 @@ void main(ComputeShaderInput IN) t_ArrayLength = 0; o_decalCount = 0; t_decalCount = 0; + o_envmapCount = 0; + t_envmapCount = 0; uDepthMask = 0; @@ -358,11 +362,20 @@ void main(ComputeShaderInput IN) break; #ifndef DEFERRED case ENTITY_TYPE_DECAL: + case ENTITY_TYPE_ENVMAP: { Sphere sphere = { entity.positionVS.xyz, entity.range }; if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS)) { - InterlockedAdd(t_decalCount, 1); + if (entity.type == ENTITY_TYPE_DECAL) + { + InterlockedAdd(t_decalCount, 1); + } + else + { + InterlockedAdd(t_envmapCount, 1); + } + t_AppendEntity(i); // unit AABB: @@ -380,7 +393,15 @@ void main(ComputeShaderInput IN) if (uDepthMask & ConstructEntityMask(minDepthVS, __depthRangeRecip, sphere)) #endif { - InterlockedAdd(o_decalCount, 1); + if (entity.type == ENTITY_TYPE_DECAL) + { + InterlockedAdd(o_decalCount, 1); + } + else + { + InterlockedAdd(o_envmapCount, 1); + } + o_AppendEntity(i); } } @@ -401,22 +422,22 @@ void main(ComputeShaderInput IN) #ifndef DEFERRED if (IN.groupIndex == 0) { - o_EntityIndexList[exportStartOffset] = uint(min(o_ArrayLength & 0x00FFFFFF, MAX_SHADER_ENTITY_COUNT_PER_TILE - 1) | ((o_decalCount & 0x000000FF) << 24)); + o_EntityIndexList[exportStartOffset] = uint(min(o_ArrayLength & 0x000FFFFF, MAX_SHADER_ENTITY_COUNT_PER_TILE - 1) | ((o_decalCount & 0x000000FF) << 24) | ((o_envmapCount & 0x0000000F) << 20)); } else #endif if(IN.groupIndex == 1) { - t_EntityIndexList[exportStartOffset] = uint(min(t_ArrayLength & 0x00FFFFFF, MAX_SHADER_ENTITY_COUNT_PER_TILE - 1) | ((t_decalCount & 0x000000FF) << 24)); + t_EntityIndexList[exportStartOffset] = uint(min(t_ArrayLength & 0x000FFFFF, MAX_SHADER_ENTITY_COUNT_PER_TILE - 1) | ((t_decalCount & 0x000000FF) << 24) | ((t_envmapCount & 0x0000000F) << 20)); } #ifndef DEFERRED - // Decals need sorting! - if (o_decalCount > 0) + // Decals and envmaps need sorting! + if (o_decalCount + o_envmapCount > 0) { o_BitonicSort(IN.groupIndex); } - if (t_decalCount > 0) + if (t_decalCount + t_envmapCount > 0) { t_BitonicSort(IN.groupIndex); } diff --git a/WickedEngine/objectHF.hlsli b/WickedEngine/objectHF.hlsli index 6d2860273..fef141c57 100644 --- a/WickedEngine/objectHF.hlsli +++ b/WickedEngine/objectHF.hlsli @@ -226,8 +226,9 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P uint2 tileIndex = uint2(floor(pixel / TILED_CULLING_BLOCKSIZE)); uint startOffset = flatten2D(tileIndex, g_xWorld_EntityCullingTileCount.xy) * MAX_SHADER_ENTITY_COUNT_PER_TILE; uint arrayProperties = EntityIndexList[startOffset]; - uint arrayLength = arrayProperties & 0x00FFFFFF; // count of every element in the tile + uint arrayLength = arrayProperties & 0x000FFFFF; // count of every element in the tile uint decalCount = (arrayProperties & 0xFF000000) >> 24; // count of just the decals in the tile + uint envmapCount = (arrayProperties & 0x00F00000) >> 20; // count of just the envmaps in the tile startOffset += 1; // first element was the itemcount uint iterator = 0; @@ -274,8 +275,60 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P } albedo.rgb = lerp(albedo.rgb, decalAccumulation.rgb, decalAccumulation.a); -#endif +#endif // DISABLE_DECALS + +#ifdef DISABLE_LOCALENVPMAPS + // local envmaps are disabled, set iterator to skip: + iterator += envmapCount; +#else + // local envmaps are enabled, loop through them and apply: + float4 envmapAccumulation = 0; + uint envmapArrayEnd = iterator + envmapCount; + + float3 R = -reflect(V, N); + + [loop] + for (; iterator < envmapArrayEnd; ++iterator) + { + ShaderEntityType probe = EntityArray[EntityIndexList[startOffset + iterator]]; + + float4x4 probeProjection = MatrixArray[probe.additionalData_index]; + float3 clipSpace = mul(float4(P, 1), probeProjection).xyz; + float3 uvw = clipSpace.xyz*float3(0.5f, -0.5f, 0.5f) + 0.5f; + [branch] + if (!any(uvw - saturate(uvw))) + { + // Perform parallax correction of reflection ray (R): + float3 RayLS = mul(R, (float3x3)probeProjection); + float3 FirstPlaneIntersect = (float3(1, 1, 1) - clipSpace) / RayLS; + float3 SecondPlaneIntersect = (-float3(1, 1, 1) - clipSpace) / RayLS; + float3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect); + float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z)); + float3 IntersectPositionWS = P + R * Distance; + float3 R_parallaxCorrected = IntersectPositionWS - probe.positionWS; + + // Sample cubemap texture: + float3 envmapColor = texture_envmaparray.SampleLevel(sampler_linear_clamp, float4(R_parallaxCorrected, probe.shadowBias), roughness * g_xWorld_EnvProbeMipCount).rgb; // shadowBias stores textureIndex here... + // blend out if close to any cube edge: + float edgeBlend = 1 - pow(saturate(max(abs(clipSpace.x), max(abs(clipSpace.y), abs(clipSpace.z)))), 8); + // perform manual blending of probes: + // NOTE: they are sorted top-to-bottom, but blending is performed bottom-to-top + envmapAccumulation.rgb = (1 - envmapAccumulation.a) * (edgeBlend*envmapColor) + envmapAccumulation.rgb; + envmapAccumulation.a = edgeBlend + (1 - edgeBlend) * envmapAccumulation.a; + // if the accumulation reached 1, we skip the rest of the probes: + iterator = envmapAccumulation.a < 1 ? iterator : envmapCount - 1; + } + } + + float f90 = saturate(50.0 * dot(f0, 0.33)); + float3 F = F_Schlick(f0, f90, abs(dot(N, V)) + 1e-5f); + + specular += max(0, envmapAccumulation.rgb * F); +#endif // DISABLE_LOCALENVPMAPS + + + // And finally loop through and apply lights: [loop] for (; iterator < arrayLength; iterator++) { diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 9694829ca..81a37e82b 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -102,6 +102,7 @@ enum TEXTYPES TEXTYPE_3D_VOXELRADIANCE, TEXTYPE_3D_VOXELRADIANCE_HELPER, TEXTYPE_2D_CLOUDS, + TEXTYPE_CUBEARRAY_ENVMAPARRAY, TEXTYPE_LAST }; diff --git a/WickedEngine/wiGraphicsDevice_DX11.cpp b/WickedEngine/wiGraphicsDevice_DX11.cpp index 72f62bc43..816c14c3b 100644 --- a/WickedEngine/wiGraphicsDevice_DX11.cpp +++ b/WickedEngine/wiGraphicsDevice_DX11.cpp @@ -2763,7 +2763,7 @@ void GraphicsDevice_DX11::BindRenderTargetsUAVs(UINT NumViews, Texture* const *p ZeroMemory(renderTargetViews, sizeof(renderTargetViews)); for (UINT i = 0; i < min(NumViews, 8); ++i) { - if (arrayIndex < 0) + if (arrayIndex < 0 || ppRenderTargets[i]->additionalRTVs_DX11.empty()) { renderTargetViews[i] = ppRenderTargets[i]->RTV_DX11; } @@ -2778,7 +2778,7 @@ void GraphicsDevice_DX11::BindRenderTargetsUAVs(UINT NumViews, Texture* const *p ID3D11DepthStencilView* depthStencilView = nullptr; if (depthStencilTexture != nullptr) { - if (arrayIndex < 0) + if (arrayIndex < 0 || depthStencilTexture->additionalDSVs_DX11.empty()) { depthStencilView = depthStencilTexture->DSV_DX11; } @@ -2807,7 +2807,7 @@ void GraphicsDevice_DX11::BindRenderTargets(UINT NumViews, Texture* const *ppRen ZeroMemory(renderTargetViews, sizeof(renderTargetViews)); for (UINT i = 0; i < min(NumViews, 8); ++i) { - if (arrayIndex < 0) + if (arrayIndex < 0 || ppRenderTargets[i]->additionalRTVs_DX11.empty()) { renderTargetViews[i] = ppRenderTargets[i]->RTV_DX11; } @@ -2822,7 +2822,7 @@ void GraphicsDevice_DX11::BindRenderTargets(UINT NumViews, Texture* const *ppRen ID3D11DepthStencilView* depthStencilView = nullptr; if (depthStencilTexture != nullptr) { - if (arrayIndex < 0) + if (arrayIndex < 0 || depthStencilTexture->additionalDSVs_DX11.empty()) { depthStencilView = depthStencilTexture->DSV_DX11; } diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp index 6a6b610eb..12cc2d129 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.cpp +++ b/WickedEngine/wiGraphicsDevice_DX12.cpp @@ -3120,8 +3120,15 @@ namespace wiGraphicsTypes void GraphicsDevice_DX12::BindRenderTargetsUAVs(UINT NumViews, Texture* const *ppRenderTargets, Texture2D* depthStencilTexture, GPUResource* const *ppUAVs, int slotUAV, int countUAV, GRAPHICSTHREAD threadID, int arrayIndex) { - //BindRenderTargets(NumViews, ppRenderTargets, depthStencilTexture, threadID, arrayIndex); + BindRenderTargets(NumViews, ppRenderTargets, depthStencilTexture, threadID, arrayIndex); + if (ppUAVs != nullptr) + { + for (int i = 0; i < countUAV; ++i) + { + BindUnorderedAccessResourceCS(ppUAVs[i], slotUAV + i, threadID, -1); + } + } } void GraphicsDevice_DX12::BindRenderTargets(UINT NumViews, Texture* const *ppRenderTargets, Texture2D* depthStencilTexture, GRAPHICSTHREAD threadID, int arrayIndex) { @@ -3130,12 +3137,13 @@ namespace wiGraphicsTypes { if (ppRenderTargets[i] != nullptr) { - if (arrayIndex < 0) + if (arrayIndex < 0 || depthStencilTexture->additionalRTVs_DX12.empty()) { descriptors[i] = *ppRenderTargets[i]->RTV_DX12; } else { + assert(depthStencilTexture->additionalRTVs_DX12.size() > static_cast(arrayIndex) && "Invalid rendertarget arrayIndex!"); descriptors[i] = *ppRenderTargets[i]->additionalRTVs_DX12[arrayIndex]; } } @@ -3144,12 +3152,13 @@ namespace wiGraphicsTypes D3D12_CPU_DESCRIPTOR_HANDLE* DSV = nullptr; if (depthStencilTexture != nullptr) { - if (arrayIndex < 0) + if (arrayIndex < 0 || depthStencilTexture->additionalDSVs_DX12.empty()) { DSV = depthStencilTexture->DSV_DX12; } else { + assert(depthStencilTexture->additionalDSVs_DX12.size() > static_cast(arrayIndex) && "Invalid depthstencil arrayIndex!"); DSV = depthStencilTexture->additionalDSVs_DX12[arrayIndex]; } } @@ -3220,7 +3229,7 @@ namespace wiGraphicsTypes } } } - void GraphicsDevice_DX12::BindUnorderedAccessResourceCS(GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex) + void GraphicsDevice_DX12::BindUnorderedAccessResource(SHADERSTAGE stage, GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex) { if (resource != nullptr && resource->resource_DX12 != nullptr) { @@ -3228,28 +3237,36 @@ namespace wiGraphicsTypes { if (resource->UAV_DX12 != nullptr) { - GetFrameResources().ResourceDescriptorsGPU[threadID]->update(CS, GPU_RESOURCE_HEAP_CBV_COUNT + GPU_RESOURCE_HEAP_SRV_COUNT + slot, + GetFrameResources().ResourceDescriptorsGPU[threadID]->update(stage, GPU_RESOURCE_HEAP_CBV_COUNT + GPU_RESOURCE_HEAP_SRV_COUNT + slot, resource->UAV_DX12, device, GetDirectCommandList(threadID)); } } else { assert(resource->additionalUAVs_DX12.size() > static_cast(arrayIndex) && "Invalid arrayIndex!"); - GetFrameResources().ResourceDescriptorsGPU[threadID]->update(CS, GPU_RESOURCE_HEAP_CBV_COUNT + GPU_RESOURCE_HEAP_SRV_COUNT + slot, + GetFrameResources().ResourceDescriptorsGPU[threadID]->update(stage, GPU_RESOURCE_HEAP_CBV_COUNT + GPU_RESOURCE_HEAP_SRV_COUNT + slot, resource->additionalUAVs_DX12[arrayIndex], device, GetDirectCommandList(threadID)); } } } - void GraphicsDevice_DX12::BindUnorderedAccessResourcesCS(GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID) + void GraphicsDevice_DX12::BindUnorderedAccessResources(SHADERSTAGE stage, GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID) { if (resources != nullptr) { for (int i = 0; i < count; ++i) { - BindUnorderedAccessResourceCS(resources[i], slot + i, threadID, -1); + BindUnorderedAccessResource(stage, resources[i], slot + i, threadID, -1); } } } + void GraphicsDevice_DX12::BindUnorderedAccessResourceCS(GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex) + { + BindUnorderedAccessResource(CS, resource, slot, threadID, arrayIndex); + } + void GraphicsDevice_DX12::BindUnorderedAccessResourcesCS(GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID) + { + BindUnorderedAccessResources(CS, resources, slot, count, threadID); + } void GraphicsDevice_DX12::UnBindResources(int slot, int num, GRAPHICSTHREAD threadID) { for (int stage = 0; stage < SHADERSTAGE_COUNT; ++stage) diff --git a/WickedEngine/wiGraphicsDevice_DX12.h b/WickedEngine/wiGraphicsDevice_DX12.h index d3f4f4028..7ef3017ff 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.h +++ b/WickedEngine/wiGraphicsDevice_DX12.h @@ -184,6 +184,8 @@ namespace wiGraphicsTypes virtual void ClearDepthStencil(Texture2D* pTexture, UINT ClearFlags, FLOAT Depth, UINT8 Stencil, GRAPHICSTHREAD threadID, int arrayIndex = -1) override; virtual void BindResource(SHADERSTAGE stage, GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex = -1) override; virtual void BindResources(SHADERSTAGE stage, GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID) override; + void BindUnorderedAccessResource(SHADERSTAGE stage, GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex = -1); + void BindUnorderedAccessResources(SHADERSTAGE stage, GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID); virtual void BindUnorderedAccessResourceCS(GPUResource* resource, int slot, GRAPHICSTHREAD threadID, int arrayIndex = -1) override; virtual void BindUnorderedAccessResourcesCS(GPUResource *const* resources, int slot, int count, GRAPHICSTHREAD threadID) override; virtual void UnBindResources(int slot, int num, GRAPHICSTHREAD threadID) override; diff --git a/WickedEngine/wiLoader.cpp b/WickedEngine/wiLoader.cpp index 878a55c80..75d68b730 100644 --- a/WickedEngine/wiLoader.cpp +++ b/WickedEngine/wiLoader.cpp @@ -1234,6 +1234,11 @@ void Scene::Update() { x->UpdateModel(); } + + for (EnvironmentProbe* probe : environmentProbes) + { + probe->UpdateEnvProbe(); + } } #pragma endregion @@ -4517,3 +4522,11 @@ void ForceField::Serialize(wiArchive& archive) } } #pragma endregion + +#pragma region ENVIRONMENTPROBE +void EnvironmentProbe::UpdateEnvProbe() +{ + bounds.createFromHalfWidth(XMFLOAT3(0, 0, 0), XMFLOAT3(1, 1, 1)); + bounds = bounds.get(world); +} +#pragma endregion diff --git a/WickedEngine/wiLoader.h b/WickedEngine/wiLoader.h index 74e431169..09116519e 100644 --- a/WickedEngine/wiLoader.h +++ b/WickedEngine/wiLoader.h @@ -1188,13 +1188,15 @@ static const int RESOLUTION = 36; static void CleanUpStatic(); }; -struct EnvironmentProbe : public Transform +struct EnvironmentProbe : public Transform, public Cullable { - wiRenderTarget cubeMap; + int textureIndex; bool realTime; bool isUpToDate; - EnvironmentProbe() :realTime(false), isUpToDate(false) {} + EnvironmentProbe() : textureIndex(-1), realTime(false), isUpToDate(false) {} + + void UpdateEnvProbe(); }; struct ForceField : public Transform { diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 6db7ef787..f5b8cf47b 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -2921,24 +2921,6 @@ void wiRenderer::UpdatePerFrameData(float dt) } wiProfiler::GetInstance().EndRange(); // SPTree Update - // Environment probe sorting: - { - ZeroMemory(globalEnvProbes, sizeof(globalEnvProbes)); - GetScene().environmentProbes.sort( - [&](EnvironmentProbe* a, EnvironmentProbe* b) { - return wiMath::DistanceSquared(a->translation, getCamera()->translation) < wiMath::DistanceSquared(b->translation, getCamera()->translation); - } - ); - int envProbeInd = 0; - for (auto& x : GetScene().environmentProbes) - { - globalEnvProbes[envProbeInd] = x; - envProbeInd++; - if (envProbeInd >= ARRAYSIZE(globalEnvProbes)) - break; - } - } - // Update Voxelization parameters: if (spTree != nullptr) { @@ -3024,6 +3006,14 @@ void wiRenderer::UpdatePerFrameData(float dt) } } + for (EnvironmentProbe* probe : GetScene().environmentProbes) + { + if (culling.frustum.CheckBox(probe->bounds)) + { + x.second.culledEnvProbes.push_back(probe); + } + } + spTree_lights->getVisible(culling.frustum, culling.culledLights, wiSPTree::SortType::SP_TREE_SORT_NONE); if (GetVoxelRadianceEnabled()) @@ -3141,7 +3131,7 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) const FrameCulling& mainCameraCulling = frameCullings[getCamera()]; - // Fill Light Array with lights + decals in the frustum: + // Fill Light Array with lights + envprobes + decals in the frustum: { const CulledList& culledLights = mainCameraCulling.culledLights; @@ -3242,6 +3232,40 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) } entityArrayCount_Lights = entityCounter - entityArrayOffset_Lights; + entityArrayOffset_EnvProbes = entityCounter; + for (EnvironmentProbe* probe : mainCameraCulling.culledEnvProbes) + { + if (probe->textureIndex < 0) + { + continue; + } + if (entityCounter == MAX_SHADER_ENTITY_COUNT) + { + assert(0); // too many entities! + entityCounter--; + break; + } + if (matrixCounter >= MATRIXARRAY_COUNT) + { + assert(0); // too many probes, can't upload the rest to matrixarray! + matrixCounter--; + break; + } + + entityArray[entityCounter].type = ENTITY_TYPE_ENVMAP; + entityArray[entityCounter].positionWS = probe->translation; + XMStoreFloat3(&entityArray[entityCounter].positionVS, XMVector3TransformCoord(XMLoadFloat3(&probe->translation), viewMatrix)); + entityArray[entityCounter].range = max(probe->scale.x, max(probe->scale.y, probe->scale.z)) * 2; + entityArray[entityCounter].shadowBias = (float)probe->textureIndex; + + entityArray[entityCounter].additionalData_index = matrixCounter; + matrixArray[matrixCounter] = XMMatrixTranspose(XMMatrixInverse(nullptr, XMLoadFloat4x4(&probe->world))); + matrixCounter++; + + entityCounter++; + } + entityArrayCount_EnvProbes = entityCounter - entityArrayOffset_EnvProbes; + entityArrayOffset_Decals = entityCounter; for (Decal* decal : mainCameraCulling.culledDecals) { @@ -3447,15 +3471,8 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) // Render out of date environment probes: RefreshEnvProbes(threadID); - // Bind environment probes: - { - GPUResource* envMaps[] = { - globalEnvProbes[0] == nullptr ? enviroMap : globalEnvProbes[0]->cubeMap.GetTexture(), - globalEnvProbes[1] == nullptr ? enviroMap : globalEnvProbes[1]->cubeMap.GetTexture(), - }; - GetDevice()->BindResources(PS, envMaps, TEXSLOT_ENV0, ARRAYSIZE(envMaps), threadID); - GetDevice()->BindResources(CS, envMaps, TEXSLOT_ENV0, ARRAYSIZE(envMaps), threadID); - } + GetDevice()->BindResource(PS, enviroMap, TEXSLOT_ENV_GLOBAL, threadID); + GetDevice()->BindResource(PS, textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], TEXSLOT_ENVMAPARRAY, threadID); } void wiRenderer::OcclusionCulling_Render(GRAPHICSTHREAD threadID) { @@ -3915,6 +3932,9 @@ void wiRenderer::DrawDebugEnvProbes(Camera* camera, GRAPHICSTHREAD threadID) { GetDevice()->EventBegin("Debug EnvProbes", threadID); + + // Envmap spheres: + GetDevice()->BindPrimitiveTopology(TRIANGLELIST, threadID); GetDevice()->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_ENVPROBE], threadID); @@ -3922,15 +3942,39 @@ void wiRenderer::DrawDebugEnvProbes(Camera* camera, GRAPHICSTHREAD threadID) MiscCB sb; for (auto& x : GetScene().environmentProbes) { - sb.mTransform = XMMatrixTranspose(x->getMatrix()); - sb.mColor = XMFLOAT4(1, 1, 1, 1); + sb.mTransform = XMMatrixTranspose(XMMatrixTranslation(x->translation.x, x->translation.y, x->translation.z)); + sb.mColor = XMFLOAT4((float)x->textureIndex, 1, 1, 1); GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &sb, threadID); - GetDevice()->BindResource(PS, x->cubeMap.GetTexture(), TEXSLOT_ENV0, threadID); - GetDevice()->Draw(2880, 0, threadID); // uv-sphere } + + // Local proxy boxes: + + GetDevice()->BindPrimitiveTopology(LINELIST, threadID); + + GetDevice()->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_CUBE], threadID); + + GPUBuffer* vbs[] = { + &Cube::vertexBuffer, + }; + const UINT strides[] = { + sizeof(XMFLOAT4) + sizeof(XMFLOAT4), + }; + GetDevice()->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, nullptr, threadID); + GetDevice()->BindIndexBuffer(&Cube::indexBuffer, INDEXFORMAT_16BIT, 0, threadID); + + for (auto& x : GetScene().environmentProbes) + { + sb.mTransform = XMMatrixTranspose(XMLoadFloat4x4(&x->world)*camera->GetViewProjection()); + sb.mColor = XMFLOAT4(0, 1, 1, 1); + + GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &sb, threadID); + + GetDevice()->DrawIndexed(24, 0, 0, threadID); + } + GetDevice()->EventEnd(threadID); } } @@ -5430,8 +5474,42 @@ void wiRenderer::RefreshEnvProbes(GRAPHICSTHREAD threadID) { GetDevice()->EventBegin("EnvironmentProbe Refresh", threadID); + static const UINT envmapRes = 128; + static const UINT envmapCount = 16; + bool envmapTaken[envmapCount] = {}; + + // reconstruct envmap array status: for (EnvironmentProbe* probe : GetScene().environmentProbes) { + if (probe->textureIndex >= 0) + { + envmapTaken[probe->textureIndex] = true; + } + } + + bool renderhappened = false; + for (EnvironmentProbe* probe : GetScene().environmentProbes) + { + if (probe->textureIndex < 0) + { + // need to take a free envmap texture slot: + bool found = false; + for (int i = 0; i < ARRAYSIZE(envmapTaken); ++i) + { + if (envmapTaken[i] == false) + { + probe->textureIndex = i; + found = true; + break; + } + } + if (!found) + { + // could not find free slot in envmap array, so skip this probe: + continue; + } + } + if (probe->isUpToDate) { continue; @@ -5441,7 +5519,57 @@ void wiRenderer::RefreshEnvProbes(GRAPHICSTHREAD threadID) probe->isUpToDate = true; } - probe->cubeMap.Activate(threadID, 0, 0, 0, 1); + if (textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY] == nullptr) + { + Texture2DDesc desc; + desc.ArraySize = envmapCount * 6; + desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = FORMAT_R16G16B16A16_FLOAT; + desc.Height = envmapRes; + desc.Width = envmapRes; + desc.MipLevels = 0; + desc.MiscFlags = RESOURCE_MISC_GENERATE_MIPS | RESOURCE_MISC_TEXTURECUBE; + desc.Usage = USAGE_DEFAULT; + + textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY] = new Texture2D; + textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]->RequestIndepententRenderTargetArraySlices(true); + HRESULT hr = GetDevice()->CreateTexture2D(&desc, nullptr, (Texture2D**)&textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY]); + assert(SUCCEEDED(hr)); + } + + static Texture2D* envrenderingDepthBuffer = nullptr; + if (envrenderingDepthBuffer == nullptr) + { + Texture2DDesc desc; + desc.ArraySize = 6; + desc.BindFlags = BIND_DEPTH_STENCIL; + desc.CPUAccessFlags = 0; + desc.Format = FORMAT_D16_UNORM; + desc.Height = envmapRes; + desc.Width = envmapRes; + desc.MipLevels = 1; + desc.MiscFlags = RESOURCE_MISC_TEXTURECUBE; + desc.Usage = USAGE_DEFAULT; + + HRESULT hr = GetDevice()->CreateTexture2D(&desc, nullptr, &envrenderingDepthBuffer); + assert(SUCCEEDED(hr)); + } + + GetDevice()->BindRenderTargets(1, &textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], envrenderingDepthBuffer, threadID, probe->textureIndex); + const float clearColor[4] = { 0,0,0,1 }; + GetDevice()->ClearRenderTarget(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], clearColor, threadID, probe->textureIndex); + GetDevice()->ClearDepthStencil(envrenderingDepthBuffer, CLEAR_DEPTH, 0.0f, 0, threadID); + + ViewPort VP; + VP.Height = envmapRes; + VP.Width = envmapRes; + VP.TopLeftX = 0; + VP.TopLeftY = 0; + VP.MinDepth = 0.0f; + VP.MaxDepth = 1.0f; + GetDevice()->BindViewports(1, &VP, threadID); + std::vector cameras; { @@ -5471,7 +5599,7 @@ void wiRenderer::RefreshEnvProbes(GRAPHICSTHREAD threadID) CameraCB camcb; camcb.mCamPos = probe->translation; // only this will be used by envprobe rendering shaders the rest is read from cubemaprenderCB - GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_CAMERA], &cb, threadID); + GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_CAMERA], &camcb, threadID); CulledList culledObjects; @@ -5508,12 +5636,14 @@ void wiRenderer::RefreshEnvProbes(GRAPHICSTHREAD threadID) GetDevice()->Draw(240, 0, threadID); } + renderhappened = true; + } - probe->cubeMap.Deactivate(threadID); - - GetDevice()->GenerateMips(probe->cubeMap.GetTexture(), threadID); - + if (renderhappened) + { + GetDevice()->BindRenderTargets(0, nullptr, nullptr, threadID); + GetDevice()->GenerateMips(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY], threadID); } GetDevice()->EventEnd(threadID); @@ -5834,7 +5964,7 @@ void wiRenderer::ComputeTiledLightCulling(bool deferred, GRAPHICSTHREAD threadID dispatchParams.numThreads[0] = dispatchParams.numThreadGroups[0] * TILED_CULLING_BLOCKSIZE; dispatchParams.numThreads[1] = dispatchParams.numThreadGroups[1] * TILED_CULLING_BLOCKSIZE; dispatchParams.numThreads[2] = 1; - dispatchParams.value0 = (UINT)(frameCullings[getCamera()].culledLights.size() + frameCullings[getCamera()].culledDecals.size()); + dispatchParams.value0 = (UINT)(frameCullings[getCamera()].culledLights.size() + frameCullings[getCamera()].culledEnvProbes.size() + frameCullings[getCamera()].culledDecals.size()); device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID); device->BindConstantBuffer(CS, constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID); @@ -6155,6 +6285,11 @@ void wiRenderer::UpdateWorldCB(GRAPHICSTHREAD threadID) value.mAdvancedRefractions = GetAdvancedRefractionsEnabled() ? 1 : 0; value.mEntityCullingTileCount = GetEntityCullingTileCount(); value.mTransparentShadowsEnabled = TRANSPARENTSHADOWSENABLED; + value.mEnvProbeMipCount = 0; + if (textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY] != nullptr) + { + value.mEnvProbeMipCount = static_cast(textures[TEXTYPE_CUBEARRAY_ENVMAPARRAY])->GetDesc().MipLevels; + } if (memcmp(&prevcb[threadID], &value, sizeof(WorldCB)) != 0) // prevent overcommit { @@ -6185,8 +6320,6 @@ void wiRenderer::UpdateFrameCB(GRAPHICSTHREAD threadID) cb.mSunEntityArrayIndex = GetSunArrayIndex(); cb.mTemporalAAJitter = temporalAAJitter; cb.mTemporalAAJitterPrev = temporalAAJitterPrev; - cb.mGlobalEnvMap0 = globalEnvProbes[0] == nullptr ? XMFLOAT3(0, 0, 0) : globalEnvProbes[0]->translation; - cb.mGlobalEnvMap1 = globalEnvProbes[1] == nullptr ? XMFLOAT3(0, 0, 0) : globalEnvProbes[1]->translation; auto camera = getCamera(); auto prevCam = prevFrameCam; @@ -6854,11 +6987,10 @@ void wiRenderer::SynchronizeWithPhysicsEngine(float dt) } } -void wiRenderer::PutEnvProbe(const XMFLOAT3& position, int resolution) +void wiRenderer::PutEnvProbe(const XMFLOAT3& position) { EnvironmentProbe* probe = new EnvironmentProbe; probe->transform(position); - probe->cubeMap.InitializeCube(resolution, true, RTFormat_envprobe, 0); scene->environmentProbes.push_back(probe); } diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index d1acbbdb0..7378e2e68 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -141,6 +141,8 @@ public: BOOL mAdvancedRefractions; XMUINT3 mEntityCullingTileCount; BOOL mTransparentShadowsEnabled; + UINT mEnvProbeMipCount; + XMFLOAT3 pad0; }; CBUFFER(FrameCB, CBSLOT_RENDERER_FRAME) { @@ -163,8 +165,6 @@ public: XMFLOAT2 pad1; XMFLOAT2 mTemporalAAJitter; XMFLOAT2 mTemporalAAJitterPrev; - XMFLOAT3 mGlobalEnvMap0; float pad2; - XMFLOAT3 mGlobalEnvMap1; float pad3; XMMATRIX mVP; XMMATRIX mView; XMMATRIX mProj; @@ -407,6 +407,7 @@ public: std::vector culledHairParticleSystems; CulledList culledLights; std::list culledDecals; + std::list culledEnvProbes; void Clear() { @@ -416,6 +417,7 @@ public: culledHairParticleSystems.clear(); culledLights.clear(); culledDecals.clear(); + culledEnvProbes.clear(); } }; static std::unordered_map frameCullings; @@ -594,7 +596,7 @@ public: static void LoadWorldInfo(const std::string& fileName); static void LoadDefaultLighting(); - static void PutEnvProbe(const XMFLOAT3& position, int resolution = 256); + static void PutEnvProbe(const XMFLOAT3& position); static void CreateImpostor(Mesh* mesh); diff --git a/WickedEngine/wiRenderer_BindLua.cpp b/WickedEngine/wiRenderer_BindLua.cpp index 18a205809..9d6162b8a 100644 --- a/WickedEngine/wiRenderer_BindLua.cpp +++ b/WickedEngine/wiRenderer_BindLua.cpp @@ -640,21 +640,16 @@ namespace wiRenderer_BindLua { XMFLOAT3 p; XMStoreFloat3(&p, pos->vector); - int res = 256; - if (argc > 1) - { - res = wiLua::SGetInt(L, 2); - } - wiRenderer::PutEnvProbe(p,res); + wiRenderer::PutEnvProbe(p); } else { - wiLua::SError(L, "PutEnvProbe(Vector pos, opt int resolution = 256) argument is not a Vector!"); + wiLua::SError(L, "PutEnvProbe(Vector pos) argument is not a Vector!"); } } else { - wiLua::SError(L, "PutEnvProbe(Vector pos, opt int resolution = 256) not enough arguments!"); + wiLua::SError(L, "PutEnvProbe(Vector pos) not enough arguments!"); } return 0; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 39b8b6f67..f14c05f14 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 14; // minor bug fixes, alterations, refactors, updates - const int revision = 24; + const int revision = 25; long GetVersion()