From b9afb844286f01d5ce96156393a1cc84b1eb0a0c Mon Sep 17 00:00:00 2001 From: pr0bability Date: Fri, 6 Jun 2025 05:27:27 +0200 Subject: [PATCH 1/8] Update terrain shaders for Vanilla Plus Terrain compatibility --- src/core/RenderManager.cpp | 4 - src/core/ShaderManager.cpp | 2 +- src/core/ShaderRecord.cpp | 6 +- src/effects/Terrain.h | 32 +++- .../NewVegas/Shaders/Includes/Parallax.hlsl | 41 +++-- .../NewVegas/Shaders/Includes/Terrain.hlsl | 74 +++++---- src/hlsl/NewVegas/Shaders/SLS2002.vso.hlsl | 85 ----------- src/hlsl/NewVegas/Shaders/SLS2003.pso.hlsl | 87 ----------- src/hlsl/NewVegas/Shaders/SLS2080.vso.hlsl | 82 ---------- src/hlsl/NewVegas/Shaders/SLS2082.pso.hlsl | 73 --------- .../NewVegas/Shaders/TerrainFadeTemplate.hlsl | 129 ++++++++++++++++ .../NewVegas/Shaders/TerrainLODTemplate.hlsl | 140 ++++++++++++++++++ .../NewVegas/Shaders/TerrainTemplate.hlsl | 99 ++++++++----- 13 files changed, 425 insertions(+), 429 deletions(-) delete mode 100644 src/hlsl/NewVegas/Shaders/SLS2002.vso.hlsl delete mode 100644 src/hlsl/NewVegas/Shaders/SLS2003.pso.hlsl delete mode 100644 src/hlsl/NewVegas/Shaders/SLS2080.vso.hlsl delete mode 100644 src/hlsl/NewVegas/Shaders/SLS2082.pso.hlsl create mode 100644 src/hlsl/NewVegas/Shaders/TerrainFadeTemplate.hlsl create mode 100644 src/hlsl/NewVegas/Shaders/TerrainLODTemplate.hlsl diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index 758627f8b..a179c23bd 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -296,10 +296,6 @@ void RenderManager::Initialize() { Logger::Log("ERROR: Cannot initialize the render manager. Graphics device not supported."); if (TheSettingManager->SettingsMain.Main.AnisotropicFilter >= 2) device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, TheSettingManager->SettingsMain.Main.AnisotropicFilter); BackBuffer = CreateHDRRenderTarget(); - - ILS = GetModuleHandle(L"ImprovedLightingShaders.dll"); - if (ILS) - Logger::Log("ILS detected."); } void RenderManager::ResolveDepthBuffer(IDirect3DTexture9* Buffer) { diff --git a/src/core/ShaderManager.cpp b/src/core/ShaderManager.cpp index c2972f4d8..ddd41f304 100644 --- a/src/core/ShaderManager.cpp +++ b/src/core/ShaderManager.cpp @@ -423,10 +423,10 @@ ShaderCollection* ShaderManager::GetShaderCollection(const char* Name) { if (!memcmp(Name, "PAR", 3)) return Shaders.POM; //if (!memcmp(Name, "SKIN", 4)) return Shaders.Skin; // temporarily disabled, the shaders are half broken if (!memcmp(Name, "SKY", 3)) return Shaders.Sky; - if (strstr(TerrainShadersNames, Name)) return Shaders.Terrain; if (strstr(BloodShaders, Name)) return Shaders.Blood; if (Shaders.PBR->GetTemplate(Name).Name != NULL) return Shaders.PBR; + if (Shaders.Terrain->GetTemplate(Name).Name != NULL) return Shaders.Terrain; return NULL; } diff --git a/src/core/ShaderRecord.cpp b/src/core/ShaderRecord.cpp index 510de2599..aa6e2a4c2 100644 --- a/src/core/ShaderRecord.cpp +++ b/src/core/ShaderRecord.cpp @@ -132,17 +132,13 @@ ShaderRecord* ShaderRecord::LoadShader(const char* Name, const char* SubPath, Sh strcat(ShaderCompiledPath, Name); D3DXMACRO* Macros = &(Template.Defines[0]); - if (TheRenderManager->ILS || TheRenderManager->IsReversedDepth()) { + if (TheRenderManager->IsReversedDepth()) { int i = 0; bool nullFound = false; while (!nullFound && i < 28) { nullFound = Template.Defines[i].Name == NULL; if (!nullFound) i++; } - if (TheRenderManager->ILS) { - Template.Defines[i] = { "ILS", "" }; - i++; - } if (TheRenderManager->IsReversedDepth()) { Template.Defines[i] = { "REVERSED_DEPTH", "" }; i++; diff --git a/src/effects/Terrain.h b/src/effects/Terrain.h index 6ab496d59..d33d47e2a 100644 --- a/src/effects/Terrain.h +++ b/src/effects/Terrain.h @@ -9,19 +9,37 @@ class TerrainShaders : public ShaderCollection return std::map{ { "SLS2100.vso", ShaderTemplate{ "TerrainTemplate", {{"VS", ""}} } }, { "SLS2092.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "1"}}} }, - { "SLS2096.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "1"}, {"POINTLIGHT", ""}}} }, + { "SLS2094.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "1"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2096.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "1"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2098.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "1"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2100.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "2"}}} }, - { "SLS2104.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "2"}, {"POINTLIGHT", ""}}} }, + { "SLS2102.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "2"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2104.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "2"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2106.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "2"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2108.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "3"}}} }, - { "SLS2112.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "3"}, {"POINTLIGHT", ""}}} }, + { "SLS2110.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "3"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2112.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "3"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2114.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "3"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2116.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "4"}}} }, - { "SLS2120.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "4"}, {"POINTLIGHT", ""}}} }, + { "SLS2118.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "4"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2120.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "4"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2122.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "4"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2124.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "5"}}} }, - { "SLS2128.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "5"}, {"POINTLIGHT", ""}}} }, + { "SLS2126.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "5"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2128.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "5"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2130.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "5"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2132.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "6"}}} }, - { "SLS2136.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "6"}, {"POINTLIGHT", ""}}} }, + { "SLS2134.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "6"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2136.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "6"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2138.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "6"}, {"NUM_PT_LIGHTS", "24"}}} }, { "SLS2140.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "7"}}} }, - { "SLS2144.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "7"}, {"POINTLIGHT", ""}}} } + { "SLS2142.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "7"}, {"NUM_PT_LIGHTS", "6"}}} }, + { "SLS2144.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "7"}, {"NUM_PT_LIGHTS", "12"}}} }, + { "SLS2146.pso", ShaderTemplate{"TerrainTemplate", {{"PS", ""}, {"TEX_COUNT", "7"}, {"NUM_PT_LIGHTS", "24"}}} }, + { "SLS2002.vso", ShaderTemplate{"TerrainLODTemplate", {{"VS", ""}}} }, + { "SLS2003.pso", ShaderTemplate{"TerrainLODTemplate", {{"PS", ""}}} }, + { "SLS2080.vso", ShaderTemplate{"TerrainFadeTemplate", {{"VS", ""}}} }, + { "SLS2082.pso", ShaderTemplate{"TerrainFadeTemplate", {{"PS", ""}}} }, }; }; diff --git a/src/hlsl/NewVegas/Shaders/Includes/Parallax.hlsl b/src/hlsl/NewVegas/Shaders/Includes/Parallax.hlsl index 974743808..c03a1fbe3 100644 --- a/src/hlsl/NewVegas/Shaders/Includes/Parallax.hlsl +++ b/src/hlsl/NewVegas/Shaders/Includes/Parallax.hlsl @@ -1,6 +1,6 @@ #ifdef TERRAIN -float4 TESR_TerrainParallaxData : register(c35); -float4 TESR_TerrainParallaxExtraData : register(c36); +float4 TESR_TerrainParallaxData : register(c91); +float4 TESR_TerrainParallaxExtraData : register(c92); #else float4 TESR_ParallaxData : register(c35); #endif @@ -8,7 +8,7 @@ float4 TESR_ParallaxData : register(c35); #ifdef TERRAIN // Complex Parallax Materials for Community Shaders // https://www.artstation.com/blogs/andreariccardi/3VPo/a-new-approach-for-parallax-mapping-presenting-the-contact-refinement-parallax-mapping-technique -float getTerrainHeight(float2 coords, float2 dx, float2 dy, float blendFactor, int texCount, sampler2D tex[7], float blends[7], out float weights[7]) { +float getTerrainHeight(float2 coords, float2 dx, float2 dy, float blendFactor, int texCount, sampler2D tex[7], float blends[7], float status[7], out float weights[7]) { weights = blends; float blendPower = blendFactor * 4; @@ -16,7 +16,7 @@ float getTerrainHeight(float2 coords, float2 dx, float2 dy, float blendFactor, i [unroll] for (int i = 0; i < texCount; i++){ weights[i] = pow(abs(blends[i]), 1 + 1 * blendFactor); if (weights[i] > 0.0) { - weights[i] *= 0.001 + pow(abs(tex2Dgrad(tex[i], coords, dx, dy).a), blendPower); + weights[i] *= 0.001 + pow(abs(status[i] ? tex2Dgrad(tex[i], coords, dx, dy).a : 0.5f), blendPower); } total += weights[i]; } @@ -33,7 +33,18 @@ float getTerrainHeight(float2 coords, float2 dx, float2 dy, float blendFactor, i #endif #ifdef TERRAIN -float2 getParallaxCoords(float distance, float2 coords, float2 dx, float2 dy, float3 viewDirTS, int texCount, sampler2D tex[7], float blends[7], out float weights[7]) { +float2 getParallaxCoords( + float distance, + float2 coords, + float2 dx, + float2 dy, + float3 viewDirTS, + int texCount, + sampler2D tex[7], + float blends[7], + float status[7], + out float weights[7] +) { #else float2 getParallaxCoords(float distance, float2 coords, float2 dx, float2 dy, float3 viewDirTS, sampler2D heightMap) { #endif @@ -107,10 +118,10 @@ float2 getParallaxCoords(float distance, float2 coords, float2 dx, float2 dy, fl float4 currHeight; #ifdef TERRAIN - currHeight.x = getTerrainHeight(currentOffset[0].xy, dx, dy, blendFactor, texCount, tex, blends, weights); - currHeight.y = getTerrainHeight(currentOffset[0].zw, dx, dy, blendFactor, texCount, tex, blends, weights); - currHeight.z = getTerrainHeight(currentOffset[1].xy, dx, dy, blendFactor, texCount, tex, blends, weights); - currHeight.w = getTerrainHeight(currentOffset[1].zw, dx, dy, blendFactor, texCount, tex, blends, weights); + currHeight.x = getTerrainHeight(currentOffset[0].xy, dx, dy, blendFactor, texCount, tex, blends, status, weights); + currHeight.y = getTerrainHeight(currentOffset[0].zw, dx, dy, blendFactor, texCount, tex, blends, status, weights); + currHeight.z = getTerrainHeight(currentOffset[1].xy, dx, dy, blendFactor, texCount, tex, blends, status, weights); + currHeight.w = getTerrainHeight(currentOffset[1].zw, dx, dy, blendFactor, texCount, tex, blends, status, weights); #else currHeight.x = tex2Dgrad(heightMap, currentOffset[0].xy, dx, dy).r; currHeight.y = tex2Dgrad(heightMap, currentOffset[0].zw, dx, dy).r; @@ -179,7 +190,7 @@ float2 getParallaxCoords(float distance, float2 coords, float2 dx, float2 dy, fl } #ifdef TERRAIN -float getParallaxShadowMultipler(float distance, float2 coords, float2 dx, float2 dy, float3 lightTS, int texCount, float blends[7], sampler2D tex[7]) { +float getParallaxShadowMultipler(float distance, float2 coords, float2 dx, float2 dy, float3 lightTS, int texCount, float blends[7], float status[7], sampler2D tex[7]) { if (!TESR_TerrainParallaxData.y) return 1.0; @@ -191,18 +202,18 @@ float getParallaxShadowMultipler(float distance, float2 coords, float2 dx, float if (quality > 0.0) { float weights[7] = { 0, 0, 0, 0, 0, 0, 0 }; - float sh0 = getTerrainHeight(coords, dx, dy, quality, texCount, tex, blends, weights); + float sh0 = getTerrainHeight(coords, dx, dy, quality, texCount, tex, blends, status, weights); const float2 rayDir = lightTS.xy * 0.1; float4 multipliers = rcp((float4(1, 2, 3, 4))); - float4 sh = getTerrainHeight(coords + rayDir * multipliers.x, dx, dy, quality, texCount, tex, blends, weights); + float4 sh = getTerrainHeight(coords + rayDir * multipliers.x, dx, dy, quality, texCount, tex, blends, status, weights); if (quality > 0.25) - sh.y = getTerrainHeight(coords + rayDir * multipliers.y, dx, dy, quality, texCount, tex, blends, weights); + sh.y = getTerrainHeight(coords + rayDir * multipliers.y, dx, dy, quality, texCount, tex, blends, status, weights); if (quality > 0.5) - sh.z = getTerrainHeight(coords + rayDir * multipliers.z, dx, dy, quality, texCount, tex, blends, weights); + sh.z = getTerrainHeight(coords + rayDir * multipliers.z, dx, dy, quality, texCount, tex, blends, status, weights); if (quality > 0.75) - sh.w = getTerrainHeight(coords + rayDir * multipliers.w, dx, dy, quality, texCount, tex, blends, weights); + sh.w = getTerrainHeight(coords + rayDir * multipliers.w, dx, dy, quality, texCount, tex, blends, status, weights); return 1.0 - saturate(dot(max(0, sh - sh0), 1.0) * shadowsIntensity) * quality; } diff --git a/src/hlsl/NewVegas/Shaders/Includes/Terrain.hlsl b/src/hlsl/NewVegas/Shaders/Includes/Terrain.hlsl index 5830de37b..2ca2e4f15 100644 --- a/src/hlsl/NewVegas/Shaders/Includes/Terrain.hlsl +++ b/src/hlsl/NewVegas/Shaders/Includes/Terrain.hlsl @@ -7,72 +7,86 @@ #include "includes/PBR.hlsl" #endif -float4 TESR_TerrainData : register(c32); -float4 TESR_TerrainExtraData : register(c33); +float4 TESR_TerrainData : register(c89); +float4 TESR_TerrainExtraData : register(c90); float3 blendDiffuseMaps(float3 vertexColor, float2 uv, int texCount, sampler2D tex[7], float blends[7]) { - float3 color = tex2D(tex[0], uv).xyz * blends[0]; - - [unroll] for (int i = 1; i < texCount; i++) { + float3 color = float3(0, 0, 0); + [unroll] for (int i = 0; i < texCount; i++) { color += tex2D(tex[i], uv).xyz * blends[i]; } return color * vertexColor; } -float3 blendNormalMaps(float2 uv, int texCount, sampler2D tex[7], float blends[7], out float roughness) { - roughness = 1.f; - - float4 normal = tex2D(tex[0], uv); - float3 combinedNormal = normal.xyz * blends[0]; - roughness = normal.w * blends[0]; - - [unroll] for (int i = 1; i < texCount; i++){ +float3 blendNormalMaps(float2 uv, int texCount, sampler2D tex[7], float blends[7], float spec[7], out float gloss, out float specExponent) { + gloss = 0.0f; + specExponent = 0.0f; + + float3 blendedNormal = float3(0, 0, 0); + + float4 normal; + [unroll] for (int i = 0; i < texCount; i++) { normal = tex2D(tex[i], uv); - combinedNormal += normal.xyz * blends[i]; - roughness += normal.w * blends[i]; + blendedNormal += normal.xyz * blends[i]; + gloss += normal.w * blends[i] * (spec[i] > 0 ? 1.0f : 0.0f); + specExponent += spec[i] * blends[i]; } - roughness = saturate((1 - roughness) * TESR_TerrainData.y); - return normalize(expand(combinedNormal)); + gloss = saturate(gloss); + return normalize(expand(blendedNormal)); } -float3 getPointLightLighting(float3 lightDir, float radius, float3 lightColor, float3 eyeDir, float3 normal, float3 albedo, float roughness = 1.0, float metallicness = 1.0) { +float3 getVanillaLightingAtt(float3 lightDir, float att, float3 lightColor, float3 viewDir, float3 normal, float3 albedo, float gloss, float glossPower) { + lightDir = normalize(lightDir); + viewDir = normalize(viewDir); + float3 halfwayDir = normalize(lightDir + viewDir); + + float NdotL = shades(normal.xyz, lightDir.xyz); + + float specStrength = gloss * pow(abs(shades(normal.xyz, halfwayDir.xyz)), glossPower); + float3 lighting = albedo.rgb * NdotL * lightColor.rgb * att; + lighting += saturate(((0.2 >= NdotL ? (specStrength * saturate(NdotL + 0.5)) : specStrength) * lightColor.rgb) * att); + + return lighting; +} + +float3 getPointLightLighting(float3 lightDir, float att, float3 lightColor, float3 eyeDir, float3 normal, float3 albedo, float gloss = 0.0, float glossPower = 0.0, float metallicness = 1.0) { float3 pointlightColor = lightColor * TESR_TerrainData.z; + [branch] if (TESR_TerrainExtraData.x){ - // PBR. - float att = vanillaAtt(lightDir, radius); - + // PBR. + float roughness = saturate((1 - gloss) * TESR_TerrainData.y); float3 lighting = PBR(saturate(metallicness * TESR_TerrainData.x), roughness, albedo, normal, eyeDir, lightDir, pointlightColor); return max(0, lighting * att); } else { - // Vanilla. - float att = vanillaAtt(lightDir, radius); - + // Vanilla. lightDir = normalize(lightDir); - float3 lighting = LambertianDiffuse(albedo, (0).xxx) * shades(normal, lightDir) * pointlightColor * PI; + float3 lighting = getVanillaLightingAtt(lightDir, att, lightColor, eyeDir, normal, albedo, gloss, glossPower); - return max(0, lighting * att); + return lighting; } } -float3 getSunLighting(float3 lightDir, float3 sunColor, float3 eyeDir, float3 normal, float3 AmbientColor, float3 albedo, float roughness = 1.0, float metallicness = 1.0, float parallaxMultiplier = 1.0) { +float3 getSunLighting(float3 lightDir, float3 sunColor, float3 eyeDir, float3 normal, float3 AmbientColor, float3 albedo, float gloss = 0.0, float glossPower = 0.0, float metallicness = 1.0, float parallaxMultiplier = 1.0) { float3 lightColor = sunColor * TESR_TerrainData.z * parallaxMultiplier; float3 ambientColor = AmbientColor * TESR_TerrainData.w; float3 color = albedo; color = lerp(luma(albedo), color, TESR_TerrainExtraData.y); + [branch] if (TESR_TerrainExtraData.x) { // PBR. - float3 lighting = PBRSun(saturate(TESR_TerrainData.x), roughness, color, normal, eyeDir, lightDir, lightColor); + float roughness = saturate((1 - gloss) * TESR_TerrainData.y); + float3 lighting = PBRSun(saturate(metallicness * TESR_TerrainData.x), roughness, color, normal, eyeDir, lightDir, lightColor); return max(0, lighting + ambientColor * color); } else { // Vanilla, no specular. - float3 lighting = LambertianDiffuse(color, (0).xxx) * shades(normal, lightDir) * lightColor * PI; + float3 lighting = getVanillaLightingAtt(lightDir, 1.0, sunColor, eyeDir, normal, albedo, gloss, glossPower); - return max(0, lighting + ambientColor * color); + return lighting + ambientColor * color; } } diff --git a/src/hlsl/NewVegas/Shaders/SLS2002.vso.hlsl b/src/hlsl/NewVegas/Shaders/SLS2002.vso.hlsl deleted file mode 100644 index 7144d4136..000000000 --- a/src/hlsl/NewVegas/Shaders/SLS2002.vso.hlsl +++ /dev/null @@ -1,85 +0,0 @@ -// LOD terrain vertex shader -// -// Parameters: - -row_major float4x4 ModelViewProj : register(c0); -row_major float4x4 ObjToCubeSpace : register(c8); -float4 HighDetailRange : register(c12); -float4 FogParam : register(c14); -float3 FogColor : register(c15); -float4 EyePosition : register(c16); -float4 GeomorphParams : register(c19); -float4 LightData[10] : register(c25); - -// Registers: -// -// Name Reg Size -// --------------- ----- ---- -// ModelViewProj[0] const_0 1 -// ModelViewProj[1] const_1 1 -// ModelViewProj[2] const_2 1 -// ModelViewProj[3] const_3 1 -// ObjToCubeSpace[0] const_8 1 -// ObjToCubeSpace[1] const_9 1 -// HighDetailRange const_12 1 -// FogParam const_14 1 -// FogColor const_15 1 -// GeomorphParams const_19 1 -// LightData[0] const_25 1 -// - - -// Structures: - -struct VS_INPUT { - float4 position : POSITION; - float4 texcoord_0 : TEXCOORD0; - float4 texcoord_1 : TEXCOORD1; -}; - -struct VS_OUTPUT { - float4 color_1 : COLOR1; - float4 position : POSITION; - float2 texcoord_0 : TEXCOORD0; - float3 texcoord_1 : TEXCOORD1; - float3 lPosition : TEXCOORD2; - float3 eyePosition : TEXCOORD3; -}; - -// Code: - -VS_OUTPUT main(VS_INPUT IN) { - VS_OUTPUT OUT; - - float4 r0 = IN.position; - float4 r1 = IN.position; - r1.z = lerp(IN.texcoord_1.x, IN.position.z, GeomorphParams.x); - - float q0 = (abs(dot(ObjToCubeSpace[1].xyzw, r1.xyzw) - HighDetailRange.y) < HighDetailRange.w ? 1.0 : 0.0); - float q1 = (abs(dot(ObjToCubeSpace[0].xyzw, r1.xyzw) - HighDetailRange.x) < HighDetailRange.z ? 1.0 : 0.0); - - r0.z = r1.z - ((q0.x * q1.x) * GeomorphParams.y); - float3 mdl11 = mul(float3x4(ModelViewProj[0].xyzw, ModelViewProj[1].xyzw, ModelViewProj[2].xyzw), r0.xyzw); - - OUT.position.w = dot(ModelViewProj[3].xyzw, r0.xyzw); - OUT.position.xyz = mdl11.xyz; - OUT.texcoord_0.xy = IN.texcoord_0.xy; - OUT.texcoord_1 = LightData[0].xyz; // sun direction - - // Fog. - float3 fogPos = OUT.position.xyz; - #ifdef REVERSED_DEPTH - fogPos.z = OUT.position.w - fogPos.z; - #endif - float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); - fogStrength = log2(fogStrength); - OUT.color_1.a = exp2(fogStrength * FogParam.z); - OUT.color_1.rgb = FogColor.rgb; - - OUT.lPosition.xyz = r0.xyz; - OUT.eyePosition.xyz = EyePosition.xyz; - - return OUT; -}; - -// approximately 34 instruction slots used diff --git a/src/hlsl/NewVegas/Shaders/SLS2003.pso.hlsl b/src/hlsl/NewVegas/Shaders/SLS2003.pso.hlsl deleted file mode 100644 index fef7507c7..000000000 --- a/src/hlsl/NewVegas/Shaders/SLS2003.pso.hlsl +++ /dev/null @@ -1,87 +0,0 @@ -// Shader for LOD terrain -// -// Parameters: -sampler2D BaseMap : register(s0); -sampler2D NormalMap : register(s1); -sampler2D LODParentTex : register(s4); -sampler2D LODParentNormals : register(s6); -sampler2D LODLandNoise : register(s7); - -float4 AmbientColor : register(c1); -float4 PSLightColor[10] : register(c3); -float4 LODTexParams : register(c31); - -// float4 TESR_DebugVar; - - -// Registers: -// -// Name Reg Size -// ---------------- ----- ---- -// AmbientColor const_1 1 -// PSLightColor[0] const_3 1 -// LODTexParams const_31 1 -// BaseMap texture_0 1 -// NormalMap texture_1 1 -// LODParentTex texture_4 1 -// LODParentNormals texture_6 1 -// LODLandNoise texture_7 1 -// - - -// Structures: - -struct VS_INPUT { - float2 NormalUV : TEXCOORD0; - float4 color_1 : COLOR1; - float3 texcoord_1 : TEXCOORD1_centroid; - float3 lPosition : TEXCOORD2_centroid; - float3 eyePosition : TEXCOORD3_centroid; -}; - -struct VS_OUTPUT { - float4 color_0 : COLOR0; -}; - -#include "includes/Helpers.hlsl" -#include "includes/Terrain.hlsl" - -// Code: - -VS_OUTPUT main(VS_INPUT IN) { - VS_OUTPUT OUT; - - float3 r0 = LODTexParams.xyw; - - float4 normal = tex2D(NormalMap, IN.NormalUV); - float3 parentNormal = tex2D(LODParentNormals, (IN.NormalUV * 0.5) + r0.xy).xyz; - - float noise = tex2D(LODLandNoise, IN.NormalUV * TESR_TerrainExtraData.w).r; - - normal.xyz = r0.z >= 1 ? normal.xyz : lerp(parentNormal, normal.xyz, LODTexParams.w); - normal.xyz = expand(normal.xyz); - normal.xyz = normalize(normal.xyz); - - float2 uv = (IN.NormalUV * 0.9921875) + (1.0 / 256); - float3 blendColor = tex2D(LODParentTex, (0.5 * uv) + lerp(r0.xy, 0.25, (1.0 / 128))).rgb; - float3 baseColor = tex2D(BaseMap, uv).rgb; - float3 eyeDir = normalize(IN.eyePosition.xyz - IN.lPosition.xyz); - - // blending between parent tex and basemap + apply noise - baseColor = r0.z >= 1 ? baseColor : lerp(blendColor, baseColor, LODTexParams.w); - - float roughness = saturate(TESR_TerrainData.y * (1 - normal.a)); - - float3 lighting = getSunLighting(IN.texcoord_1.xyz, PSLightColor[0].rgb, eyeDir, normal.xyz, AmbientColor.rgb, baseColor.rgb, roughness); - - float3 final = lighting; - final = lerp(final, final * (0.8 * noise + 0.55), saturate(TESR_TerrainExtraData.z)); // Apply noise. - final = lerp(final, IN.color_1.rgb, IN.color_1.a); // Apply fog. - - OUT.color_0.rgb = final; - OUT.color_0.a = 1; - - return OUT; -}; - -// approximately 29 instruction slots used (5 texture, 24 arithmetic) diff --git a/src/hlsl/NewVegas/Shaders/SLS2080.vso.hlsl b/src/hlsl/NewVegas/Shaders/SLS2080.vso.hlsl deleted file mode 100644 index f65d4985e..000000000 --- a/src/hlsl/NewVegas/Shaders/SLS2080.vso.hlsl +++ /dev/null @@ -1,82 +0,0 @@ -// Vertex Shader for LOD terrain during transition with near terrain -// -// Parameters: - -row_major float4x4 ModelViewProj : register(c0); -float4 FogParam : register(c14); -float3 FogColor : register(c15); -float4 EyePosition : register(c16); -float4 LandBlendParams : register(c19); -float4 LightData[10] : register(c25); - - -// Registers: -// -// Name Reg Size -// --------------- ----- ---- -// ModelViewProj[0] const_0 1 -// ModelViewProj[1] const_1 1 -// ModelViewProj[2] const_2 1 -// ModelViewProj[3] const_3 1 -// FogParam const_14 1 -// FogColor const_15 1 -// LandBlendParams const_19 1 -// LightData[0] const_25 1 -// - - -// Structures: - -struct VS_INPUT { - float4 position : POSITION; - float4 texcoord_0 : TEXCOORD0; -}; - -struct VS_OUTPUT { - float4 position : POSITION; - float2 texcoord_0 : TEXCOORD0; - float3 texcoord_3 : TEXCOORD3; - float texcoord_4 : TEXCOORD4; - float4 texcoord_5 : TEXCOORD5; - float3 lPosition : TEXCOORD6; - float3 eyePosition : TEXCOORD7; -}; - - -#include "includes/Helpers.hlsl" -// Code: - -VS_OUTPUT main(VS_INPUT IN) { - VS_OUTPUT OUT; - - float4 r0; - - float3 mdl4 = mul(float3x4(ModelViewProj[0].xyzw, ModelViewProj[1].xyzw, ModelViewProj[2].xyzw), IN.position.xyzw); - - OUT.position.w = dot(ModelViewProj[3].xyzw, IN.position.xyzw); - OUT.position.xyz = mdl4.xyz; - - r0.xy = (IN.texcoord_0.xy * 0.015625) + LandBlendParams.xy; - r0.z = 1 - r0.x; - - OUT.texcoord_0.xy = (r0.zy * 0.9921875) + (1.0 / 256); - OUT.texcoord_3.xyz = LightData[0].xyz; - OUT.texcoord_4.x = 1 - saturate((9625.59961 - sqrt(r0.y + r0.x)) * 0.000375600968); - - // Fog. - float3 fogPos = OUT.position.xyz; - #ifdef REVERSED_DEPTH - fogPos.z = OUT.position.w - fogPos.z; - #endif - float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); - fogStrength = log2(fogStrength); - OUT.texcoord_5.a = exp2(fogStrength * FogParam.z); - OUT.texcoord_5.rgb = FogColor.rgb; - - OUT.lPosition.xyz = r0.xyz; - OUT.eyePosition.xyz = EyePosition.xyz; - - return OUT; -}; - -// approximately 33 instruction slots used diff --git a/src/hlsl/NewVegas/Shaders/SLS2082.pso.hlsl b/src/hlsl/NewVegas/Shaders/SLS2082.pso.hlsl deleted file mode 100644 index 919407e69..000000000 --- a/src/hlsl/NewVegas/Shaders/SLS2082.pso.hlsl +++ /dev/null @@ -1,73 +0,0 @@ -// Shader for LOD terrain during transition with near terrain -// -// Parameters: -sampler2D BaseMap : register(s0); -sampler2D NormalMap : register(s1); -sampler2D LODLandNoise : register(s2); - -float4 AmbientColor : register(c1); -float4 PSLightColor[10] : register(c3); -// float4 TESR_DebugVar; - - -// Registers: -// -// Name Reg Size -// ------------ ----- ---- -// AmbientColor const_1 1 -// PSLightColor[0] const_3 1 -// BaseMap texture_0 1 -// NormalMap texture_1 1 -// LODLandNoise texture_2 1 -// - - -// Structures: - -struct VS_INPUT { - - float2 BaseUV : TEXCOORD0; - float3 texcoord_3 : TEXCOORD3_centroid; - float texcoord_4 : TEXCOORD4_centroid; - float4 texcoord_5 : TEXCOORD5_centroid; - float3 lPosition : TEXCOORD6_centroid; - float3 eyePosition : TEXCOORD7_centroid; -}; - -struct VS_OUTPUT { - float4 color_0 : COLOR0; -}; - - -#include "includes/Helpers.hlsl" -#include "includes/Terrain.hlsl" -// Code: - -VS_OUTPUT main(VS_INPUT IN) { - VS_OUTPUT OUT; - - float3 eyeDir = normalize(IN.eyePosition.xyz - IN.lPosition.xyz); - - float noise = tex2D(LODLandNoise, IN.BaseUV.xy * TESR_TerrainExtraData.w).r; - noise = lerp(0, noise, IN.texcoord_4.x); - - float4 normal = tex2D(NormalMap, IN.BaseUV.xy); - normal.rgb = normalize(expand(normal.rgb)); - - float3 baseColor = tex2D(BaseMap, IN.BaseUV.xy).rgb; - - float roughness = saturate(TESR_TerrainData.y * (1 - normal.a)); - - float3 lighting = getSunLighting(IN.texcoord_3.xyz, PSLightColor[0].rgb, eyeDir, normal.rgb, AmbientColor.rgb, baseColor, roughness); - - float3 final = lighting; - final = lerp(final, final * (0.8 * noise + 0.55), saturate(TESR_TerrainExtraData.z)); // Apply noise. - final = lerp(final, IN.texcoord_5.rgb, IN.texcoord_5.a); // Apply fog. - - OUT.color_0.rgb = final; - OUT.color_0.a = IN.texcoord_4.x; - - return OUT; -}; - -// approximately 16 instruction slots used (3 texture, 13 arithmetic) diff --git a/src/hlsl/NewVegas/Shaders/TerrainFadeTemplate.hlsl b/src/hlsl/NewVegas/Shaders/TerrainFadeTemplate.hlsl new file mode 100644 index 000000000..04775ee7f --- /dev/null +++ b/src/hlsl/NewVegas/Shaders/TerrainFadeTemplate.hlsl @@ -0,0 +1,129 @@ +// Template for fade between terrain and LOD terrain. + +#if defined(__INTELLISENSE__) + #define PS +#endif + +#define REVERSED_DEPTH + +#include "includes/Helpers.hlsl" +#include "includes/Terrain.hlsl" + +struct VS_INPUT { + float4 position : POSITION; + float4 uv : TEXCOORD0; +}; + +struct VS_OUTPUT { + float4 position : POSITION; + float2 uv : TEXCOORD0; + float3 sunDirection : TEXCOORD3; + float blend : TEXCOORD4; + float4 fog : TEXCOORD5; + float3 lPosition : TEXCOORD6; + float3 eyePosition : TEXCOORD7; +}; + +#ifdef VS + +row_major float4x4 ModelViewProj : register(c0); + +float4 FogParam : register(c14); +float3 FogColor : register(c15); +float4 EyePosition : register(c16); +float4 LandBlendParams : register(c19); +float4 LightData : register(c25); + +static const float fUVScale = 1.f / 64.f; +static const float fUVScaleQuant = 127.f / 128.f; +static const float fUVOffset = 1.f / 256.f; +static const float fBlendBaseDistance = 9625.59961f; +static const float fBlendScale = 0.000375600968f; + +VS_OUTPUT main(VS_INPUT IN) { + VS_OUTPUT OUT; + + float4 posPS = mul(ModelViewProj, IN.position.xyzw); + + OUT.position.xyzw = posPS; + + float2 uv = (IN.uv.xy * fUVScale) + LandBlendParams.xy; + uv.x = 1 - uv.x; + + OUT.uv.xy = (uv.xy * fUVScaleQuant) + fUVOffset; + OUT.sunDirection.xyz = LightData.xyz; + + float2 blendVector = LandBlendParams.zw - IN.position.xy; + OUT.blend.x = 1 - saturate((fBlendBaseDistance - length(blendVector)) * fBlendScale); + + // Fog. + float3 fogPos = OUT.position.xyz; + #ifdef REVERSED_DEPTH + fogPos.z = OUT.position.w - fogPos.z; + #endif + float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); + OUT.fog.rgb = FogColor.rgb; + OUT.fog.a = pow(fogStrength, FogParam.z); + + OUT.lPosition.xyz = IN.position.xyz; + OUT.eyePosition.xyz = EyePosition.xyz; + + return OUT; +}; + +#endif // Vertex shader. + +struct PS_INPUT +{ + float2 uv : TEXCOORD0; + float3 sunDirection : TEXCOORD3_centroid; + float blend : TEXCOORD4_centroid; + float4 fog : TEXCOORD5_centroid; + float3 lPosition : TEXCOORD6_centroid; + float3 eyePosition : TEXCOORD7_centroid; +}; + +struct PS_OUTPUT { + float4 color_0 : COLOR0; +}; + +#ifdef PS + +sampler2D BaseMap : register(s0); +sampler2D NormalMap : register(s1); +sampler2D LODLandNoise : register(s2); + +float4 AmbientColor : register(c1); +float4 PSLightColor : register(c3); + +float4 LandLODSpec : register(c38); + +static const float fNoiseScale = 0.8f; +static const float fNoiseOffset = 0.55f; + +PS_OUTPUT main(PS_INPUT IN) { + PS_OUTPUT OUT; + + float3 eyeDir = normalize(IN.eyePosition.xyz - IN.lPosition.xyz); + + float noise = tex2D(LODLandNoise, IN.uv.xy * TESR_TerrainExtraData.w).r; + + float4 normal = tex2D(NormalMap, IN.uv.xy); + normal.rgb = normalize(expand(normal.rgb)); + normal.a *= LandLODSpec.x > 0.0f ? 1.0f : 0.0f; + + float3 baseColor = tex2D(BaseMap, IN.uv.xy).rgb; + + float3 lighting = getSunLighting(IN.sunDirection.xyz, PSLightColor.rgb, eyeDir, normal.xyz, AmbientColor.rgb, baseColor, normal.a, LandLODSpec.x); + + float3 final = lighting; + final = lerp(final, final * (noise * fNoiseScale + fNoiseOffset), saturate(TESR_TerrainExtraData.z)); // Apply noise. + final = lerp(final, IN.fog.rgb, IN.fog.a); // Apply fog. + + OUT.color_0.rgb = final; + OUT.color_0.a = IN.blend.x; + + return OUT; +}; + +#endif // Pixel shader. diff --git a/src/hlsl/NewVegas/Shaders/TerrainLODTemplate.hlsl b/src/hlsl/NewVegas/Shaders/TerrainLODTemplate.hlsl new file mode 100644 index 000000000..cae7c9901 --- /dev/null +++ b/src/hlsl/NewVegas/Shaders/TerrainLODTemplate.hlsl @@ -0,0 +1,140 @@ +// Template for LOD terrain shaders. + +#if defined(__INTELLISENSE__) + #define PS +#endif + +#define REVERSED_DEPTH + +#include "includes/Helpers.hlsl" +#include "includes/Terrain.hlsl" + +struct VS_INPUT { + float4 position : POSITION; + float4 uv : TEXCOORD0; + float geomorphHeight : TEXCOORD1; +}; + +struct VS_OUTPUT { + float4 fog : COLOR1; + float4 position : POSITION; + float2 uv : TEXCOORD0; + float3 sunDirection : TEXCOORD1; + float3 lPosition : TEXCOORD2; + float3 eyePosition : TEXCOORD3; +}; + +#ifdef VS + +row_major float4x4 ModelViewProj : register(c0); +row_major float4x4 ObjToCubeSpace : register(c8); + +float4 HighDetailRange : register(c12); +float4 FogParam : register(c14); +float3 FogColor : register(c15); +float4 EyePosition : register(c16); +float4 GeomorphParams : register(c19); +float4 LightData : register(c25); + +VS_OUTPUT main(VS_INPUT IN) { + VS_OUTPUT OUT; + + float4 posLS = IN.position; + float4 geomorphPos = IN.position; + geomorphPos.z = lerp(IN.geomorphHeight.x, IN.position.z, GeomorphParams.x); + + float q0 = (abs(dot(ObjToCubeSpace[1].xyzw, geomorphPos.xyzw) - HighDetailRange.y) < HighDetailRange.w ? 1.0 : 0.0); + float q1 = (abs(dot(ObjToCubeSpace[0].xyzw, geomorphPos.xyzw) - HighDetailRange.x) < HighDetailRange.z ? 1.0 : 0.0); + + posLS.z = geomorphPos.z - ((q0.x * q1.x) * GeomorphParams.y); + float4 posPS = mul(ModelViewProj, posLS.xyzw); + + OUT.position.xyzw = posPS.xyzw; + OUT.uv.xy = IN.uv.xy; + OUT.sunDirection = LightData.xyz; + + // Fog. + float3 fogPos = OUT.position.xyz; + #ifdef REVERSED_DEPTH + fogPos.z = OUT.position.w - fogPos.z; + #endif + float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); + OUT.fog.rgb = FogColor.rgb; + OUT.fog.a = pow(fogStrength, FogParam.z); + + OUT.lPosition.xyz = posLS.xyz; + OUT.eyePosition.xyz = EyePosition.xyz; + + return OUT; +}; + +#endif // Vertex shader. + +struct PS_INPUT +{ + float4 fog : COLOR1; + float4 position : POSITION; + float2 uv : TEXCOORD0; + float3 sunDirection : TEXCOORD1_centroid; + float3 lPosition : TEXCOORD2_centroid; + float3 eyePosition : TEXCOORD3_centroid; +}; + +struct PS_OUTPUT { + float4 color_0 : COLOR0; +}; + +#ifdef PS + +sampler2D BaseMap : register(s0); +sampler2D NormalMap : register(s1); +sampler2D LODParentTex : register(s4); +sampler2D LODParentNormals : register(s6); +sampler2D LODLandNoise : register(s7); + +float4 AmbientColor : register(c1); +float4 PSLightColor : register(c3); +float4 LODTexParams : register(c31); + +float4 LandLODSpec : register(c38); + +static const float fUVScale = 1.f / 128.f; +static const float fUVScaleQuant = 127.f / 128.f; +static const float fUVOffset = 1.f / 256.f; +static const float fNoiseScale = 0.8f; +static const float fNoiseOffset = 0.55f; + +PS_OUTPUT main(PS_INPUT IN) { + PS_OUTPUT OUT; + + float4 normal = tex2D(NormalMap, IN.uv); + float4 parentNormal = tex2D(LODParentNormals, (IN.uv * 0.5f) + LODTexParams.xy); + + float noise = tex2D(LODLandNoise, IN.uv * TESR_TerrainExtraData.w).r; + + normal.rgba = LODTexParams.w >= 1 ? normal.rgba : lerp(parentNormal, normal.rgba, LODTexParams.w); + normal.rgb = expand(normal.rgb); + normal.rgb = normalize(normal.rgb); + normal.a *= LandLODSpec.x > 0.0f ? 1.0f : 0.0f; + + float2 uv = (IN.uv * fUVScaleQuant) + fUVOffset; + float3 parentColor = tex2D(LODParentTex, (0.5f * uv) + lerp(LODTexParams.xy, 0.25f, fUVScale)).rgb; + float3 baseColor = tex2D(BaseMap, uv).rgb; + + baseColor = LODTexParams.w >= 1 ? baseColor : lerp(parentColor, baseColor, LODTexParams.w); + + float3 eyeDir = normalize(IN.eyePosition.xyz - IN.lPosition.xyz); + + float3 lighting = getSunLighting(IN.sunDirection.xyz, PSLightColor.rgb, eyeDir, normal.xyz, AmbientColor.rgb, baseColor, normal.a, LandLODSpec.x); + + float3 final = lighting; + final = lerp(final, final * (0.8 * noise + 0.55), saturate(TESR_TerrainExtraData.z)); // Apply noise. + final = lerp(final, IN.fog.rgb, IN.fog.a); + + OUT.color_0.rgb = final; + OUT.color_0.a = 1; + + return OUT; +}; + +#endif // Pixel shader. diff --git a/src/hlsl/NewVegas/Shaders/TerrainTemplate.hlsl b/src/hlsl/NewVegas/Shaders/TerrainTemplate.hlsl index ea1193b60..4e65b10c9 100644 --- a/src/hlsl/NewVegas/Shaders/TerrainTemplate.hlsl +++ b/src/hlsl/NewVegas/Shaders/TerrainTemplate.hlsl @@ -2,15 +2,19 @@ #if defined(__INTELLISENSE__) #define PS - #define POINTLIGHT + #define NUM_PT_LIGHTS 24 #endif #define TERRAIN -#ifndef ILS - #define NUM_PT_LIGHTS 3 -#else - #define NUM_PT_LIGHTS 12 +#define REVERSED_DEPTH + +#ifndef TEX_COUNT + #define TEX_COUNT 1 +#endif + +#if defined(NUM_PT_LIGHTS) && (NUM_PT_LIGHTS > 24) + #define NUM_PT_LIGHTS 24 #endif #include "includes/Helpers.hlsl" @@ -38,7 +42,7 @@ struct VS_OUTPUT { float3 tangent : TEXCOORD3; float3 binormal : TEXCOORD4; float3 normal : TEXCOORD5; - float4 fog : TEXCOORD6; + float4 projectionPosition : TEXCOORD6; float3 viewPosition : TEXCOORD7; }; @@ -53,32 +57,19 @@ float4 EyePosition : register(c16); VS_OUTPUT main(VS_INPUT IN) { VS_OUTPUT OUT; - float3 mdl0; - - mdl0.xyz = mul(float3x4(ModelViewProj[0].xyzw, ModelViewProj[1].xyzw, ModelViewProj[2].xyzw), IN.position.xyzw); + float4 posPS = mul(float4x4(ModelViewProj[0].xyzw, ModelViewProj[1].xyzw, ModelViewProj[2].xyzw, ModelViewProj[3].xyzw), IN.position.xyzw); OUT.blend_0 = IN.blend_0; OUT.blend_1 = IN.blend_1; - - OUT.sPosition.w = dot(ModelViewProj[3].xyzw, IN.position.xyzw); - OUT.sPosition.xyz = mdl0.xyz; + + OUT.sPosition.xyzw = posPS; OUT.uv.xy = IN.uv.xy; OUT.vertex_color.xyz = clamp(IN.vertex_color.rgb, 0.0f, 1.0f); OUT.lPosition.xyz = IN.position.xyz; OUT.tangent.xyz = IN.tangent.xyz; OUT.binormal.xyz = IN.binormal.xyz; OUT.normal.xyz = IN.normal.xyz; - - // Fog. - float3 fogPos = OUT.sPosition.xyz; - #ifdef REVERSED_DEPTH - fogPos.z = OUT.sPosition.w - fogPos.z; - #endif - float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); - fogStrength = log2(fogStrength); - OUT.fog.a = exp2(fogStrength * FogParam.z); - OUT.fog.rgb = FogColor.rgb; - + OUT.projectionPosition.xyzw = posPS; OUT.viewPosition.xyz = EyePosition.xyz; return OUT; @@ -96,7 +87,7 @@ struct PS_INPUT float3 normal : TEXCOORD5_centroid; float4 blend_0 : COLOR0; float4 blend_1 : COLOR1; - float4 fog : TEXCOORD6_centroid; + float4 projectionPosition : TEXCOORD6_centroid; float3 viewPosition : TEXCOORD7_centroid; float4 sPosition : POSITION1; }; @@ -111,9 +102,19 @@ sampler2D BaseMap[7]:register(s0); sampler2D NormalMap[7]:register(s7); float4 AmbientColor : register(c1); -float4 PSLightColor[13] : register(c3); -float4 PSLightDir : register(c18); -float4 PSLightPosition[12] : register(c19); +float4 SunColor : register(c3); +float4 SunDir : register(c18); + +float4 LandSpec[2] : register(c32); +float4 LandHeight[2] : register(c34); +float4 FogParam : register(c36); +float4 FogColor : register(c37); + +#ifdef NUM_PT_LIGHTS +float4 PointLightColor[NUM_PT_LIGHTS] : register(c39); +float4 PointLightPosition[NUM_PT_LIGHTS] : register(c63); +float PointLightCount : register(c88); +#endif PS_OUTPUT main(PS_INPUT IN) { PS_OUTPUT OUT; @@ -132,27 +133,45 @@ PS_OUTPUT main(PS_INPUT IN) { float weights[7] = { 0, 0, 0, 0, 0, 0, 0 }; float blends[7] = { IN.blend_0.x, IN.blend_0.y, IN.blend_0.z, IN.blend_0.w, IN.blend_1.x, IN.blend_1.y, IN.blend_1.z }; - float2 offsetUV = getParallaxCoords(dist, IN.uv.xy, dx, dy, eyeDir, texCount, BaseMap, blends, weights); + float spec[7] = { LandSpec[0].x, LandSpec[0].y, LandSpec[0].z, LandSpec[0].w, LandSpec[1].x, LandSpec[1].y, LandSpec[1].z }; + float heightStatus[7] = { LandHeight[0].x, LandHeight[0].y, LandHeight[0].z, LandHeight[0].w, LandHeight[1].x, LandHeight[1].y, LandHeight[1].z }; + float2 offsetUV = getParallaxCoords(dist, IN.uv.xy, dx, dy, eyeDir, texCount, BaseMap, blends, heightStatus, weights); - float roughness = 1.f; + float gloss = 0.0f; + float specExponent = 0.0f; float3 baseColor = blendDiffuseMaps(IN.vertex_color, offsetUV, texCount, BaseMap, weights); - float3 combinedNormal = blendNormalMaps(offsetUV, texCount, NormalMap, weights, roughness); + float3 combinedNormal = blendNormalMaps(offsetUV, texCount, NormalMap, weights, spec, gloss, specExponent); - float3 lightTS = mul(tbn, PSLightDir.xyz); - float parallaxShadowMultiplier = getParallaxShadowMultipler(dist, offsetUV, dx, dy, lightTS, texCount, blends, BaseMap); + float3 lightTS = mul(tbn, SunDir.xyz); + float parallaxShadowMultiplier = getParallaxShadowMultipler(dist, offsetUV, dx, dy, lightTS, texCount, blends, heightStatus, BaseMap); - float3 lighting = getSunLighting(lightTS, PSLightColor[0].rgb, eyeDir, combinedNormal, AmbientColor.rgb, baseColor, roughness, 1.0, parallaxShadowMultiplier); - - #if defined(POINTLIGHT) - float3 pointlightDir; - [unroll] for (int i = 0; i < NUM_PT_LIGHTS; i++) { - pointlightDir = mul(tbn, PSLightPosition[i].xyz - IN.lPosition.xyz); - lighting += getPointLightLighting(pointlightDir, PSLightPosition[i].w, PSLightColor[i + 1].rgb, eyeDir, combinedNormal, baseColor, roughness, 1.0); + float3 lighting = getSunLighting(lightTS, SunColor.rgb, eyeDir, combinedNormal, AmbientColor.rgb, baseColor, gloss, specExponent); + + #if defined(NUM_PT_LIGHTS) + [loop] for (int i = 0; i < PointLightCount; i++) { + float3 pointlightDir = PointLightPosition[i].xyz - IN.lPosition.xyz; + float att = vanillaAtt(pointlightDir, PointLightPosition[i].w); + + [branch] + if (att > 0.001) { + pointlightDir = mul(tbn, pointlightDir); + lighting += getPointLightLighting(pointlightDir, att, PointLightColor[i].rgb, eyeDir, combinedNormal, baseColor, gloss, specExponent); + } } #endif + // Per pixel fog. + float4 fog; + float3 fogPos = IN.projectionPosition.xyz; + #ifdef REVERSED_DEPTH + fogPos.z = IN.projectionPosition.w - IN.projectionPosition.z; + #endif + float fogStrength = 1 - saturate((FogParam.x - length(fogPos)) / FogParam.y); + fog.rgb = FogColor.rgb; + fog.a = pow(fogStrength, FogParam.z); + float3 finalColor = lighting; - finalColor = lerp(finalColor, IN.fog.rgb, IN.fog.a); // Apply fog. + finalColor = lerp(finalColor, fog.rgb, fog.a); // Apply fog. OUT.color_0.a = 1; OUT.color_0.rgb = finalColor; From c03851c3e7f621ff48bb48216011cc52dd62db71 Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 01:13:29 +0200 Subject: [PATCH 2/8] Enforce NVR dependencies at startup Add dependency on LOD Flicker Fix and Vanilla Plus Terrain to avoid a lot of trouble figuring out variants for everything. --- NewVegasReloaded/Main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NewVegasReloaded/Main.cpp b/NewVegasReloaded/Main.cpp index 835939bb0..5c0847284 100644 --- a/NewVegasReloaded/Main.cpp +++ b/NewVegasReloaded/Main.cpp @@ -8,6 +8,18 @@ extern "C" { static void MessageHandler(NVSEMessagingInterface::Message* msg) { switch (msg->type) { + case NVSEMessagingInterface::kMessage_PostLoad: + if (!GetModuleHandle(L"LODFlickerFix.dll")) { + MessageBox(NULL, L"LOD Flicker Fix not found.\nNew Vegas Reloaded cannot be used without it, please install it.", L"New Vegas Reloaded", MB_OK | MB_ICONERROR); + ExitProcess(0); + } + + if (!GetModuleHandle(L"VanillaPlusTerrain.dll")) { + MessageBox(NULL, L"Vanilla Plus Terrain not found.\nNew Vegas Reloaded cannot be used without it, please install it.", L"New Vegas Reloaded", MB_OK | MB_ICONERROR); + ExitProcess(0); + } + + break; case NVSEMessagingInterface::kMessage_PreLoadGame: TheSettingManager->GameLoading = true; break; From ac496e2f03979e28459db5502c517850c8c8027f Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 01:14:13 +0200 Subject: [PATCH 3/8] Avoid vertex shaders reseting set samplers Fixed a rare issue with close water getting their normals sampler cleared by a swap of vertex shaders. --- src/core/ShaderRecord.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/ShaderRecord.cpp b/src/core/ShaderRecord.cpp index aa6e2a4c2..e700edab2 100644 --- a/src/core/ShaderRecord.cpp +++ b/src/core/ShaderRecord.cpp @@ -567,6 +567,7 @@ ShaderRecordVertex::ShaderRecordVertex(const char* shaderName) { Name = shaderName; ShaderHandle = NULL; + ClearSamplers = false; } @@ -579,6 +580,7 @@ ShaderRecordVertex::~ShaderRecordVertex() { ShaderRecordPixel::ShaderRecordPixel(const char* shaderName) { Name = shaderName; ShaderHandle = NULL; + ClearSamplers = true; } From cc0c26226d8e7f76d59c43dc7ecc38ae24fb7c74 Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 03:36:31 +0200 Subject: [PATCH 4/8] Fix view model depth blending Fix some issues regarding the blending between scene and view model depths - view model should always take precedent. Point sampling instead of linear. JG clip distance taken into account. --- .../NewVegas/Effects/CombineDepth.fx.hlsl | 43 +++++++------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/hlsl/NewVegas/Effects/CombineDepth.fx.hlsl b/src/hlsl/NewVegas/Effects/CombineDepth.fx.hlsl index 640538419..2cb7d74ab 100644 --- a/src/hlsl/NewVegas/Effects/CombineDepth.fx.hlsl +++ b/src/hlsl/NewVegas/Effects/CombineDepth.fx.hlsl @@ -3,9 +3,10 @@ float4 TESR_CameraData; float4x4 TESR_InvProjectionTransform; -sampler2D TESR_DepthBufferWorld : register(s0) = sampler_state { ADDRESSU = CLAMP; ADDRESSV = CLAMP; MAGFILTER = LINEAR; MINFILTER = LINEAR; MIPFILTER = LINEAR; }; -sampler2D TESR_DepthBufferViewModel : register(s1) = sampler_state { ADDRESSU = CLAMP; ADDRESSV = CLAMP; MAGFILTER = LINEAR; MINFILTER = LINEAR; MIPFILTER = LINEAR; }; +sampler2D TESR_DepthBufferWorld : register(s0) = sampler_state { ADDRESSU = CLAMP; ADDRESSV = CLAMP; MAGFILTER = POINT; MINFILTER = POINT; MIPFILTER = NONE; }; +sampler2D TESR_DepthBufferViewModel : register(s1) = sampler_state { ADDRESSU = CLAMP; ADDRESSV = CLAMP; MAGFILTER = POINT; MINFILTER = POINT; MIPFILTER = NONE; }; +static const float viewModelNearZ = TESR_DepthConstants.x; static const float invertedDepth = TESR_DepthConstants.z; static const float nearZ = TESR_CameraData.x; static const float farZ = TESR_CameraData.y; @@ -30,41 +31,29 @@ VSOUT FrameVS(VSIN IN) return OUT; } -// linearize depth -float readDepth(float depth, float nearZ, float farZ) -{ - float Q = farZ/(farZ - nearZ); - float ViewZ = (-nearZ *Q) / (depth - Q); - return ViewZ; +// Convert depth to view space Z. +float ToVS(float depth, float nearZ, float farZ) { + return nearZ * farZ / (nearZ + depth * (farZ - nearZ)); } -// convert back to usual depth buffer format for easier reconstruction -float packDepth(float viewZ, float nearZ, float farZ){ - float Q = farZ/(farZ - nearZ); - return (Q* (viewZ - nearZ ))/ viewZ; +// Convert view space Z to depth. +float ToPS(float viewZ, float nearZ, float farZ){ + return nearZ * (farZ - viewZ) / (viewZ * (farZ - nearZ)); } -float4 CombineDepth(VSOUT IN) : COLOR0 -{ - +float4 CombineDepth(VSOUT IN) : COLOR0 { float worldDepth = tex2D(TESR_DepthBufferWorld, IN.UVCoord).x; float viewModelDepth = tex2D(TESR_DepthBufferViewModel, IN.UVCoord).x; - float combinedDepth = min(worldDepth, viewModelDepth); - if (invertedDepth){ - combinedDepth = max(worldDepth, viewModelDepth); - } - - float x = IN.UVCoord.x * 2 - 1; - float y = (1 - IN.UVCoord.y) * 2 - 1; - float4 clipSpace = float4(x, y, combinedDepth, 1.0f); - - float4 viewSpace = mul(clipSpace, TESR_InvProjectionTransform); + float worldViewZ = ToVS(worldDepth, nearZ, farZ); + float viewModelViewZ = ToVS(viewModelDepth, viewModelNearZ, farZ); - viewSpace /= viewSpace.w; + float combinedViewZ = worldViewZ; + if (viewModelDepth > 0.0) + combinedViewZ = viewModelViewZ; - return float4(viewSpace.z / farZ, combinedDepth, 1.0, 1.0); // scale values back to 0 - 1 to avoid overflow + return float4(combinedViewZ / farZ, ToPS(combinedViewZ, nearZ, farZ), 1.0, 1.0); } technique From 401a86336e10614fe06b9bd675c8c2d30ff7dea1 Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 04:23:27 +0200 Subject: [PATCH 5/8] More safety for shader compilation Still no idea where the infinite loading is coming from. --- src/core/ShaderRecord.cpp | 72 +++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/core/ShaderRecord.cpp b/src/core/ShaderRecord.cpp index e700edab2..1ccd07ec3 100644 --- a/src/core/ShaderRecord.cpp +++ b/src/core/ShaderRecord.cpp @@ -51,32 +51,33 @@ bool ShaderProgram::FileExists(const char* path) { bool ShaderProgram::CheckPreprocessResult(const char* CachedPreprocessPath, ID3DXBuffer* ShaderSource) { void* CurrentContent = ShaderSource->GetBufferPointer(); - ID3DXBuffer* CachedSource; - void* CachedContent; + ID3DXBuffer* CachedSource = nullptr; + void* CachedContent = nullptr; std::ifstream File(CachedPreprocessPath, std::ios::in | std::ios::ate); if (File.is_open()) { std::streamoff Size = File.tellg(); - D3DXCreateBuffer(Size, &CachedSource); - File.seekg(0, std::ios::beg); - CachedContent = CachedSource->GetBufferPointer(); - File.read((char*)CachedContent, Size); - File.close(); + if (Size > 0 && SUCCEEDED(D3DXCreateBuffer(Size, &CachedSource))) { + File.seekg(0, std::ios::beg); + CachedContent = CachedSource->GetBufferPointer(); + File.read((char*)CachedContent, Size); + File.close(); + } + else { + File.close(); + return false; + } } else { return false; } - bool match; + bool match = false; - if (!CachedContent) { - match = false; - } - else if (ShaderSource->GetBufferSize() != CachedSource->GetBufferSize()) { - match = false; - } - else { - match = !memcmp(CurrentContent, CachedContent, ShaderSource->GetBufferSize()); + if (CachedContent && CachedSource) { + if (ShaderSource->GetBufferSize() == CachedSource->GetBufferSize()) { + match = !memcmp(CurrentContent, CachedContent, ShaderSource->GetBufferSize()); + } } if (CachedSource) CachedSource->Release(); @@ -139,10 +140,8 @@ ShaderRecord* ShaderRecord::LoadShader(const char* Name, const char* SubPath, Sh nullFound = Template.Defines[i].Name == NULL; if (!nullFound) i++; } - if (TheRenderManager->IsReversedDepth()) { - Template.Defines[i] = { "REVERSED_DEPTH", "" }; - i++; - } + Template.Defines[i] = { "REVERSED_DEPTH", "" }; + Template.Defines[i + 1] = { NULL, NULL }; // Ensure null termination } HRESULT prepass = D3DXPreprocessShaderFromFileA(ShaderSourcePath, Macros, NULL, &ShaderSource, &Errors); @@ -158,11 +157,16 @@ ShaderRecord* ShaderRecord::LoadShader(const char* Name, const char* SubPath, Sh std::ifstream FileBinary(ShaderCompiledPath, std::ios::in | std::ios::binary | std::ios::ate); if (FileBinary.is_open()) { std::streamoff Size = FileBinary.tellg(); - D3DXCreateBuffer(Size, &Shader); - FileBinary.seekg(0, std::ios::beg); - Function = Shader->GetBufferPointer(); - FileBinary.read((char*)Function, Size); - FileBinary.close(); + if (Size > 0 && SUCCEEDED(D3DXCreateBuffer(Size, &Shader))) { + FileBinary.seekg(0, std::ios::beg); + Function = Shader->GetBufferPointer(); + FileBinary.read((char*)Function, Size); + FileBinary.close(); + } + else { + FileBinary.close(); + Logger::Log("ERROR: Failed to create buffer for shader binary %s", ShaderCompiledPath); + } } else { Logger::Log("ERROR: Shader binary %s not found.", ShaderCompiledPath); @@ -218,16 +222,26 @@ ShaderRecord* ShaderRecord::LoadShader(const char* Name, const char* SubPath, Sh Logger::Log("Issues getting constants descriptions for %s", Name); } else if (Shader) { + HRESULT createResult = E_FAIL; if (ShaderProfile[0] == 'v') { ShaderProg = new ShaderRecordVertex(Name); - TheRenderManager->device->CreateVertexShader((const DWORD*)Function, &((ShaderRecordVertex*)ShaderProg)->ShaderHandle); + createResult = TheRenderManager->device->CreateVertexShader((const DWORD*)Function, &((ShaderRecordVertex*)ShaderProg)->ShaderHandle); } else { ShaderProg = new ShaderRecordPixel(Name); - TheRenderManager->device->CreatePixelShader((const DWORD*)Function, &((ShaderRecordPixel*)ShaderProg)->ShaderHandle); + createResult = TheRenderManager->device->CreatePixelShader((const DWORD*)Function, &((ShaderRecordPixel*)ShaderProg)->ShaderHandle); + } + + if (SUCCEEDED(createResult)) { + ShaderProg->CreateCT(ShaderSource, ConstantTable); + Logger::Log("Shader loaded: %s", ShaderCompiledPath); + } + else { + Logger::Log("ERROR: Failed to create DirectX shader for %s", Name); + ReportError(createResult); + delete ShaderProg; + ShaderProg = nullptr; } - ShaderProg->CreateCT(ShaderSource, ConstantTable); - Logger::Log("Shader loaded: %s", ShaderCompiledPath); } } } From c5654d673e64554705a055b17242153bba5b4f1f Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 05:34:01 +0200 Subject: [PATCH 6/8] Make sure volumetric fog doesn't underflow Causes issues downstream with other shaders resulting in "purple" fog. --- src/hlsl/NewVegas/Effects/VolumetricFog.fx.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hlsl/NewVegas/Effects/VolumetricFog.fx.hlsl b/src/hlsl/NewVegas/Effects/VolumetricFog.fx.hlsl index 691730269..7cf7d00ca 100644 --- a/src/hlsl/NewVegas/Effects/VolumetricFog.fx.hlsl +++ b/src/hlsl/NewVegas/Effects/VolumetricFog.fx.hlsl @@ -235,7 +235,7 @@ float4 VolumetricFog(VSOUT IN) : COLOR0 float3 heightFog = mixHeightFog(finalColor.rgb, heightFogColor.rgb, extinction, inScattering, fogDepth, strength * HeightFogDensity, 1.5 / (fogPower * HeightFogFalloff), worldPos, HeightFogHeight); finalColor = lerp(finalColor, float4(heightFog, 1), saturate(HeightFogBlend)); - finalColor = lerp(color, finalColor, FogAmount); + finalColor = max(lerp(color, finalColor, FogAmount), 0.0f); return delinearize(finalColor); } From b25c9d1555f8ed1ccad607cf4eeb8ecc6cc9baed Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 18:04:55 +0200 Subject: [PATCH 7/8] Add description to missing water settings They were marked "Not used.", while in fact they are in use. --- resource/NewVegasReloaded.dll.defaults.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resource/NewVegasReloaded.dll.defaults.toml b/resource/NewVegasReloaded.dll.defaults.toml index c290d04db..a1aff1afe 100644 --- a/resource/NewVegasReloaded.dll.defaults.toml +++ b/resource/NewVegasReloaded.dll.defaults.toml @@ -887,13 +887,13 @@ Enabled = true # Volumetric fog shader tinted by the sun. R [_Shaders.Water.Default] causticsStrength = 3.0 # Caustic strength underwater. Caustics seen from above water not currently supported -causticsStrengthS = 0.2 # Not used. +causticsStrengthS = 0.2 # Godrays intensity underwater. choppiness = 0.7 # Exponent for the waves normals. A higher value will create more defined wave crests. depthDarkness = 1.0 # How much light reaches the bottom of the water. -inExtCoeff_B = 1.0 # Not used. -inExtCoeff_G = 1.0 # Not used. -inExtCoeff_R = 1.0 # Not used. -inScattCoeff = 1.0 # Not used. +inExtCoeff_B = 1.0 # Underwater fog color tint (blue component). +inExtCoeff_G = 1.0 # Underwater fog color tint (green component). +inExtCoeff_R = 1.0 # Underwater fog color tint (red component). +inScattCoeff = 1.0 # Underwater scattering modifier, higher values lead to less brightness. reflectivity = 1.0 # Multiplier for the strength of reflections on the surface. shoreFactor = 6.0 # Size of the shore fading area on shallow slope areas. shoreMovement = 0.3 # Speed of wave movement in the shore. From 9d235ce1d141df8ce58945f5f786a675aeddb916 Mon Sep 17 00:00:00 2001 From: pr0bability Date: Sun, 8 Jun 2025 18:06:21 +0200 Subject: [PATCH 8/8] Bump up version to 4.3.0 --- NewVegasReloaded/Main.cpp | 2 +- NewVegasReloaded/NewVegasReloaded.rc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NewVegasReloaded/Main.cpp b/NewVegasReloaded/Main.cpp index 5c0847284..49fa04cba 100644 --- a/NewVegasReloaded/Main.cpp +++ b/NewVegasReloaded/Main.cpp @@ -64,7 +64,7 @@ extern "C" { Info->InfoVersion = PluginInfo::kInfoVersion; Info->Name = "NewVegasReloaded"; - Info->Version = 421; + Info->Version = 430; return true; } diff --git a/NewVegasReloaded/NewVegasReloaded.rc b/NewVegasReloaded/NewVegasReloaded.rc index 25cd55197..540805f2b 100644 --- a/NewVegasReloaded/NewVegasReloaded.rc +++ b/NewVegasReloaded/NewVegasReloaded.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,2,1,0 - PRODUCTVERSION 4,2,1,0 + FILEVERSION 4,3,0,0 + PRODUCTVERSION 4,3,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "New Vegas Reloaded" - VALUE "FileVersion", "4.2.1" + VALUE "FileVersion", "4.3.0" VALUE "InternalName", "NewVegasReloaded.dll" - VALUE "LegalCopyright", "Copyright (C) 2024" + VALUE "LegalCopyright", "Copyright (C) 2025" VALUE "OriginalFilename", "NewVegasReloaded.dll" VALUE "ProductName", "New Vegas Reloaded" - VALUE "ProductVersion", "4.2.1" + VALUE "ProductVersion", "4.3.0" END END BLOCK "VarFileInfo"