Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion features/Grass Lighting/Shaders/Features/GrassLighting.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[Info]
Version = 2-0-1
Version = 2-0-2

[Nexus]
nexusmodid = 86502
Expand Down
3 changes: 1 addition & 2 deletions package/Shaders/Common/SharedData.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ namespace SharedData
bool OverrideComplexGrassSettings;

float BasicGrassBrightness;
bool EnableWrappedLighting;
float ComplexGrassThreshold;
float1 pad0;
float2 pad0;
};

struct CPMSettings
Expand Down
7 changes: 7 additions & 0 deletions package/Shaders/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2871,6 +2871,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
}
# endif

# if defined(LANDSCAPE)
if (SharedData::lodBlendingSettings.DisableTerrainVertexColors)
input.Color.xyz = 1;
else
input.Color.xyz /= max(max(max(input.Color.x, input.Color.y), input.Color.z), EPSILON_DIVISION);
# endif

# if defined(HAIR)
float3 vertexColor = lerp(1, Color::ColorToLinear(TintColor.xyz), Color::ColorToLinear(input.Color.y));
# if defined(CS_HAIR)
Expand Down
60 changes: 32 additions & 28 deletions package/Shaders/RunGrass.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct VS_INPUT
struct VS_OUTPUT
{
float4 HPosition: SV_POSITION0;
float4 VertexColor: COLOR0;
float4 Color: COLOR0;
float VertexMult: COLOR1;
float3 TexCoord: TEXCOORD0;
float3 ViewSpacePosition:
Expand Down Expand Up @@ -65,7 +65,7 @@ struct VS_OUTPUT
struct VS_OUTPUT
{
float4 HPosition: SV_POSITION0;
float4 VertexColor: COLOR0;
float4 Color: COLOR0;
float VertexMult: COLOR1;
float3 TexCoord: TEXCOORD0;
float4 AmbientColor: TEXCOORD1;
Expand Down Expand Up @@ -228,8 +228,8 @@ VS_OUTPUT main(VS_INPUT input)
# endif

// Note: input.Color.w is used for wind speed
vsout.VertexColor.xyz = input.Color.xyz;
vsout.VertexColor.w = distanceFade * perInstanceFade;
vsout.Color.xyz = input.Color.xyz;
vsout.Color.w = distanceFade * perInstanceFade;
vsout.VertexMult = input.InstanceData1.w;

vsout.TexCoord.xy = input.TexCoord.xy;
Expand Down Expand Up @@ -305,8 +305,8 @@ VS_OUTPUT main(VS_INPUT input)
float distanceFade = 1 - saturate((length(projSpacePosition.xyz) - AlphaParam1) / AlphaParam2);
# endif

vsout.VertexColor.xyz = input.Color.xyz;
vsout.VertexColor.w = distanceFade * perInstanceFade;
vsout.Color.xyz = input.Color.xyz;
vsout.Color.w = distanceFade * perInstanceFade;
vsout.VertexMult = input.InstanceData1.w;

vsout.TexCoord.xy = input.TexCoord.xy;
Expand Down Expand Up @@ -466,6 +466,15 @@ cbuffer PerMaterial : register(b1)

# include "GrassLighting/GrassLighting.hlsli"

float GetSoftLightMultiplier(float angle, float rolloff)
{
float softLight = saturate((rolloff + angle) / (1 + rolloff));
float arg1 = (softLight * softLight) * (3 - 2 * softLight);
float clampedAngle = saturate(angle);
float arg2 = (clampedAngle * clampedAngle) * (3 - 2 * clampedAngle);
return saturate(arg1 - arg2);
}

PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
{
PS_OUTPUT psout = (PS_OUTPUT)0;
Expand Down Expand Up @@ -493,7 +502,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
baseColor.xyz = Color::Diffuse(baseColor.xyz);

# if defined(RENDER_DEPTH)
float diffuseAlpha = input.VertexColor.w * baseColor.w;
float diffuseAlpha = input.Color.w * baseColor.w;
if ((diffuseAlpha - AlphaTestRefRS) < 0) {
discard;
}
Expand All @@ -504,6 +513,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
psout.PS.xyz = input.Depth.xxx / input.Depth.yyy;
psout.PS.w = diffuseAlpha;
# else
if (SharedData::lodBlendingSettings.DisableTerrainVertexColors)
input.Color.xyz = 1;

# if !defined(TRUE_PBR)
float4 specColor = complex ? TexBaseSampler.SampleBias(SampBaseSampler, float2(input.TexCoord.x, 0.5 + input.TexCoord.y * 0.5), SharedData::MipBias) : 1;
# else
Expand Down Expand Up @@ -616,18 +628,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
# else
dirLightColor *= dirLightColorMultiplier;

float wrapAmount = saturate(input.VertexNormal.w * 10.0) * 0.5 * (!complex);
float softLightRolloff = saturate(input.VertexNormal.w * 10.0) * SharedData::grassLightingSettings.SubsurfaceScatteringAmount * 2.0;

if (SharedData::grassLightingSettings.EnableWrappedLighting) {
// Old Wrapped Model
float wrappedDirLight = saturate(dirLightAngle + wrapAmount) / (1.0 + wrapAmount);
lightsDiffuseColor += dirLightColor * dirDetailedShadow * saturate(wrappedDirLight) * Color::VanillaNormalization();
} else {
// Original Standard Model
lightsDiffuseColor += dirLightColor * dirDetailedShadow * saturate(dirLightAngle) * Color::VanillaNormalization();
}
lightsDiffuseColor += dirLightColor * dirDetailedShadow * saturate(dirLightAngle) * Color::VanillaNormalization();

float3 vertexColor = Color::ColorToLinear(input.VertexColor.xyz);
float3 vertexColor = Color::ColorToLinear(input.Color.xyz);
vertexColor /= max(max(max(vertexColor.r, vertexColor.g), vertexColor.b), EPSILON_DIVISION);

# if defined(SKYLIGHTING)
# if defined(VR)
Expand All @@ -641,7 +647,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)

float3 albedo = baseColor.xyz * vertexColor;

float3 subsurfaceColor = dirLightColor * dirDetailedShadow * saturate(-dirLightAngle) * Color::VanillaNormalization();
float3 subsurfaceColor = dirLightColor * dirDetailedShadow * (GetSoftLightMultiplier(dirLightAngle, softLightRolloff)) * Color::VanillaNormalization();

if (complex)
lightsSpecularColor += dirDetailedShadow * GrassLighting::GetLightSpecularInput(SharedData::DirLightDirection.xyz, viewDirection, normal, dirLightColor, SharedData::grassLightingSettings.Glossiness) * Color::VanillaNormalization();
Expand Down Expand Up @@ -703,14 +709,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
float lightNoL = dot(normalizedLightDirection.xyz, viewDirection);
float3 lightDiffuseColor;

if (SharedData::grassLightingSettings.EnableWrappedLighting) {
float wrappedLight = saturate(lightAngle + wrapAmount) / (1.0 + wrapAmount);
lightDiffuseColor = lightColor * wrappedLight;
} else {
lightDiffuseColor = lightColor * saturate(lightAngle);
}
lightDiffuseColor = lightColor * saturate(lightAngle);

subsurfaceColor += lightColor * saturate(-lightAngle) * Color::VanillaNormalization();
subsurfaceColor += lightColor * GetSoftLightMultiplier(lightAngle, softLightRolloff) * Color::VanillaNormalization();

lightsDiffuseColor += lightDiffuseColor * Color::VanillaNormalization();

Expand Down Expand Up @@ -747,7 +748,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
# endif

diffuseColor += directionalAmbientColor;
diffuseColor += subsurfaceColor * albedo * SharedData::grassLightingSettings.SubsurfaceScatteringAmount;
diffuseColor += subsurfaceColor * albedo;
diffuseColor *= albedo;
Comment thread
doodlum marked this conversation as resolved.

directionalAmbientColor *= albedo;
Expand Down Expand Up @@ -805,7 +806,7 @@ PS_OUTPUT main(PS_INPUT input)
float4 baseColor = TexBaseSampler.SampleBias(SampBaseSampler, input.TexCoord.xy, SharedData::MipBias);

# if defined(RENDER_DEPTH)
float diffuseAlpha = input.VertexColor.w * baseColor.w;
float diffuseAlpha = input.Color.w * baseColor.w;
if ((diffuseAlpha - AlphaTestRefRS) < 0) {
discard;
}
Expand All @@ -816,6 +817,8 @@ PS_OUTPUT main(PS_INPUT input)
psout.PS.xyz = input.Depth.xxx / input.Depth.yyy;
psout.PS.w = diffuseAlpha;
# else
if (SharedData::lodBlendingSettings.DisableTerrainVertexColors)
input.Color.xyz = 1;

uint eyeIndex = Stereo::GetEyeIndexPS(input.HPosition, VPOSOffset);

Expand Down Expand Up @@ -896,7 +899,8 @@ PS_OUTPUT main(PS_INPUT input)
float3 ddy = ddy_coarse(input.WorldPosition);
float3 normal = -normalize(cross(ddx, ddy));

float3 vertexColor = Color::ColorToLinear(input.VertexColor.xyz);
float3 vertexColor = Color::ColorToLinear(input.Color.xyz);
vertexColor /= max(max(max(vertexColor.r, vertexColor.g), vertexColor.b), EPSILON_DIVISION);

# if defined(SKYLIGHTING)
# if defined(VR)
Expand Down
61 changes: 35 additions & 26 deletions src/Features/GrassCollision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ void GrassCollision::DrawSettings()
}
}

