From 00fd6ce281bb28b53f6d22ff2427c97556238c6f Mon Sep 17 00:00:00 2001 From: turanszkij Date: Sat, 17 Mar 2018 20:27:06 +0000 Subject: [PATCH] new feature: volumetric light scattering --- Editor/LightWindow.cpp | 15 ++ Editor/LightWindow.h | 1 + WickedEngine/ArchiveVersionHistory.txt | 1 + WickedEngine/Renderable3DComponent.cpp | 22 +- WickedEngine/Renderable3DComponent.h | 1 + WickedEngine/WickedEngine_SHADERS.vcxproj | 11 +- .../WickedEngine_SHADERS.vcxproj.filters | 15 +- WickedEngine/deferredLightHF.hlsli | 2 +- WickedEngine/lightVisualizerPS.hlsl | 6 + WickedEngine/objectPS_voxelizer.hlsl | 2 +- WickedEngine/volumeLightPS.hlsl | 11 - .../volumetricLight_DirectionalPS.hlsl | 55 +++++ WickedEngine/volumetricLight_PointPS.hlsl | 55 +++++ WickedEngine/volumetricLight_SpotPS.hlsl | 67 ++++++ WickedEngine/wiArchive.cpp | 2 +- WickedEngine/wiEnums.h | 17 +- WickedEngine/wiLoader.cpp | 9 + WickedEngine/wiLoader.h | 1 + WickedEngine/wiRenderer.cpp | 222 ++++++++++++++---- WickedEngine/wiRenderer.h | 1 + WickedEngine/wiVersion.cpp | 2 +- features.txt | 1 + 22 files changed, 439 insertions(+), 80 deletions(-) create mode 100644 WickedEngine/lightVisualizerPS.hlsl delete mode 100644 WickedEngine/volumeLightPS.hlsl create mode 100644 WickedEngine/volumetricLight_DirectionalPS.hlsl create mode 100644 WickedEngine/volumetricLight_PointPS.hlsl create mode 100644 WickedEngine/volumetricLight_SpotPS.hlsl diff --git a/Editor/LightWindow.cpp b/Editor/LightWindow.cpp index 88e2c11e0..44efdba53 100644 --- a/Editor/LightWindow.cpp +++ b/Editor/LightWindow.cpp @@ -121,6 +121,18 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) shadowCheckBox->SetTooltip("Set light as shadow caster. Many shadow casters can affect performance!"); lightWindow->AddWidget(shadowCheckBox); + volumetricsCheckBox = new wiCheckBox("Volumetric Scattering: "); + volumetricsCheckBox->SetPos(XMFLOAT2(x, y += step)); + volumetricsCheckBox->OnClick([&](wiEventArgs args) { + if (light != nullptr) + { + light->volumetrics = args.bValue; + } + }); + volumetricsCheckBox->SetEnabled(false); + volumetricsCheckBox->SetTooltip("Compute volumetric light scattering effect. The scattering is modulated by fog settings!"); + lightWindow->AddWidget(volumetricsCheckBox); + haloCheckBox = new wiCheckBox("Visualizer: "); haloCheckBox->SetPos(XMFLOAT2(x, y += step)); haloCheckBox->OnClick([&](wiEventArgs args) { @@ -217,6 +229,8 @@ void LightWindow::SetLight(Light* light) shadowCheckBox->SetCheck(light->shadow); haloCheckBox->SetEnabled(true); haloCheckBox->SetCheck(!light->noHalo); + volumetricsCheckBox->SetEnabled(true); + volumetricsCheckBox->SetCheck(light->volumetrics); colorPicker->SetEnabled(true); typeSelectorComboBox->SetEnabled(true); typeSelectorComboBox->SetSelected((int)light->GetType()); @@ -233,6 +247,7 @@ void LightWindow::SetLight(Light* light) biasSlider->SetEnabled(false); shadowCheckBox->SetEnabled(false); haloCheckBox->SetEnabled(false); + volumetricsCheckBox->SetEnabled(false); energySlider->SetEnabled(false); colorPicker->SetEnabled(false); typeSelectorComboBox->SetEnabled(false); diff --git a/Editor/LightWindow.h b/Editor/LightWindow.h index 9d4458f36..eb4aa0ddb 100644 --- a/Editor/LightWindow.h +++ b/Editor/LightWindow.h @@ -35,6 +35,7 @@ public: wiSlider* biasSlider; wiCheckBox* shadowCheckBox; wiCheckBox* haloCheckBox; + wiCheckBox* volumetricsCheckBox; wiButton* addLightButton; wiColorPicker* colorPicker; wiComboBox* typeSelectorComboBox; diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 13bb596ff..eba77d7bb 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wiArchive versions +17: serialized light scattering property 16: environment probes are now serialized into Model 15: removed redundant matrix store from hair paticle serializator 14: serialize emitter property: shaderType diff --git a/WickedEngine/Renderable3DComponent.cpp b/WickedEngine/Renderable3DComponent.cpp index ad51a1b32..fdef7e2a0 100644 --- a/WickedEngine/Renderable3DComponent.cpp +++ b/WickedEngine/Renderable3DComponent.cpp @@ -29,6 +29,7 @@ wiRenderTarget , Renderable3DComponent::rtWaterRipple , Renderable3DComponent::rtLinearDepth , Renderable3DComponent::rtParticle + , Renderable3DComponent::rtVolumetricLights , Renderable3DComponent::rtFinal[2] , Renderable3DComponent::rtDof[3] , Renderable3DComponent::rtTemporalAA[2] @@ -72,6 +73,9 @@ void Renderable3DComponent::ResizeBuffers() rtParticle.Initialize( (UINT)(wiRenderer::GetInternalResolution().x*getParticleDownSample()), (UINT)(wiRenderer::GetInternalResolution().y*getParticleDownSample()) , false, wiRenderer::RTFormat_hdr); + rtVolumetricLights.Initialize( + (UINT)(wiRenderer::GetInternalResolution().x*0.25f), (UINT)(wiRenderer::GetInternalResolution().y*0.25f) + , false, wiRenderer::RTFormat_hdr); rtWaterRipple.Initialize( wiRenderer::GetInternalResolution().x, wiRenderer::GetInternalResolution().y , false, wiRenderer::RTFormat_waterripple); @@ -373,6 +377,12 @@ void Renderable3DComponent::RenderSecondaryScene(wiRenderTarget& mainRT, wiRende wiRenderer::GetDevice()->EventEnd(threadID); } + if (getVolumeLightsEnabled()) + { + rtVolumetricLights.Activate(threadID, 0, 0, 0, 0); + wiRenderer::DrawVolumeLights(wiRenderer::getCamera(), threadID); + } + if (getEmittedParticlesEnabled()) { rtParticle.Activate(threadID, 0, 0, 0, 0); @@ -402,10 +412,7 @@ void Renderable3DComponent::RenderSecondaryScene(wiRenderTarget& mainRT, wiRende RenderTransparentScene(rtSceneCopy, threadID); wiRenderer::DrawTrails(threadID, rtSceneCopy.GetTexture()); - if (getVolumeLightsEnabled()) - { - wiRenderer::DrawVolumeLights(wiRenderer::getCamera(), threadID); - } + wiRenderer::DrawLightVisualizers(wiRenderer::getCamera(), threadID); fx.presentFullScreen = true; @@ -416,6 +423,13 @@ void Renderable3DComponent::RenderSecondaryScene(wiRenderTarget& mainRT, wiRende wiRenderer::GetDevice()->EventEnd(threadID); } + if (getVolumeLightsEnabled()) + { + wiRenderer::GetDevice()->EventBegin("Contribute Volumetric Lights", threadID); + wiImage::Draw(rtVolumetricLights.GetTexture(), fx, threadID); + wiRenderer::GetDevice()->EventEnd(threadID); + } + if (getLightShaftsEnabled()) { wiRenderer::GetDevice()->EventBegin("Contribute LightShafts", threadID); fx.blendFlag = BLENDMODE_ADDITIVE; diff --git a/WickedEngine/Renderable3DComponent.h b/WickedEngine/Renderable3DComponent.h index e48b9b698..abe517c81 100644 --- a/WickedEngine/Renderable3DComponent.h +++ b/WickedEngine/Renderable3DComponent.h @@ -56,6 +56,7 @@ protected: , rtWaterRipple , rtLinearDepth , rtParticle + , rtVolumetricLights , rtFinal[2] , rtDof[3] , rtTemporalAA[2] diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj b/WickedEngine/WickedEngine_SHADERS.vcxproj index f4cce4d9a..f0a1fc8ca 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj @@ -612,7 +612,16 @@ Pixel - + + Pixel + + + Pixel + + + Pixel + + Pixel diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters index 528857991..f50f21ef8 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters @@ -240,9 +240,6 @@ PS - - PS - PS @@ -693,6 +690,18 @@ PS + + PS + + + PS + + + PS + + + PS + diff --git a/WickedEngine/deferredLightHF.hlsli b/WickedEngine/deferredLightHF.hlsli index 7d6756248..78b692f86 100644 --- a/WickedEngine/deferredLightHF.hlsli +++ b/WickedEngine/deferredLightHF.hlsli @@ -26,7 +26,7 @@ struct LightOutputType #define DEFERREDLIGHT_MAKEPARAMS \ ShaderEntityType light = EntityArray[PSIn.lightIndex]; \ float3 diffuse, specular; \ - float2 ScreenCoord = float2(1, -1) * PSIn.pos2D.xy / PSIn.pos2D.w * 0.5f + 0.5f; \ + float2 ScreenCoord = PSIn.pos2D.xy / PSIn.pos2D.w * float2(0.5f, -0.5f) + 0.5f; \ float depth = texture_depth[PSIn.pos.xy]; \ float4 baseColor = texture_gbuffer0[PSIn.pos.xy]; \ float4 g1 = texture_gbuffer1[PSIn.pos.xy]; \ diff --git a/WickedEngine/lightVisualizerPS.hlsl b/WickedEngine/lightVisualizerPS.hlsl new file mode 100644 index 000000000..e770bb48a --- /dev/null +++ b/WickedEngine/lightVisualizerPS.hlsl @@ -0,0 +1,6 @@ +#include "volumeLightHF.hlsli" + +float4 main(VertexToPixel PSIn) : SV_TARGET +{ + return max(PSIn.col,0); +} \ No newline at end of file diff --git a/WickedEngine/objectPS_voxelizer.hlsl b/WickedEngine/objectPS_voxelizer.hlsl index a8781ccc8..63599eaaa 100644 --- a/WickedEngine/objectPS_voxelizer.hlsl +++ b/WickedEngine/objectPS_voxelizer.hlsl @@ -40,7 +40,7 @@ void main(float4 pos : SV_POSITION, float3 N : NORMAL, float2 tex : TEXCOORD, fl { float4 ShPos = mul(float4(P, 1), MatrixArray[light.additionalData_index + 0]); ShPos.xyz /= ShPos.w; - float3 ShTex = ShPos.xyz*float3(1, -1, 1) / 2.0f + 0.5f; + float3 ShTex = ShPos.xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; [branch]if ((saturate(ShTex.x) == ShTex.x) && (saturate(ShTex.y) == ShTex.y) && (saturate(ShTex.z) == ShTex.z)) { diff --git a/WickedEngine/volumeLightPS.hlsl b/WickedEngine/volumeLightPS.hlsl deleted file mode 100644 index 7551569fb..000000000 --- a/WickedEngine/volumeLightPS.hlsl +++ /dev/null @@ -1,11 +0,0 @@ -#include "volumeLightHF.hlsli" -//#include "depthConvertHF.hlsli" -//#include "effectHF_PS.hlsli" -//#include "fogHF.hlsli" - -float4 main(VertexToPixel PSIn) : SV_TARGET -{ - //float4 color = PSIn.col; - //color.rgb = applyFog(color.rgb,xHorizon,getFog(getLinearDepth(PSIn.pos2D.z/PSIn.pos2D.w),xFogSEH)); - return max(PSIn.col,0); -} \ No newline at end of file diff --git a/WickedEngine/volumetricLight_DirectionalPS.hlsl b/WickedEngine/volumetricLight_DirectionalPS.hlsl new file mode 100644 index 000000000..54c9c1883 --- /dev/null +++ b/WickedEngine/volumetricLight_DirectionalPS.hlsl @@ -0,0 +1,55 @@ +#include "deferredLightHF.hlsli" +#include "fogHF.hlsli" + +float4 main(VertexToPixel input) : SV_TARGET +{ + ShaderEntityType light = EntityArray[(uint)g_xColor.x]; + + if (light.additionalData_index < 0) + { + // Dirlight volume has no meaning without shadows!! + return 0; + } + + float2 ScreenCoord = input.pos2D.xy / input.pos2D.w * float2(0.5f, -0.5f) + 0.5f; + float depth = max(input.pos.z, texture_depth.SampleLevel(sampler_linear_clamp, ScreenCoord, 0)); + float3 P = getPosition(ScreenCoord, depth); + float3 V = g_xCamera_CamPos - P; + float cameraDistance = length(V); + V /= cameraDistance; + + float marchedDistance = 0; + float3 accumulation = 0; + + const float3 L = light.directionWS; + + // Perform ray marching to integrate light volume along view ray: + float sum = 0; + while (marchedDistance < cameraDistance) + { + float3 attenuation = 1; + + float4 ShPos = mul(float4(P, 1), MatrixArray[light.additionalData_index + 0]); + ShPos.xyz /= ShPos.w; + float3 ShTex = ShPos.xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; + + [branch]if ((saturate(ShTex.x) == ShTex.x) && (saturate(ShTex.y) == ShTex.y) && (saturate(ShTex.z) == ShTex.z)) + { + attenuation *= shadowCascade(ShPos, ShTex.xy, light.shadowKernel, light.shadowBias, light.additionalData_index + 0); + } + + attenuation *= GetFog(cameraDistance - marchedDistance); + + accumulation += attenuation; + + const float stepSize = 0.5f; + marchedDistance += stepSize; + P = P + V * stepSize; + + sum += 1.0f; + } + + accumulation /= sum; + + return max(0, float4(accumulation * light.GetColor().rgb * light.energy, 1)); +} \ No newline at end of file diff --git a/WickedEngine/volumetricLight_PointPS.hlsl b/WickedEngine/volumetricLight_PointPS.hlsl new file mode 100644 index 000000000..7affb07d9 --- /dev/null +++ b/WickedEngine/volumetricLight_PointPS.hlsl @@ -0,0 +1,55 @@ +#include "deferredLightHF.hlsli" +#include "fogHF.hlsli" + +float4 main(VertexToPixel input) : SV_TARGET +{ + ShaderEntityType light = EntityArray[(uint)g_xColor.x]; + + float2 ScreenCoord = input.pos2D.xy / input.pos2D.w * float2(0.5f, -0.5f) + 0.5f; + float depth = max(input.pos.z, texture_depth.SampleLevel(sampler_linear_clamp, ScreenCoord, 0)); + float3 P = getPosition(ScreenCoord, depth); + float3 V = g_xCamera_CamPos - P; + float cameraDistance = length(V); + V /= cameraDistance; + + float marchedDistance = 0; + float accumulation = 0; + + float3 L = light.positionWS - P; + float dist = length(L); + L /= dist; + + // reposition ray start to be inside light all times: + dist = min(dist, light.range); + P = light.positionWS - L * dist; + + // Perform ray marching to integrate light volume along view ray: + float sum = 0; + while (dist <= light.range && marchedDistance < cameraDistance) + { + float att = (light.energy * (light.range / (light.range + 1 + dist))); + float attenuation = (att * (light.range - dist) / light.range); + + [branch] + if (light.additionalData_index >= 0) { + attenuation *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.additionalData_index), 1 - dist / light.range * (1 - light.shadowBias)).r; + } + + attenuation *= GetFog(cameraDistance - marchedDistance); + + accumulation += attenuation; + + const float stepSize = 0.1f; + marchedDistance += stepSize; + P = P + V * stepSize; + L = light.positionWS - P; + dist = length(L); + L /= dist; + + sum += 1.0f; + } + + accumulation /= sum; + + return max(0, float4(accumulation.xxx * light.GetColor().rgb * light.energy, 1)); +} \ No newline at end of file diff --git a/WickedEngine/volumetricLight_SpotPS.hlsl b/WickedEngine/volumetricLight_SpotPS.hlsl new file mode 100644 index 000000000..6e2062327 --- /dev/null +++ b/WickedEngine/volumetricLight_SpotPS.hlsl @@ -0,0 +1,67 @@ +#include "deferredLightHF.hlsli" +#include "fogHF.hlsli" + +float4 main(VertexToPixel input) : SV_TARGET +{ + ShaderEntityType light = EntityArray[(uint)g_xColor.x]; + + float2 ScreenCoord = input.pos2D.xy / input.pos2D.w * float2(0.5f, -0.5f) + 0.5f; + float depth = max(input.pos.z, texture_depth.SampleLevel(sampler_linear_clamp, ScreenCoord, 0)); + float3 P = getPosition(ScreenCoord, depth); + float3 V = g_xCamera_CamPos - P; + float cameraDistance = length(V); + V /= cameraDistance; + + float marchedDistance = 0; + float3 accumulation = 0; + + float3 L = light.positionWS - P; + float dist = length(L); + L /= dist; + + // Perform ray marching to integrate light volume along view ray: + float sum = 0; + while (dist <= light.range && marchedDistance < cameraDistance) + { + float SpotFactor = dot(L, light.directionWS); + float spotCutOff = light.coneAngleCos; + + [branch] + if (SpotFactor > spotCutOff) + { + float att = (light.energy * (light.range / (light.range + 1 + dist))); + float3 attenuation = (att * (light.range - dist) / light.range); + attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff))); + + [branch] + if (light.additionalData_index >= 0) + { + float4 ShPos = mul(float4(P, 1), MatrixArray[light.additionalData_index + 0]); + ShPos.xyz /= ShPos.w; + float2 ShTex = ShPos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f); + [branch] + if ((saturate(ShTex.x) == ShTex.x) && (saturate(ShTex.y) == ShTex.y)) + { + attenuation *= shadowCascade(ShPos, ShTex.xy, light.shadowKernel, light.shadowBias, light.additionalData_index); + } + } + + attenuation *= GetFog(distance(P, g_xCamera_CamPos)); + + accumulation += attenuation; + } + + const float stepSize = 0.1f; + marchedDistance += stepSize; + P = P + V * stepSize; + L = light.positionWS - P; + dist = length(L); + L /= dist; + + sum += 1.0f; + } + + accumulation /= sum; + + return max(0, float4(accumulation * light.GetColor().rgb * light.energy, 1)); +} \ No newline at end of file diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 9d2b8c0ef..8f1964bf5 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -7,7 +7,7 @@ using namespace std; // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! -uint64_t __archiveVersion = 16; +uint64_t __archiveVersion = 17; // this is the version number of which below the archive is not compatible with the current version uint64_t __archiveVersionBarrier = 1; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 908b7e347..e73fd04fe 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -127,12 +127,12 @@ enum VSTYPES VSTYPE_DIRLIGHT, VSTYPE_POINTLIGHT, VSTYPE_SPOTLIGHT, - VSTYPE_VOLUMESPOTLIGHT, - VSTYPE_VOLUMEPOINTLIGHT, - VSTYPE_VOLUMESPHERELIGHT, - VSTYPE_VOLUMEDISCLIGHT, - VSTYPE_VOLUMERECTANGLELIGHT, - VSTYPE_VOLUMETUBELIGHT, + VSTYPE_LIGHTVISUALIZER_SPOTLIGHT, + VSTYPE_LIGHTVISUALIZER_POINTLIGHT, + VSTYPE_LIGHTVISUALIZER_SPHERELIGHT, + VSTYPE_LIGHTVISUALIZER_DISCLIGHT, + VSTYPE_LIGHTVISUALIZER_RECTANGLELIGHT, + VSTYPE_LIGHTVISUALIZER_TUBELIGHT, VSTYPE_SKY, VSTYPE_DECAL, VSTYPE_ENVMAP, @@ -204,7 +204,10 @@ enum PSTYPES PSTYPE_DISCLIGHT, PSTYPE_RECTANGLELIGHT, PSTYPE_TUBELIGHT, - PSTYPE_VOLUMELIGHT, + PSTYPE_LIGHTVISUALIZER, + PSTYPE_VOLUMETRICLIGHT_DIRECTIONAL, + PSTYPE_VOLUMETRICLIGHT_POINT, + PSTYPE_VOLUMETRICLIGHT_SPOT, PSTYPE_SHADOWCUBEMAPRENDER, PSTYPE_SHADOWCUBEMAPRENDER_ALPHATEST, PSTYPE_DECAL, diff --git a/WickedEngine/wiLoader.cpp b/WickedEngine/wiLoader.cpp index 9760da691..846ad8190 100644 --- a/WickedEngine/wiLoader.cpp +++ b/WickedEngine/wiLoader.cpp @@ -4134,6 +4134,7 @@ Light::Light():Transform() { SetType(LightType::POINT); shadow = false; noHalo = false; + volumetrics = false; lensFlareRimTextures.resize(0); lensFlareNames.resize(0); shadowMap_index = -1; @@ -4369,6 +4370,10 @@ void Light::Serialize(wiArchive& archive) archive >> width; archive >> height; } + if (archive.GetVersion() >= 17) + { + archive >> volumetrics; + } } else { @@ -4390,6 +4395,10 @@ void Light::Serialize(wiArchive& archive) archive << width; archive << height; } + if (archive.GetVersion() >= 17) + { + archive << volumetrics; + } } } #pragma endregion diff --git a/WickedEngine/wiLoader.h b/WickedEngine/wiLoader.h index 95594bc5f..b9bc0f097 100644 --- a/WickedEngine/wiLoader.h +++ b/WickedEngine/wiLoader.h @@ -902,6 +902,7 @@ struct Light : public Cullable , public Transform XMFLOAT4 color; XMFLOAT4 enerDis; + bool volumetrics = false; bool noHalo; bool shadow; std::vector lensFlareRimTextures; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index d2caeb55e..d6977e57a 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -1157,7 +1157,8 @@ GraphicsPSO* GetImpostorPSO(SHADERTYPE shaderType) } GraphicsPSO* PSO_deferredlight[Light::LIGHTTYPE_COUNT] = {}; -GraphicsPSO* PSO_volumelight[Light::LIGHTTYPE_COUNT] = {}; +GraphicsPSO* PSO_lightvisualizer[Light::LIGHTTYPE_COUNT] = {}; +GraphicsPSO* PSO_volumetriclight[Light::LIGHTTYPE_COUNT] = {}; GraphicsPSO* PSO_enviromentallight = nullptr; enum SKYRENDERING @@ -1358,12 +1359,12 @@ void wiRenderer::LoadShaders() vertexShaders[VSTYPE_DIRLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "dirLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; vertexShaders[VSTYPE_POINTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "pointLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; vertexShaders[VSTYPE_SPOTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "spotLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMESPOTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vSpotLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMEPOINTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vPointLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMESPHERELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vSphereLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMEDISCLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vDiscLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMERECTANGLELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vRectangleLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; - vertexShaders[VSTYPE_VOLUMETUBELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vTubeLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_SPOTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vSpotLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_POINTLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vPointLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_SPHERELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vSphereLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_DISCLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vDiscLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_RECTANGLELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vRectangleLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; + vertexShaders[VSTYPE_LIGHTVISUALIZER_TUBELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "vTubeLightVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; vertexShaders[VSTYPE_DECAL] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "decalVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; vertexShaders[VSTYPE_ENVMAP] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "envMapVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; vertexShaders[VSTYPE_ENVMAP_SKY] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "envMap_skyVS.cso", wiResourceManager::VERTEXSHADER))->vertexShader; @@ -1431,7 +1432,10 @@ void wiRenderer::LoadShaders() pixelShaders[PSTYPE_DISCLIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "discLightPS.cso", wiResourceManager::PIXELSHADER)); pixelShaders[PSTYPE_RECTANGLELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "rectangleLightPS.cso", wiResourceManager::PIXELSHADER)); pixelShaders[PSTYPE_TUBELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "tubeLightPS.cso", wiResourceManager::PIXELSHADER)); - pixelShaders[PSTYPE_VOLUMELIGHT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "volumeLightPS.cso", wiResourceManager::PIXELSHADER)); + pixelShaders[PSTYPE_LIGHTVISUALIZER] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "volumeLightPS.cso", wiResourceManager::PIXELSHADER)); + pixelShaders[PSTYPE_VOLUMETRICLIGHT_DIRECTIONAL] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "volumetricLight_DirectionalPS.cso", wiResourceManager::PIXELSHADER)); + pixelShaders[PSTYPE_VOLUMETRICLIGHT_POINT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "volumetricLight_PointPS.cso", wiResourceManager::PIXELSHADER)); + pixelShaders[PSTYPE_VOLUMETRICLIGHT_SPOT] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "volumetricLight_SpotPS.cso", wiResourceManager::PIXELSHADER)); pixelShaders[PSTYPE_DECAL] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "decalPS.cso", wiResourceManager::PIXELSHADER)); pixelShaders[PSTYPE_ENVMAP] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "envMapPS.cso", wiResourceManager::PIXELSHADER)); pixelShaders[PSTYPE_ENVMAP_SKY_STATIC] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "envMap_skyPS_static.cso", wiResourceManager::PIXELSHADER)); @@ -1901,55 +1905,88 @@ void wiRenderer::LoadShaders() - // volume lights: - if (type == Light::DIRECTIONAL) + // light visualizers: + if (type != Light::DIRECTIONAL) { - continue; + + desc.dss = depthStencils[DSSTYPE_DEPTHREAD]; + desc.ps = pixelShaders[PSTYPE_LIGHTVISUALIZER]; + + switch (type) + { + case Light::POINT: + desc.bs = blendStates[BSTYPE_ADDITIVE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_POINTLIGHT]; + desc.rs = rasterizers[RSTYPE_FRONT]; + break; + case Light::SPOT: + desc.bs = blendStates[BSTYPE_ADDITIVE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_SPOTLIGHT]; + desc.rs = rasterizers[RSTYPE_DOUBLESIDED]; + break; + case Light::SPHERE: + desc.bs = blendStates[BSTYPE_OPAQUE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_SPHERELIGHT]; + desc.rs = rasterizers[RSTYPE_FRONT]; + break; + case Light::DISC: + desc.bs = blendStates[BSTYPE_OPAQUE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_DISCLIGHT]; + desc.rs = rasterizers[RSTYPE_FRONT]; + break; + case Light::RECTANGLE: + desc.bs = blendStates[BSTYPE_OPAQUE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_RECTANGLELIGHT]; + desc.rs = rasterizers[RSTYPE_BACK]; + break; + case Light::TUBE: + desc.bs = blendStates[BSTYPE_OPAQUE]; + desc.vs = vertexShaders[VSTYPE_LIGHTVISUALIZER_TUBELIGHT]; + desc.rs = rasterizers[RSTYPE_FRONT]; + break; + } + + desc.numRTs = 1; + desc.RTFormats[0] = RTFormat_hdr; + desc.DSFormat = DSFormat_full; + + RECREATE(PSO_lightvisualizer[type]); + device->CreateGraphicsPSO(&desc, PSO_lightvisualizer[type]); } - desc.dss = depthStencils[DSSTYPE_DEPTHREAD]; - desc.ps = pixelShaders[PSTYPE_VOLUMELIGHT]; - switch (type) + // volumetric lights: + if (type <= Light::SPOT) { - case Light::POINT: + desc.dss = depthStencils[DSSTYPE_XRAY]; desc.bs = blendStates[BSTYPE_ADDITIVE]; - desc.vs = vertexShaders[VSTYPE_VOLUMEPOINTLIGHT]; - desc.rs = rasterizers[RSTYPE_FRONT]; - break; - case Light::SPOT: - desc.bs = blendStates[BSTYPE_ADDITIVE]; - desc.vs = vertexShaders[VSTYPE_VOLUMESPOTLIGHT]; - desc.rs = rasterizers[RSTYPE_DOUBLESIDED]; - break; - case Light::SPHERE: - desc.bs = blendStates[BSTYPE_OPAQUE]; - desc.vs = vertexShaders[VSTYPE_VOLUMESPHERELIGHT]; - desc.rs = rasterizers[RSTYPE_FRONT]; - break; - case Light::DISC: - desc.bs = blendStates[BSTYPE_OPAQUE]; - desc.vs = vertexShaders[VSTYPE_VOLUMEDISCLIGHT]; - desc.rs = rasterizers[RSTYPE_FRONT]; - break; - case Light::RECTANGLE: - desc.bs = blendStates[BSTYPE_OPAQUE]; - desc.vs = vertexShaders[VSTYPE_VOLUMERECTANGLELIGHT]; desc.rs = rasterizers[RSTYPE_BACK]; - break; - case Light::TUBE: - desc.bs = blendStates[BSTYPE_OPAQUE]; - desc.vs = vertexShaders[VSTYPE_VOLUMETUBELIGHT]; - desc.rs = rasterizers[RSTYPE_FRONT]; - break; + + switch (type) + { + case Light::DIRECTIONAL: + desc.vs = vertexShaders[VSTYPE_DIRLIGHT]; + desc.ps = pixelShaders[PSTYPE_VOLUMETRICLIGHT_DIRECTIONAL]; + break; + case Light::POINT: + desc.vs = vertexShaders[VSTYPE_POINTLIGHT]; + desc.ps = pixelShaders[PSTYPE_VOLUMETRICLIGHT_POINT]; + break; + case Light::SPOT: + desc.vs = vertexShaders[VSTYPE_SPOTLIGHT]; + desc.ps = pixelShaders[PSTYPE_VOLUMETRICLIGHT_SPOT]; + break; + } + + desc.numRTs = 1; + desc.RTFormats[0] = RTFormat_hdr; + desc.DSFormat = FORMAT_UNKNOWN; + + RECREATE(PSO_volumetriclight[type]); + device->CreateGraphicsPSO(&desc, PSO_volumetriclight[type]); } - desc.numRTs = 1; - desc.RTFormats[0] = RTFormat_hdr; - desc.DSFormat = DSFormat_full; - RECREATE(PSO_volumelight[type]); - device->CreateGraphicsPSO(&desc, PSO_volumelight[type]); } { GraphicsPSODesc desc; @@ -4409,14 +4446,14 @@ void wiRenderer::DrawLights(Camera* camera, GRAPHICSTHREAD threadID) wiProfiler::GetInstance().EndRange(threadID); GetDevice()->EventEnd(threadID); } -void wiRenderer::DrawVolumeLights(Camera* camera, GRAPHICSTHREAD threadID) +void wiRenderer::DrawLightVisualizers(Camera* camera, GRAPHICSTHREAD threadID) { const FrameCulling& culling = frameCullings[camera]; const CulledList& culledLights = culling.culledLights; if(!culledLights.empty()) { - GetDevice()->EventBegin("Light Volume Render", threadID); + GetDevice()->EventBegin("Light Visualizer Render", threadID); GetDevice()->BindPrimitiveTopology(TRIANGLELIST,threadID); @@ -4426,7 +4463,7 @@ void wiRenderer::DrawVolumeLights(Camera* camera, GRAPHICSTHREAD threadID) for (int type = Light::POINT; type < Light::LIGHTTYPE_COUNT; ++type) { - GetDevice()->BindGraphicsPSO(PSO_volumelight[type], threadID); + GetDevice()->BindGraphicsPSO(PSO_lightvisualizer[type], threadID); for (Cullable* c : culledLights) { @@ -4523,6 +4560,91 @@ void wiRenderer::DrawVolumeLights(Camera* camera, GRAPHICSTHREAD threadID) GetDevice()->EventEnd(threadID); } + + +} +void wiRenderer::DrawVolumeLights(Camera* camera, GRAPHICSTHREAD threadID) +{ + const FrameCulling& culling = frameCullings[camera]; + const CulledList& culledLights = culling.culledLights; + + if (!culledLights.empty()) + { + GetDevice()->EventBegin("Volumetric Light Render", threadID); + + GetDevice()->BindPrimitiveTopology(TRIANGLELIST, threadID); + + + for (int type = 0; type < Light::LIGHTTYPE_COUNT; ++type) + { + GraphicsPSO* pso = PSO_volumetriclight[type]; + + if (pso == nullptr) + { + continue; + } + + GetDevice()->BindGraphicsPSO(pso, threadID); + + for (Cullable* c : culledLights) + { + Light* l = (Light*)c; + if (l->GetType() == type && l->volumetrics) + { + + switch (type) + { + case Light::DIRECTIONAL: + case Light::SPHERE: + case Light::DISC: + case Light::RECTANGLE: + case Light::TUBE: + { + MiscCB miscCb; + miscCb.mColor.x = (float)l->entityArray_index; + GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &miscCb, threadID); + + GetDevice()->Draw(3, 0, threadID); // full screen triangle + } + break; + case Light::POINT: + { + MiscCB miscCb; + miscCb.mColor.x = (float)l->entityArray_index; + float sca = l->enerDis.y + 1; + miscCb.mTransform = XMMatrixTranspose(XMMatrixScaling(sca, sca, sca)*XMMatrixTranslation(l->translation.x, l->translation.y, l->translation.z) * camera->GetViewProjection()); + GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &miscCb, threadID); + + GetDevice()->Draw(240, 0, threadID); // icosphere + } + break; + case Light::SPOT: + { + MiscCB miscCb; + miscCb.mColor.x = (float)l->entityArray_index; + const float coneS = (const float)(l->enerDis.z / XM_PIDIV4); + miscCb.mTransform = XMMatrixTranspose( + XMMatrixScaling(coneS*l->enerDis.y, l->enerDis.y, coneS*l->enerDis.y)* + XMMatrixRotationQuaternion(XMLoadFloat4(&l->rotation))* + XMMatrixTranslationFromVector(XMLoadFloat3(&l->translation)) * + camera->GetViewProjection() + ); + GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &miscCb, threadID); + + GetDevice()->Draw(192, 0, threadID); // cone + } + break; + } + + } + } + + } + + GetDevice()->EventEnd(threadID); + } + + } void wiRenderer::DrawLensFlares(GRAPHICSTHREAD threadID) { diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index f86ab3a31..890895b40 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -476,6 +476,7 @@ public: static void DrawImages(GRAPHICSTHREAD threadID, wiGraphicsTypes::Texture2D* refracRes); static void DrawImagesNormals(GRAPHICSTHREAD threadID, wiGraphicsTypes::Texture2D* refracRes); static void DrawLights(Camera* camera, GRAPHICSTHREAD threadID); + static void DrawLightVisualizers(Camera* camera, GRAPHICSTHREAD threadID); static void DrawVolumeLights(Camera* camera, GRAPHICSTHREAD threadID); static void DrawLensFlares(GRAPHICSTHREAD threadID); static void DrawDecals(Camera* camera, GRAPHICSTHREAD threadID); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 07dfd8896..e5bd465eb 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 16; // minor bug fixes, alterations, refactors, updates - const int revision = 24; + const int revision = 25; long GetVersion() diff --git a/features.txt b/features.txt index 7e18177cb..713ab3048 100644 --- a/features.txt +++ b/features.txt @@ -77,3 +77,4 @@ Ocean simulation (FFT) Translucent shadows Refraction caustics Local parallax-corrected environment maps +Volumetric light scattering