Skip to content

Commit

Permalink
feat: add settings for water parallax and caustics (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
alandtse authored Apr 4, 2024
1 parent abb767e commit 6fa104d
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
struct PerPassWaterCaustics
{
bool EnableWaterCaustics;
float pad[3];
};

StructuredBuffer<PerPassWaterCaustics> perPassWaterCaustics : register(t71);

#if defined(WATER)

Expand Down
10 changes: 10 additions & 0 deletions features/Water Parallax/Shaders/WaterParallax/WaterParallax.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
// http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf
// https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf

struct PerPassWaterParallax
{
bool EnableWaterParallax;
float pad[3];
};

StructuredBuffer<PerPassWaterParallax> perPassWaterParallax : register(t72);

float GetMipLevel(float2 coords, Texture2D<float4> tex)
{
// Compute the current gradients:
Expand Down Expand Up @@ -39,6 +47,8 @@ float GetHeight(PS_INPUT input, float2 currentOffset, float3 normalScalesRcp, fl

float2 GetParallaxOffset(PS_INPUT input, float3 normalScalesRcp)
{
if (!perPassWaterParallax[0].EnableWaterParallax)
return 0.0.xx;
float3 viewDirection = normalize(input.WPosition.xyz);
float2 parallaxOffsetTS = viewDirection.xy / -viewDirection.z;

Expand Down
3 changes: 2 additions & 1 deletion package/Shaders/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2023,7 +2023,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace
# endif

# if defined(WATER_CAUSTICS)
color.xyz *= ComputeWaterCaustics(waterHeight, input.WorldPosition.xyz, worldSpaceNormal);
if (perPassWaterCaustics[0].EnableWaterCaustics)
color.xyz *= ComputeWaterCaustics(waterHeight, input.WorldPosition.xyz, worldSpaceNormal);
# endif

color.xyz = Lin2sRGB(color.xyz);
Expand Down
3 changes: 2 additions & 1 deletion package/Shaders/Water.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@ float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection,
# endif

# if defined(WATER_CAUSTICS)
refractionColor *= lerp(1.0, caustics, refractionMul);
if (perPassWaterCaustics[0].EnableWaterCaustics)
refractionColor *= lerp(1.0, caustics, refractionMul);
# endif

return lerp(refractionColor * WaterParams.w, refractionDiffuseColor, refractionMul);
Expand Down
50 changes: 48 additions & 2 deletions src/Features/WaterCaustics.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
#include "WaterCaustics.h"

#include "Util.h"
#include <DDSTextureLoader.h>

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
WaterCaustics::Settings,
EnableWaterCaustics)

void WaterCaustics::DrawSettings()
{
if (ImGui::TreeNodeEx("Water Caustics", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Checkbox("Enable Water Caustics", (bool*)&settings.EnableWaterCaustics);
if (auto _tt = Util::HoverTooltipWrapper()) {
ImGui::Text(
"Enables water caustics. "
"Water caustics are the way light bends to create dancing patterns at the bottom of bodies of water.");
}

ImGui::TreePop();
}
}

void WaterCaustics::Draw(const RE::BSShader*, const uint32_t)
{
auto& context = State::GetSingleton()->context;
context->PSSetShaderResources(70, 1, &causticsView);
PerPass data{};
data.settings = settings;

D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(perPass->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(PerPass);
memcpy_s(mapped.pData, bytes, &data, bytes);
context->Unmap(perPass->resource.get(), 0);

ID3D11ShaderResourceView* views[1]{};
views[0] = perPass->srv.get();
context->PSSetShaderResources(71, ARRAYSIZE(views), views);
}

void WaterCaustics::SetupResources()
Expand All @@ -18,19 +44,39 @@ void WaterCaustics::SetupResources()
auto& context = State::GetSingleton()->context;

DirectX::CreateDDSTextureFromFile(device, context, L"Data\\Shaders\\WaterCaustics\\watercaustics.dds", nullptr, &causticsView);
D3D11_BUFFER_DESC sbDesc{};
sbDesc.Usage = D3D11_USAGE_DYNAMIC;
sbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
sbDesc.StructureByteStride = sizeof(PerPass);
sbDesc.ByteWidth = sizeof(PerPass);
perPass = std::make_unique<Buffer>(sbDesc);

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = 1;
perPass->CreateSRV(srvDesc);
}

void WaterCaustics::Load(json& o_json)
{
if (o_json[GetName()].is_object())
settings = o_json[GetName()];

Feature::Load(o_json);
}

void WaterCaustics::Save(json&)
void WaterCaustics::Save(json& o_json)
{
o_json[GetName()] = settings;
}

void WaterCaustics::RestoreDefaultSettings()
{
settings = {};
}

bool WaterCaustics::HasShaderDefine(RE::BSShader::Type)
Expand Down
14 changes: 14 additions & 0 deletions src/Features/WaterCaustics.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ struct WaterCaustics : Feature
return &singleton;
}

struct Settings
{
uint32_t EnableWaterCaustics = 1;
};

struct PerPass
{
Settings settings;
};

Settings settings;

std::unique_ptr<Buffer> perPass = nullptr;

ID3D11ShaderResourceView* causticsView;

virtual inline std::string GetName() { return "Water Caustics"; }
Expand Down
50 changes: 49 additions & 1 deletion src/Features/WaterParallax.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,76 @@
#include "WaterParallax.h"
#include "State.h"
#include "Util.h"

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
WaterParallax::Settings,
EnableWaterParallax)

void WaterParallax::DrawSettings()
{
if (ImGui::TreeNodeEx("Water Parallax", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Checkbox("Enable Water Parallax", (bool*)&settings.EnableWaterParallax);
if (auto _tt = Util::HoverTooltipWrapper()) {
ImGui::Text(
"Enables water parallax. "
"Parallax adds depth to the water surface to simulate greater detail.");
}

ImGui::TreePop();
}
}

void WaterParallax::Draw(const RE::BSShader*, const uint32_t)
{
auto& context = State::GetSingleton()->context;
PerPass data{};
data.settings = settings;

D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(perPass->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(PerPass);
memcpy_s(mapped.pData, bytes, &data, bytes);
context->Unmap(perPass->resource.get(), 0);

ID3D11ShaderResourceView* views[1]{};
views[0] = perPass->srv.get();
context->PSSetShaderResources(72, ARRAYSIZE(views), views);
}

void WaterParallax::SetupResources()
{
D3D11_BUFFER_DESC sbDesc{};
sbDesc.Usage = D3D11_USAGE_DYNAMIC;
sbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
sbDesc.StructureByteStride = sizeof(PerPass);
sbDesc.ByteWidth = sizeof(PerPass);
perPass = std::make_unique<Buffer>(sbDesc);

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = 1;
perPass->CreateSRV(srvDesc);
}

void WaterParallax::Load(json& o_json)
{
if (o_json[GetName()].is_object())
settings = o_json[GetName()];
Feature::Load(o_json);
}

void WaterParallax::Save(json&)
void WaterParallax::Save(json& o_json)
{
o_json[GetName()] = settings;
}

void WaterParallax::RestoreDefaultSettings()
{
settings = {};
}

bool WaterParallax::HasShaderDefine(RE::BSShader::Type)
Expand Down
16 changes: 15 additions & 1 deletion src/Features/WaterParallax.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#pragma once

#include "Buffer.h"
#include "Feature.h"

struct WaterParallax : Feature
Expand All @@ -11,6 +11,20 @@ struct WaterParallax : Feature
return &singleton;
}

struct Settings
{
uint32_t EnableWaterParallax = 1;
};

struct PerPass
{
Settings settings;
};

Settings settings;

std::unique_ptr<Buffer> perPass = nullptr;

virtual inline std::string GetName() { return "Water Parallax"; }
virtual inline std::string GetShortName() { return "WaterParallax"; }
inline std::string_view GetShaderDefineName() override { return "WATER_PARALLAX"; }
Expand Down

0 comments on commit 6fa104d

Please sign in to comment.