void GrassCollision::UpdateCollisions(PerFrame& perFrameData)
void GrassCollision::QueueCollisions()
{
if (!settings.EnableGrassCollision)
return;

eastl::vector<GrassCollisionActorCandidate> actorCandidates{};
RE::NiPoint3 cameraPosition = Util::GetEyePosition(0);

Expand Down Expand Up @@ -83,7 +86,6 @@ void GrassCollision::UpdateCollisions(PerFrame& perFrameData)
RE::NiPoint3 centerPos;
float radius;
if (Util::GetShapeBound(a_object, centerPos, radius)) {
// Cull extremely small collisions
if (radius < distance * MIN_COLLISION_RADIUS_DISTANCE_SCALE)
return RE::BSVisit::BSVisitControl::kContinue;

Expand Down Expand Up @@ -140,25 +142,8 @@ void GrassCollision::UpdateCollisions(PerFrame& perFrameData)
}
}

perFrameData.BoundingBoxCount = std::min((uint)boundingBoxData.size(), MAX_BOUNDING_BOXES);

auto context = globals::d3d::context;

if (collisionIndexExtent > 0) {
D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(collisionInstances->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(float4) * collisionIndexExtent;
memcpy_s(mapped.pData, bytes, collisionsData.data(), bytes);
context->Unmap(collisionInstances->resource.get(), 0);
}

if (perFrameData.BoundingBoxCount > 0) {
D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(collisionBoundingBoxes->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(BoundingBoxPacked) * perFrameData.BoundingBoxCount;
memcpy_s(mapped.pData, bytes, boundingBoxData.data(), bytes);
context->Unmap(collisionBoundingBoxes->resource.get(), 0);
}
queuedBoundingBoxes = std::move(boundingBoxData);
queuedCollisions = std::move(collisionsData);
}

void GrassCollision::Update()
Expand Down Expand Up @@ -201,8 +186,28 @@ void GrassCollision::Update()

perFrameData.CameraHeightDelta = prevEyePosNI.z - eyePosNI.z;

if (settings.EnableGrassCollision)
UpdateCollisions(perFrameData);
perFrameData.BoundingBoxCount = std::min((uint)queuedBoundingBoxes.size(), MAX_BOUNDING_BOXES);

auto context = globals::d3d::context;

if (!queuedCollisions.empty()) {
D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(collisionInstances->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(float4) * queuedCollisions.size();
memcpy_s(mapped.pData, bytes, queuedCollisions.data(), bytes);
context->Unmap(collisionInstances->resource.get(), 0);
}

if (perFrameData.BoundingBoxCount > 0) {
D3D11_MAPPED_SUBRESOURCE mapped;
DX::ThrowIfFailed(context->Map(collisionBoundingBoxes->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped));
size_t bytes = sizeof(BoundingBoxPacked) * perFrameData.BoundingBoxCount;
memcpy_s(mapped.pData, bytes, queuedBoundingBoxes.data(), bytes);
context->Unmap(collisionBoundingBoxes->resource.get(), 0);
}

queuedBoundingBoxes.clear();
queuedCollisions.clear();

perFrame->Update(perFrameData);

Expand All @@ -211,8 +216,6 @@ void GrassCollision::Update()
prevCellID = cellID;
prevEyePosNI = eyePosNI;

auto context = globals::d3d::context;

ID3D11Buffer* buffers[1];
buffers[0] = perFrame->CB();
context->VSSetConstantBuffers(5, ARRAYSIZE(buffers), buffers);
Expand Down Expand Up @@ -252,7 +255,7 @@ void GrassCollision::SetupResources()
.Height = 512,
.MipLevels = 1,
.ArraySize = 1,
.Format = DXGI_FORMAT_R16G16B16A16_UNORM,
.Format = DXGI_FORMAT_R16G16B16A16_FLOAT,
.SampleDesc = { .Count = 1 },
.Usage = D3D11_USAGE_DEFAULT,
.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS
Expand Down Expand Up @@ -324,6 +327,12 @@ bool GrassCollision::HasShaderDefine(RE::BSShader::Type shaderType)
}
}

