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