diff --git a/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli b/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli index e184403f4..919e9079b 100644 --- a/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli +++ b/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli @@ -4,11 +4,8 @@ struct PerPassWaterCaustics float pad[3]; }; -StructuredBuffer perPassWaterCaustics : register(t71); - -#if defined(WATER) - Texture2D WaterCaustics : register(t70); +StructuredBuffer perPassWaterCaustics : register(t71); float2 PanCausticsUV(float2 uv, float speed, float tiling) { @@ -43,29 +40,7 @@ float3 ComputeWaterCaustics(float2 uv) return caustics; } -#else - -Texture2D WaterCaustics : register(t70); - -float2 PanCausticsUV(float2 uv, float speed, float tiling) -{ - return (float2(1, 0) * lightingData[0].Timer * speed) + (uv * tiling); -} - -float3 SampleCaustics(float2 uv, float split) -{ - float2 uv1 = uv + float2(split, split); - float2 uv2 = uv + float2(split, -split); - float2 uv3 = uv + float2(-split, -split); - - float r = WaterCaustics.Sample(SampColorSampler, uv1).r; - float g = WaterCaustics.Sample(SampColorSampler, uv2).r; - float b = WaterCaustics.Sample(SampColorSampler, uv3).r; - - return float3(r, g, b); -} - -float3 ComputeWaterCaustics(float3 waterHeight, float3 worldPosition, float3 worldSpaceNormal) +float3 ComputeWaterCaustics(float waterHeight, float3 worldPosition, float3 worldSpaceNormal) { float causticsDistToWater = waterHeight - worldPosition.z; float shoreFactorCaustics = saturate(causticsDistToWater / 64.0); @@ -99,5 +74,3 @@ float3 ComputeWaterCaustics(float3 waterHeight, float3 worldPosition, float3 wor caustics = lerp(causticsLow, caustics, upAmount); return lerp(1.0, caustics, shoreFactorCaustics * upAmount); } - -#endif \ No newline at end of file diff --git a/package/Shaders/Common/VR.hlsl b/package/Shaders/Common/VR.hlsl index 42bd7b53f..a931d409a 100644 --- a/package/Shaders/Common/VR.hlsl +++ b/package/Shaders/Common/VR.hlsl @@ -1,35 +1,58 @@ /** -Converts to the eye specific uv. -In VR, texture buffers include the left and right eye in the same buffer. Flat only has a single camera for the entire width. -This means the x value [0, .5] represents the left eye, and the y value (.5, 1] are the right eye. -This returns the adjusted value +Converts to the eye specific uv [0,1]. +In VR, texture buffers include the left and right eye in the same buffer. Flat +only has a single camera for the entire width. This means the x value [0, .5] +represents the left eye, and the x value (.5, 1] are the right eye. This returns +the adjusted value @param uv - uv coords [0,1] to be encoded for VR @param a_eyeIndex The eyeIndex; 0 is left, 1 is right +@param a_invertY Whether to invert the Y direction @returns uv with x coords adjusted for the VR texture buffer */ -float2 ConvertToStereoUV(float2 uv, uint a_eyeIndex) +float2 ConvertToStereoUV(float2 uv, uint a_eyeIndex, uint a_invertY = 0) { #ifdef VR // convert [0,1] to eye specific [0,.5] and [.5, 1] dependent on a_eyeIndex uv.x = (uv.x + (float)a_eyeIndex) / 2; + if (a_invertY) + uv.y = 1 - uv.y; #endif return uv; } /** -Converts from eye specific uv to general uv. +Converts from eye specific uv to general uv [0,1]. In VR, texture buffers include the left and right eye in the same buffer. -This means the x value [0, .5] represents the left eye, and the y value (.5, 1] are the right eye. +This means the x value [0, .5] represents the left eye, and the x value (.5, 1] are the right eye. This returns the adjusted value @param uv - eye specific uv coords [0,1]; if uv.x < 0.5, it's a left eye; otherwise right @param a_eyeIndex The eyeIndex; 0 is left, 1 is right +@param a_invertY Whether to invert the Y direction @returns uv with x coords adjusted to full range for either left or right eye */ -float2 ConvertFromStereoUV(float2 uv, uint a_eyeIndex) +float2 ConvertFromStereoUV(float2 uv, uint a_eyeIndex, uint a_invertY = 0) { #ifdef VR // convert [0,.5] to [0, 1] and [.5, 1] to [0,1] uv.x = 2 * uv.x - (float)a_eyeIndex; + if (a_invertY) + uv.y = 1 - uv.y; #endif return uv; } + +/** +Converts to the eye specific screenposition [0,Resolution]. +In VR, texture buffers include the left and right eye in the same buffer. Flat only has a single camera for the entire width. +This means the x value [0, resx/2] represents the left eye, and the x value (resx/2, x] are the right eye. +This returns the adjusted value +@param screenPosition - Screenposition coords ([0,resx], [0,resy]) to be encoded for VR +@param a_eyeIndex The eyeIndex; 0 is left, 1 is right +@param a_resolution The resolution of the screen +@returns screenPosition with x coords adjusted for the VR texture buffer +*/ +float2 ConvertToStereoSP(float2 screenPosition, uint a_eyeIndex, float2 a_resolution) +{ + screenPosition.x /= a_resolution.x; + return ConvertToStereoUV(screenPosition, a_eyeIndex) * a_resolution; +} \ No newline at end of file diff --git a/package/Shaders/Water.hlsl b/package/Shaders/Water.hlsl index ab44dce2e..64c305dd8 100644 --- a/package/Shaders/Water.hlsl +++ b/package/Shaders/Water.hlsl @@ -24,6 +24,9 @@ struct VS_INPUT float4 Color : COLOR0; # endif #endif +#if defined(VR) + uint InstanceID : SV_INSTANCEID; +#endif // VR }; struct VS_OUTPUT @@ -68,13 +71,21 @@ struct VS_OUTPUT #endif float4 NormalsScale : TEXCOORD8; +#if defined(VR) + float ClipDistance : SV_ClipDistance0; // o11 + float CullDistance : SV_CullDistance0; // p11 +#endif // VR }; #ifdef VSHADER cbuffer PerTechnique : register(b0) { - float4 QPosAdjust : packoffset(c0); +# if !defined(VR) + float4 QPosAdjust[1] : packoffset(c0); +# else + float4 QPosAdjust[2] : packoffset(c0); +# endif // VR }; cbuffer PerMaterial : register(b1) @@ -89,22 +100,50 @@ cbuffer PerMaterial : register(b1) cbuffer PerGeometry : register(b2) { - row_major float4x4 World : packoffset(c0); - row_major float4x4 PreviousWorld : packoffset(c4); - row_major float4x4 WorldViewProj : packoffset(c8); +# if !defined(VR) + row_major float4x4 World[1] : packoffset(c0); + row_major float4x4 PreviousWorld[1] : packoffset(c4); + row_major float4x4 WorldViewProj[1] : packoffset(c8); float3 ObjectUV : packoffset(c12); float4 CellTexCoordOffset : packoffset(c13); +# else // VR has 25 vs 13 entries + row_major float4x4 World[2] : packoffset(c0); + row_major float4x4 PreviousWorld[2] : packoffset(c8); + row_major float4x4 WorldViewProj[2] : packoffset(c16); + float3 ObjectUV : packoffset(c24); + float4 CellTexCoordOffset : packoffset(c25); +# endif // VR +}; + +# ifdef VR +cbuffer VRValues : register(b13) +{ + float AlphaThreshold : packoffset(c0); + float StereoEnabled : packoffset(c0.y); + float2 EyeOffsetScale : packoffset(c0.z); + float4 EyeClipEdge[2] : packoffset(c1); +} +# endif // VR + +const static float4x4 M_IdentityMatrix = { + { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; VS_OUTPUT main(VS_INPUT input) { VS_OUTPUT vsout; +# if !defined(VR) + uint eyeIndex = 0; +# else // VR + uint eyeIndex = StereoEnabled * (input.InstanceID.x & 1); +# endif // VR + vsout.NormalsScale = NormalsScale; float4 inputPosition = float4(input.Position.xyz, 1.0); - float4 worldPos = mul(World, inputPosition); - float4 worldViewPos = mul(WorldViewProj, inputPosition); + float4 worldPos = mul(World[eyeIndex], inputPosition); + float4 worldViewPos = mul(WorldViewProj[eyeIndex], inputPosition); float heightMult = min((1.0 / 10000.0) * max(worldViewPos.z - 70000, 0), 1); @@ -114,7 +153,7 @@ VS_OUTPUT main(VS_INPUT input) # if defined(STENCIL) vsout.WorldPosition = worldPos; - vsout.PreviousWorldPosition = mul(PreviousWorld, inputPosition); + vsout.PreviousWorldPosition = mul(PreviousWorld[eyeIndex], inputPosition); # else float fogColorParam = min(VSFogFarColor.w, pow(saturate(length(worldViewPos.xyz) * VSFogParam.y - VSFogParam.x), NormalsScale.w)); @@ -126,7 +165,7 @@ VS_OUTPUT main(VS_INPUT input) # if defined(LOD) float4 posAdjust = - ObjectUV.x ? 0.0 : (QPosAdjust.xyxy + worldPos.xyxy) / NormalsScale.xxyy; + ObjectUV.x ? 0.0 : (QPosAdjust[eyeIndex].xyxy + worldPos.xyxy) / NormalsScale.xxyy; vsout.TexCoord1.xyzw = NormalsScroll0 + posAdjust; # else @@ -134,7 +173,7 @@ VS_OUTPUT main(VS_INPUT input) vsout.MPosition.xyzw = inputPosition.xyzw; # endif - float2 posAdjust = worldPos.xy + QPosAdjust.xy; + float2 posAdjust = worldPos.xy + QPosAdjust[eyeIndex].xy; float2 scrollAdjust1 = posAdjust / NormalsScale.xx; float2 scrollAdjust2 = posAdjust / NormalsScale.yy; @@ -203,6 +242,28 @@ VS_OUTPUT main(VS_INPUT input) # endif # endif +# ifdef VR + float4 r0; + float4 projSpacePosition = vsout.HPosition; + r0.xyzw = 0; + if (0 < StereoEnabled) { + r0.yz = dot(projSpacePosition, EyeClipEdge[eyeIndex]); // projSpacePosition is clipPos + } else { + r0.yz = float2(1, 1); + } + + r0.w = 2 + -StereoEnabled; + r0.x = dot(EyeOffsetScale, M_IdentityMatrix[eyeIndex].xy); + r0.xw = r0.xw * projSpacePosition.wx; + r0.x = StereoEnabled * r0.x; + + vsout.HPosition.x = r0.w * 0.5 + r0.x; + vsout.HPosition.yzw = projSpacePosition.yzw; + + vsout.ClipDistance.x = r0.z; + vsout.CullDistance.x = r0.y; +# endif // VR + return vsout; } @@ -252,11 +313,19 @@ Texture2D RawSSRReflectionTex : register(t11); cbuffer PerTechnique : register(b0) { - float4 VPOSOffset : packoffset(c0); // inverse main render target width and height in xy, 0 in zw - float4 PosAdjust : packoffset(c1); // inverse framebuffer range in w +# if !defined(VR) + float4 VPOSOffset : packoffset(c0); // inverse main render target width and height in xy, 0 in zw + float4 PosAdjust[1] : packoffset(c1); // inverse framebuffer range in w float4 CameraData : packoffset(c2); float4 SunDir : packoffset(c3); float4 SunColor : packoffset(c4); +# else + float4 VPOSOffset : packoffset(c0); // inverse main render target width and height in xy, 0 in zw + float4 PosAdjust[2] : packoffset(c1); // inverse framebuffer range in w + float4 CameraData : packoffset(c3); + float4 SunDir : packoffset(c4); + float4 SunColor : packoffset(c5); +# endif } cbuffer PerMaterial : register(b1) @@ -279,13 +348,56 @@ cbuffer PerMaterial : register(b1) cbuffer PerGeometry : register(b2) { - float4x4 TextureProj : packoffset(c0); - float4 ReflectPlane : packoffset(c4); +# if !defined(VR) + float4x4 TextureProj[1] : packoffset(c0); + float4 ReflectPlane[1] : packoffset(c4); float4 ProjData : packoffset(c5); float4 LightPos[8] : packoffset(c6); float4 LightColor[8] : packoffset(c14); +# else + float4x4 TextureProj[2] : packoffset(c0); + float4 ReflectPlane[2] : packoffset(c8); + float4 ProjData : packoffset(c10); + float4 LightPos[8] : packoffset(c11); + float4 LightColor[8] : packoffset(c19); +# endif //VR } +# ifdef VR +cbuffer VRValues : register(b13) +{ + float AlphaThreshold : packoffset(c0); + float StereoEnabled : packoffset(c0.y); + float2 EyeOffsetScale : packoffset(c0.z); + float4 EyeClipEdge[2] : packoffset(c1); +} + +float GetStencil(float2 uv) +{ + return DepthTex.Load(int3(uv * lightingData[0].BufferDim * DynamicResolutionParams1.xy, 0)).g; +} + +/** +Calculates the depthMultiplier as used in water.hlsl + +VR appears to require use of CameraProjInverse and does not use projData +@param a_uv uv coords to convert +@param a_depth The calculated depth +@param a_eyeIndex The eyeIndex; 0 is left, 1 is right +@returns depthMultiplier +*/ +float calculateDepthMultfromUV(float2 a_uv, float a_depth, uint a_eyeIndex = 0) +{ + float4 temp; + temp.xy = (a_uv * 2 - 1); + temp.z = a_depth; + temp.w = 1; + temp = mul(CameraProjInverse[a_eyeIndex], temp.xyzw); + temp.xyz /= temp.w; + return length(temp); +} +# endif // VR + # define SampColorSampler Normals01Sampler # if defined(LOD) @@ -299,9 +411,9 @@ cbuffer PerGeometry : register(b2) # if defined(SIMPLE) || defined(UNDERWATER) || defined(LOD) || defined(SPECULAR) # if defined(FLOWMAP) # if defined(WATER_CAUSTICS) -float3 GetFlowmapNormal(PS_INPUT input, float2 uvShift, float multiplier, float offset, float2 viewOffset, out float3 caustics) +float3 GetFlowmapNormal(PS_INPUT input, float2 uvShift, float multiplier, float offset, float2 viewOffset, out float3 caustics, uint a_eyeIndex) # else -float3 GetFlowmapNormal(PS_INPUT input, float2 uvShift, float multiplier, float offset) +float3 GetFlowmapNormal(PS_INPUT input, float2 uvShift, float multiplier, float offset, uint a_eyeIndex) # endif { float4 flowmapColor = FlowMapTex.Sample(FlowMapSampler, input.TexCoord2.zw + uvShift); @@ -330,9 +442,9 @@ float3 GetFlowmapNormal(PS_INPUT input, float2 uvShift, float multiplier, float # endif # if defined(WATER_CAUSTICS) -float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth, inout float3 caustics) +float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth, inout float3 caustics, uint a_eyeIndex) # else -float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth) +float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth, uint a_eyeIndex) # endif { float3 normalScalesRcp = rcp(input.NormalsScale.xyz); @@ -357,21 +469,21 @@ float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFa # if defined(WATER_CAUSTICS) float3 flowmapCaustics0; - float3 flowmapNormal0 = GetFlowmapNormal(input, uvShift.xx, 9.92, 0, viewOffset, flowmapCaustics0); + float3 flowmapNormal0 = GetFlowmapNormal(input, uvShift.xx, 9.92, 0, viewOffset, flowmapCaustics0, a_eyeIndex); float3 flowmapCaustics1; - float3 flowmapNormal1 = GetFlowmapNormal(input, float2(0, uvShift), 10.64, 0.27, viewOffset, flowmapCaustics1); + float3 flowmapNormal1 = GetFlowmapNormal(input, float2(0, uvShift), 10.64, 0.27, viewOffset, flowmapCaustics1, a_eyeIndex); float3 flowmapCaustics2; - float3 flowmapNormal2 = GetFlowmapNormal(input, 0.0.xx, 8, 0, viewOffset, flowmapCaustics2); + float3 flowmapNormal2 = GetFlowmapNormal(input, 0.0.xx, 8, 0, viewOffset, flowmapCaustics2, a_eyeIndex); float3 flowmapCaustics3; - float3 flowmapNormal3 = GetFlowmapNormal(input, float2(uvShift, 0), 8.48, 0.62, viewOffset, flowmapCaustics3); + float3 flowmapNormal3 = GetFlowmapNormal(input, float2(uvShift, 0), 8.48, 0.62, viewOffset, flowmapCaustics3, a_eyeIndex); float3 flowmapCausticsWeighted = normalMul.y * (normalMul.x * flowmapCaustics2 + (1.0 - normalMul.x) * flowmapCaustics3) + (1.0 - normalMul.y) * (normalMul.x * flowmapCaustics1 + (1.0 - normalMul.x) * flowmapCaustics0); caustics = flowmapCausticsWeighted; # else - float3 flowmapNormal0 = GetFlowmapNormal(input, uvShift.xx, 9.92, 0); - float3 flowmapNormal1 = GetFlowmapNormal(input, float2(0, uvShift), 10.64, 0.27); + float3 flowmapNormal0 = GetFlowmapNormal(input, uvShift.xx, 9.92, 0, a_eyeIndex); + float3 flowmapNormal1 = GetFlowmapNormal(input, float2(0, uvShift), 10.64, 0.27, a_eyeIndex); float3 flowmapNormal2 = GetFlowmapNormal(input, 0.0.xx, 8, 0); - float3 flowmapNormal3 = GetFlowmapNormal(input, float2(uvShift, 0), 8.48, 0.62); + float3 flowmapNormal3 = GetFlowmapNormal(input, float2(uvShift, 0), 8.48, 0.62, a_eyeIndex); # endif float2 flowmapNormalWeighted = @@ -406,7 +518,7 @@ float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFa float3 normals3 = Normals03Tex.Sample(Normals03Sampler, input.TexCoord2.xy).xyz * 2.0 - 1.0; # endif -# if defined(WATER_CAUSTICS) +# if defined(WATER_CAUSTICS) && !defined(VR) // VR disabled until caustics doesn't move float3 caustics1 = ComputeWaterCaustics(input.TexCoord1.xy + viewOffset.xy * normalScalesRcp.x); float3 caustics2 = ComputeWaterCaustics(input.TexCoord1.zw + viewOffset.xy * normalScalesRcp.y); float3 caustics3 = ComputeWaterCaustics(input.TexCoord2.xy + viewOffset.xy * normalScalesRcp.z); @@ -452,7 +564,7 @@ float3 GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFa } float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection, - float distanceFactor, float refractionsDepthFactor) + float distanceFactor, float refractionsDepthFactor, uint a_eyeIndex = 0) { float4 dynamicCubemap = 0.0; if (shaderDescriptors[0].PixelShaderDescriptor & _Reflections) { @@ -463,7 +575,11 @@ float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection float3 cubemapUV = reflect(viewDirection, WaterParams.y * normal + float3(0, 0, 1 - WaterParams.y)); # if defined(DYNAMIC_CUBEMAPS) dynamicCubemap = specularTexture.SampleLevel(CubeMapSampler, cubemapUV, 0); - reflectionColor = lerp(dynamicCubemap.xyz, CubeMapTex.SampleLevel(CubeMapSampler, cubemapUV, 0).xyz, saturate(length(input.WPosition.xyz) * 0.0001)); + reflectionColor = +# if defined(VR) // use stencil to ignore player character + GetStencil(cubemapUV.xy) == 0 ? CubeMapTex.SampleLevel(CubeMapSampler, cubemapUV, 0).xyz : +# endif + lerp(dynamicCubemap.xyz, CubeMapTex.SampleLevel(CubeMapSampler, cubemapUV, 0).xyz, saturate(length(input.WPosition.xyz) * 0.0001)); # else reflectionColor = CubeMapTex.SampleLevel(CubeMapSampler, cubemapUV, 0).xyz; # endif @@ -474,11 +590,11 @@ float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection float4 reflectionNormalRaw = float4(VarAmounts.w * normal.xy, 0, 1); # endif - float4 reflectionNormal = mul(transpose(TextureProj), reflectionNormalRaw); + float4 reflectionNormal = mul(transpose(TextureProj[a_eyeIndex]), reflectionNormalRaw); reflectionColor = ReflectionTex.SampleLevel(ReflectionSampler, reflectionNormal.xy / reflectionNormal.ww, 0).xyz; } -# if !defined(LOD) && NUM_SPECULAR_LIGHTS == 0 +# if !defined(LOD) && NUM_SPECULAR_LIGHTS == 0 && !defined(VR) if (shaderDescriptors[0].PixelShaderDescriptor & _Cubemap) { float2 ssrReflectionUv = GetDynamicResolutionAdjustedScreenPosition((DynamicResolutionParams2.xy * input.HPosition.xy) * SSRParams.zw + SSRParams2.x * normal.xy); float4 ssrReflectionColor1 = SSRReflectionTex.Sample(SSRReflectionSampler, ssrReflectionUv); @@ -497,10 +613,14 @@ float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection } # if defined(DEPTH) -float GetScreenDepthWater(float2 screenPosition) +float GetScreenDepthWater(float2 screenPosition, uint a_useVR = 0) { float depth = DepthTex.Load(float3(screenPosition, 0)).x; - return (CameraData.w / (-depth * CameraData.z + CameraData.x)); + return +# if defined(VR) // VR appears to use hard coded values + a_useVR ? depth * 1.01 + -0.01 : +# endif + (CameraData.w / (-depth * CameraData.z + CameraData.x)); } # endif @@ -528,38 +648,41 @@ float GetFresnelValue(float3 normal, float3 viewDirection) # if defined(WATER_CAUSTICS) float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, - float4 distanceMul, float refractionsDepthFactor, float fresnel, float3 caustics) + float4 distanceMul, float refractionsDepthFactor, float fresnel, float3 caustics, uint a_eyeIndex = 0) # else float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, - float4 distanceMul, float refractionsDepthFactor, float fresnel) + float4 distanceMul, float refractionsDepthFactor, float fresnel, uint a_eyeIndex = 0) # endif { # if defined(REFRACTIONS) - float4 refractionNormal = mul(transpose(TextureProj), + float4 refractionNormal = mul(transpose(TextureProj[a_eyeIndex]), float4((VarAmounts.w * refractionsDepthFactor).xx * normal.xy + input.MPosition.xy, input.MPosition.z, 1)); float2 refractionUvRaw = float2(refractionNormal.x, refractionNormal.w - refractionNormal.y) / refractionNormal.ww; + refractionUvRaw = ConvertToStereoUV(refractionUvRaw, a_eyeIndex); // need to convert here for VR due to refractionNormal values # if defined(DEPTH) && !defined(VERTEX_ALPHA_DEPTH) - float depth = GetScreenDepthWater(DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy)); - float refractionDepth = - GetScreenDepthWater(DynamicResolutionParams1.xy * (refractionUvRaw / VPOSOffset.xy)); - float refractionDepthMul = length( - float3((refractionDepth * ((VPOSOffset.zw + refractionUvRaw) * 2 - 1)) / - ProjData.xy, - refractionDepth)); + float2 screenPosition = DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy); + float depth = GetScreenDepthWater(screenPosition); + float2 refractionScreenPosition = DynamicResolutionParams1.xy * (refractionUvRaw / VPOSOffset.xy); + float refractionDepth = GetScreenDepthWater(refractionScreenPosition); +# if !defined(VR) + float refractionDepthMul = length(float3((((VPOSOffset.zw + refractionUvRaw) * 2 - 1)) * refractionDepth / ProjData.xy, refractionDepth)); +# else + float refractionDepthMul = calculateDepthMultfromUV(ConvertFromStereoUV(VPOSOffset.zw + refractionUvRaw, a_eyeIndex, 1), refractionDepth, a_eyeIndex); +# endif //VR float3 refractionDepthAdjustedViewDirection = -viewDirection * refractionDepthMul; - float refractionViewSurfaceAngle = dot(refractionDepthAdjustedViewDirection, ReflectPlane.xyz); + float refractionViewSurfaceAngle = dot(refractionDepthAdjustedViewDirection, ReflectPlane[a_eyeIndex].xyz); float refractionPlaneMul = - sign(refractionViewSurfaceAngle) * (1 - ReflectPlane.w / refractionViewSurfaceAngle); + sign(refractionViewSurfaceAngle) * (1 - ReflectPlane[a_eyeIndex].w / refractionViewSurfaceAngle); if (refractionPlaneMul < 0) { refractionUvRaw = - DynamicResolutionParams2.xy * input.HPosition.xy * VPOSOffset.xy + VPOSOffset.zw; + DynamicResolutionParams2.xy * input.HPosition.xy * VPOSOffset.xy + VPOSOffset.zw; // This value is already stereo converted for VR } # endif @@ -616,6 +739,16 @@ PS_OUTPUT main(PS_INPUT input) { PS_OUTPUT psout; +# if !defined(VR) + uint eyeIndex = 0; +# else + float4 r0, r1, r3, stereoUV; + stereoUV.xy = input.HPosition.xy * VPOSOffset.xy + VPOSOffset.zw; + stereoUV.x = DynamicResolutionParams2.x * stereoUV.x; + stereoUV.x = (stereoUV.x >= 0.5); + uint eyeIndex = (uint)(((int)((uint)StereoEnabled)) * (int)stereoUV.x); +# endif + # if defined(SIMPLE) || defined(UNDERWATER) || defined(LOD) || defined(SPECULAR) float3 viewDirection = normalize(input.WPosition.xyz); @@ -634,16 +767,21 @@ PS_OUTPUT main(PS_INPUT input) # else distanceMul = 0; - depth = GetScreenDepthWater( - DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy)); + float2 screenPosition = DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy); + + depth = GetScreenDepthWater(screenPosition); float2 depthOffset = DynamicResolutionParams2.xy * input.HPosition.xy * VPOSOffset.xy + VPOSOffset.zw; +# if !defined(VR) float depthMul = length(float3((depthOffset * 2 - 1) * depth / ProjData.xy, depth)); - +# else + float VRDepth = GetScreenDepthWater(screenPosition, 1); // VR uses special hardcoded depth for this calculation + float depthMul = calculateDepthMultfromUV(ConvertFromStereoUV(depthOffset, eyeIndex, 1), VRDepth, eyeIndex); +# endif //VR float3 depthAdjustedViewDirection = -viewDirection * depthMul; - float viewSurfaceAngle = dot(depthAdjustedViewDirection, ReflectPlane.xyz); + float viewSurfaceAngle = dot(depthAdjustedViewDirection, ReflectPlane[eyeIndex].xyz); - float planeMul = (1 - ReflectPlane.w / viewSurfaceAngle); + float planeMul = (1 - ReflectPlane[eyeIndex].w / viewSurfaceAngle); distanceMul = saturate( planeMul * float4(length(depthAdjustedViewDirection).xx, abs(viewSurfaceAngle).xx) / FogParam.z); @@ -662,9 +800,9 @@ PS_OUTPUT main(PS_INPUT input) # if defined(WATER_CAUSTICS) float3 caustics = 0.0; - float3 normal = GetWaterNormal(input, distanceFactor, depthControl.z, viewDirection, depth, caustics); + float3 normal = GetWaterNormal(input, distanceFactor, depthControl.z, viewDirection, depth, caustics, eyeIndex); # else - float3 normal = GetWaterNormal(input, distanceFactor, depthControl.z, viewDirection, depth); + float3 normal = GetWaterNormal(input, distanceFactor, depthControl.z, viewDirection, depth, eyeIndex); # endif float fresnel = GetFresnelValue(normal, viewDirection); @@ -673,7 +811,7 @@ PS_OUTPUT main(PS_INPUT input) float3 finalColor = 0.0.xxx; for (int lightIndex = 0; lightIndex < NUM_SPECULAR_LIGHTS; ++lightIndex) { - float3 lightVector = LightPos[lightIndex].xyz - (PosAdjust.xyz + input.WPosition.xyz); + float3 lightVector = LightPos[lightIndex].xyz - (PosAdjust[eyeIndex].xyz + input.WPosition.xyz, eyeIndex); float3 lightDirection = normalize(normalize(lightVector) - viewDirection); float lightFade = saturate(length(lightVector) / LightPos[lightIndex].w); float lightColorMul = (1 - lightFade * lightFade); @@ -687,18 +825,17 @@ PS_OUTPUT main(PS_INPUT input) isSpecular = true; # else - float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, depthControl.y); + float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, depthControl.y, eyeIndex); # if defined(WATER_CAUSTICS) - float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, caustics); + float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, caustics, eyeIndex); # else - float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel); + float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, eyeIndex); # endif float3 specularLighting = 0; # if defined(LIGHT_LIMIT_FIX) - uint eyeIndex = 0; uint lightCount = 0; float3 viewPosition = mul(CameraView[eyeIndex], float4(input.WPosition.xyz, 1)).xyz; @@ -744,26 +881,21 @@ PS_OUTPUT main(PS_INPUT input) # endif # endif - psout.Lighting = saturate(float4(finalColor * PosAdjust.w, isSpecular)); + psout.Lighting = saturate(float4(finalColor * PosAdjust[eyeIndex].w, isSpecular)); # if defined(WATER_BLENDING) # if defined(DEPTH) if (perPassWaterBlending[0].EnableWaterBlending) { + float2 screenPosition = DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy); # if defined(VERTEX_ALPHA_DEPTH) && defined(VC) float blendFactor = 1 - smoothstep(0.0, 0.025 * perPassWaterBlending[0].WaterBlendRange, input.TexCoord3.z); - if (blendFactor > 0.0) { - float4 background = RefractionTex.Load(float3(DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy), 0)); - psout.Lighting.xyz = lerp(psout.Lighting.xyz, background.xyz, blendFactor); - psout.Lighting.w = lerp(psout.Lighting.w, background.w, blendFactor); - } # else float blendFactor = 1 - smoothstep(0.0, 0.025 * perPassWaterBlending[0].WaterBlendRange, distanceMul.z); - +# endif // defined(VERTEX_ALPHA_DEPTH) && defined(VC) if (blendFactor > 0.0) { - float4 background = RefractionTex.Load(float3(DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy), 0)); + float4 background = RefractionTex.Load(float3(screenPosition, 0)); psout.Lighting.xyz = lerp(psout.Lighting.xyz, background.xyz, blendFactor); psout.Lighting.w = lerp(psout.Lighting.w, background.w, blendFactor); } -# endif } # endif # endif diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 78d308604..1f2a72fa1 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -1004,9 +1004,9 @@ bool LightLimitFix::HasShaderDefine(RE::BSShader::Type shaderType) switch (shaderType) { case RE::BSShader::Type::Lighting: case RE::BSShader::Type::Grass: + case RE::BSShader::Type::Water: return true; case RE::BSShader::Type::Effect: - case RE::BSShader::Type::Water: return !REL::Module::IsVR(); default: return false; diff --git a/src/Features/WaterBlending.h b/src/Features/WaterBlending.h index f2879739f..28ca12641 100644 --- a/src/Features/WaterBlending.h +++ b/src/Features/WaterBlending.h @@ -47,4 +47,5 @@ struct WaterBlending : Feature virtual void Save(json& o_json); virtual void RestoreDefaultSettings(); + bool SupportsVR() override { return true; }; }; diff --git a/src/Features/WaterParallax.h b/src/Features/WaterParallax.h index 205190a4c..d1cf6cf7a 100644 --- a/src/Features/WaterParallax.h +++ b/src/Features/WaterParallax.h @@ -42,4 +42,5 @@ struct WaterParallax : Feature virtual void Save(json& o_json); virtual void RestoreDefaultSettings(); + bool SupportsVR() override { return true; }; }; diff --git a/src/ShaderCache.h b/src/ShaderCache.h index f9e6b5c0f..220152dab 100644 --- a/src/ShaderCache.h +++ b/src/ShaderCache.h @@ -115,6 +115,7 @@ namespace SIE type == RE::BSShader::Type::Water || type == RE::BSShader::Type::Effect; return type == RE::BSShader::Type::Lighting || + type == RE::BSShader::Type::Water || type == RE::BSShader::Type::Grass; }