void GrassCollision::Hooks::MainUpdate_QueueCollisions::thunk()
{
func();
globals::features::grassCollision.QueueCollisions();
}

void GrassCollision::Hooks::BSGrassShader_SetupGeometry::thunk(RE::BSShader* This, RE::BSRenderPass* Pass, uint32_t RenderFlags)
{
globals::features::grassCollision.Update();
Expand Down
12 changes: 11 additions & 1 deletion src/Features/GrassCollision.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ struct GrassCollision : Feature
eastl::unique_ptr<Buffer> collisionBoundingBoxes = nullptr;
eastl::unique_ptr<Buffer> collisionInstances = nullptr;

eastl::vector<BoundingBoxPacked> queuedBoundingBoxes;
eastl::vector<float4> queuedCollisions;

virtual void ClearShaderCache() override;

ID3D11ComputeShader* GetCollisionUpdateCS();
Expand All @@ -78,7 +81,7 @@ struct GrassCollision : Feature
virtual void SetupResources() override;

virtual void DrawSettings() override;
void UpdateCollisions(PerFrame& perFrame);
void QueueCollisions();
void Update();

virtual void LoadSettings(json& o_json) override;
Expand All @@ -98,9 +101,16 @@ struct GrassCollision : Feature
static inline REL::Relocation<decltype(thunk)> func;
};

struct MainUpdate_QueueCollisions
{
static void thunk();
static inline REL::Relocation<decltype(thunk)> func;
};

static void Install()
{
stl::write_vfunc<0x6, BSGrassShader_SetupGeometry>(RE::VTABLE_BSGrassShader[0]);
stl::write_thunk_call<MainUpdate_QueueCollisions>(REL::RelocationID(35565, 36564).address() + REL::Relocate(0x748, 0xC26, 0x7EE));
logger::info("[GRASS COLLISION] Installed hooks");
}
};
Expand Down
7 changes: 0 additions & 7 deletions src/Features/GrassLighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
SubsurfaceScatteringAmount,
OverrideComplexGrassSettings,
BasicGrassBrightness,
EnableWrappedLighting,
ComplexGrassThreshold)

void GrassLighting::DrawSettings()
Expand Down Expand Up @@ -53,12 +52,6 @@ void GrassLighting::DrawSettings()
}

if (ImGui::TreeNodeEx("Lighting", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Checkbox("Enable Wrapped Lighting", (bool*)&settings.EnableWrappedLighting);
if (auto _tt = Util::HoverTooltipWrapper()) {
ImGui::Text("Enables a softer-looking wrapped lighting model from CS 1.3. Useful for certain non-complex grass textures that look too dark during mid day, when the sun is directly overhead.");
}
ImGui::Spacing();
ImGui::Spacing();
ImGui::Checkbox("Override Complex Grass Lighting Settings", (bool*)&settings.OverrideComplexGrassSettings);
if (auto _tt = Util::HoverTooltipWrapper()) {
ImGui::Text(
Expand Down
7 changes: 3 additions & 4 deletions src/Features/GrassLighting.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,11 @@ struct GrassLighting : Feature
{
float Glossiness = 20.0f;
float SpecularStrength = 0.5f;
float SubsurfaceScatteringAmount = 0.5f;
float SubsurfaceScatteringAmount = 1.0f;
uint OverrideComplexGrassSettings = false;
float BasicGrassBrightness = 1.0f; // Match brightness of ENB
uint EnableWrappedLighting = false;
float BasicGrassBrightness = 1.0f;
float ComplexGrassThreshold = 0.03f;
uint pad1;
float2 pad0;
};
STATIC_ASSERT_ALIGNAS_16(Settings);

Expand Down
Loading