summaryrefslogtreecommitdiff
path: root/sample/d3d11/ocean_surface.fx
diff options
context:
space:
mode:
Diffstat (limited to 'sample/d3d11/ocean_surface.fx')
-rw-r--r--sample/d3d11/ocean_surface.fx791
1 files changed, 791 insertions, 0 deletions
diff --git a/sample/d3d11/ocean_surface.fx b/sample/d3d11/ocean_surface.fx
new file mode 100644
index 0000000..c34c65e
--- /dev/null
+++ b/sample/d3d11/ocean_surface.fx
@@ -0,0 +1,791 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#define GFSDK_WAVEWORKS_SM5
+#define GFSDK_WAVEWORKS_USE_TESSELLATION
+
+#define GFSDK_WAVEWORKS_DECLARE_GEOM_VS_CONSTANT(Type,Label,Regoff) Type Label;
+#define GFSDK_WAVEWORKS_BEGIN_GEOM_VS_CBUFFER(Label) cbuffer Label {
+#define GFSDK_WAVEWORKS_END_GEOM_VS_CBUFFER };
+
+#define GFSDK_WAVEWORKS_DECLARE_GEOM_HS_CONSTANT(Type,Label,Regoff) Type Label;
+#define GFSDK_WAVEWORKS_BEGIN_GEOM_HS_CBUFFER(Label) cbuffer Label {
+#define GFSDK_WAVEWORKS_END_GEOM_HS_CBUFFER };
+
+#include "GFSDK_WaveWorks_Quadtree.fxh"
+
+#define GFSDK_WAVEWORKS_DECLARE_ATTR_DS_CONSTANT(Type,Label,Regoff) Type Label;
+#define GFSDK_WAVEWORKS_BEGIN_ATTR_DS_CBUFFER(Label) cbuffer Label {
+#define GFSDK_WAVEWORKS_END_ATTR_DS_CBUFFER };
+#define GFSDK_WAVEWORKS_DECLARE_ATTR_DS_SAMPLER(Label,TextureLabel,Regoff) sampler Label; texture2D TextureLabel;
+
+#define GFSDK_WAVEWORKS_DECLARE_ATTR_PS_CONSTANT(Type,Label,Regoff) Type Label;
+#define GFSDK_WAVEWORKS_BEGIN_ATTR_PS_CBUFFER(Label) cbuffer Label {
+#define GFSDK_WAVEWORKS_END_ATTR_PS_CBUFFER };
+#define GFSDK_WAVEWORKS_DECLARE_ATTR_PS_SAMPLER(Label,TextureLabel,Regoff) sampler Label; texture2D TextureLabel;
+
+#include "GFSDK_WaveWorks_Attributes.fxh"
+#include "common.fx"
+
+//------------------------------------------------------------------------------------
+// Global variables
+//------------------------------------------------------------------------------------
+
+// Constant
+
+float3 g_LightPosition;
+float3 g_CameraPosition;
+float4x4 g_ModelViewMatrix;
+float4x4 g_ModelViewProjectionMatrix;
+float4x4 g_LightModelViewProjectionMatrix;
+float4x4 g_WorldToTopDownTextureMatrix;
+
+float3 g_WaterTransmittance = {0.065,0.028,0.035}; // light absorption per meter for coastal water, taken from here: http://www.seafriends.org.nz/phgraph/water.htm http://www.seafriends.org.nz/phgraph/phdwg34.gif
+float3 g_WaterScatterColor = {0.0,0.7,0.3};
+float3 g_WaterSpecularColor = {1.1,0.8,0.5};
+float g_WaterScatterIntensity = 0.1;
+float g_WaterSpecularIntensity = 10.0f;
+
+float3 g_FoamColor = {0.90f, 0.95f, 1.0f};
+float3 g_FoamUnderwaterColor = {0.0,0.7,0.6};
+
+float g_WaterSpecularPower = 200.0;
+float3 g_AtmosphereBrightColor = {1.1,0.9,0.6};
+float3 g_AtmosphereDarkColor = {0.4,0.4,0.5};
+float g_FogDensity = 1.0f/1500.0f;
+
+float4 g_WireframeColor = {1.0,1.0,1.0,1.0};
+
+float2 g_WindDirection;
+
+float2 g_ScreenSizeInv;
+float g_ZNear;
+float g_ZFar;
+float g_Time;
+
+float g_GerstnerSteepness;
+float g_BaseGerstnerAmplitude;
+float g_BaseGerstnerWavelength;
+float g_BaseGerstnerSpeed;
+float g_BaseGerstnerParallelness;
+float g_enableShoreEffects;
+
+float g_Wireframe;
+float2 g_WinSize = {1920.0,1080.0};
+
+//-----------------------------------------------------------------------------------
+// Texture & Samplers
+//-----------------------------------------------------------------------------------
+texture2D g_LogoTexture;
+Texture2D g_ReflectionTexture;
+Texture2D g_RefractionTexture;
+Texture2D g_RefractionDepthTextureResolved;
+Texture2D g_WaterNormalMapTexture;
+Texture2D g_ShadowmapTexture;
+Texture2D g_FoamIntensityTexture;
+Texture2D g_FoamDiffuseTexture;
+Texture2D g_DataTexture;
+
+// Custom trilinear sampler clamping to custom border color
+sampler SamplerTrilinearBorder =
+sampler_state
+{
+ Filter = MIN_MAG_MIP_LINEAR;
+ AddressU = Border;
+ AddressV = Border;
+ BorderColor = float4(20.0,-50.0,0.0,0.0);
+};
+
+struct VS_OUTPUT
+{
+ float4 worldspace_position : VSO ;
+};
+
+struct DS_OUTPUT
+{
+ float4 positionClip : SV_Position;
+ GFSDK_WAVEWORKS_INTERPOLATED_VERTEX_OUTPUT NV_ocean_interp;
+ float3 displacementWS: TEXCOORD5;
+ float3 positionWS: TEXCOORD6;
+ float3 world_pos_undisplaced : TEXCOORD7;
+ float3 gerstner_displacement : TEXCOORD8;
+ float2 gerstner_sdfUV : TEXCOORD9;
+ float gerstner_multiplier : TEXCOORD10;
+};
+
+struct PS_INPUT
+{
+ float4 positionClip : SV_Position;
+ GFSDK_WAVEWORKS_INTERPOLATED_VERTEX_OUTPUT NV_ocean_interp;
+ float3 displacementWS: TEXCOORD5;
+ float3 positionWS: TEXCOORD6;
+ float3 world_pos_undisplaced : TEXCOORD7;
+ float3 gerstner_displacement : TEXCOORD8;
+ float2 gerstner_sdfUV : TEXCOORD9;
+ float gerstner_multiplier : TEXCOORD10;
+ noperspective float3 v_dist : TEXCOORD11;
+};
+
+struct HS_ConstantOutput
+{
+ float fTessFactor[3] : SV_TessFactor;
+ float fInsideTessFactor : SV_InsideTessFactor;
+};
+
+
+
+static const float kTopDownDataPixelsPerMeter = 256.0f/700.0; // taken from SDF generation source code, the SDF texture size is 256x256, the viewport size is 700x700
+static const float kMaxDepthBelowSea = 50.0f;
+static const float kMaxDistance = 20.0f; // taken from SDF generation code
+static const float kNumWaves = 1.0; // Total number of Gerster waves of different amplitude, speed etc to calculate,
+ // i+1-th wave has 20% smaller amplitude,
+ // 20% smaller phase and group speed and 20% less parallelity
+ // Note that all the waves will share the same gerstnerMultiplierOut (lerping between ocean waves and Gerstner waves) for simplicity
+
+void GetGerstnerVertexAttributes(float3 posWS, out float2 sdfUVOut, out float3 offsetOut, out float gerstnerMultiplierOut)
+{
+ // getting UV for fetching SDF texture
+ float4 topDownPosition = mul( float4( posWS.xyz, 1), g_WorldToTopDownTextureMatrix );
+ float2 uv = mad( topDownPosition.xy/topDownPosition.w, 0.5f, 0.5f );
+ uv.y = 1-uv.y;
+
+ // initializing the outputs so we can exit early
+ sdfUVOut = uv;
+ offsetOut = float3 (0.0,0.0,0.0);
+ gerstnerMultiplierOut = 0;
+
+ // getting SDF
+ const float4 tdData = g_DataTexture.SampleLevel(SamplerTrilinearBorder, uv, 0 );
+
+ // early out without adding gerstner waves if far from shore
+ if((tdData.x >= kMaxDistance - 0.1))
+ {
+ return;
+ }
+
+ // initializing variables common to all Gerstner waves
+ float phaseShift = g_Time;
+ float sdfPhase = tdData.x*kMaxDistance/kTopDownDataPixelsPerMeter;
+ float distanceMultiplier = saturate(1.0-tdData.x); // Shore waves linearly fade in on the edges of SDF
+ float depthMultiplier = saturate((g_BaseGerstnerWavelength*0.5 + tdData.y)*0.5); // Shore waves fade in when depth is less than half the wave length, we use 0.25 as this parameter also allows shore waves to heighten as the depth decreases
+ gerstnerMultiplierOut = distanceMultiplier*depthMultiplier;
+
+ // initializing variables to be changed along summing up the waves
+ float gerstnerWavelength = g_BaseGerstnerWavelength;
+ float gerstnerOmega = 2.0*3.141592 / g_BaseGerstnerWavelength; // angular speed of gerstner wave
+ float gerstnerParallelness = g_BaseGerstnerParallelness; // "parallelness" of shore waves. 0 means the waves are parallel to shore, 1 means the waves are parallel to wind gradient
+ float gerstnerSpeed = g_BaseGerstnerSpeed; // phase speed of gerstner waves
+ float gerstnerAmplitude = g_BaseGerstnerAmplitude;
+ float2 windDirection = g_WindDirection;
+
+ // summing up the waves
+ for(float i = 0.0; i < kNumWaves; i+=1.0)
+ {
+ float windPhase = dot(windDirection, posWS.xz);
+ float gerstnerPhase = 2.0*3.141592*(lerp( sdfPhase, windPhase, gerstnerParallelness)/gerstnerWavelength);
+ float2 propagationDirection = normalize( lerp(-tdData.zw + windDirection * 0.000001f, g_WindDirection, gerstnerParallelness*gerstnerParallelness));
+ float gerstnerGroupSpeedPhase = 2.0*3.141592*(lerp( sdfPhase, windPhase, gerstnerParallelness*3.0)/gerstnerWavelength); // letting the group speed phase to be non-parallel to propagation phase, so altering parallelness modificator fot this
+
+ float groupSpeedMultiplier = 0.5 + 0.5*cos((gerstnerGroupSpeedPhase + gerstnerOmega*gerstnerSpeed*phaseShift/2.0)/2.7); // Group speed for water waves is half of the phase speed, we allow 2.7 wavelengths to be in wave group, not so much as breaking shore waves lose energy quickly
+ float worldSpacePosMultiplier = 0.75 + 0.25*sin(phaseShift*0.3 + 0.5*posWS.x/gerstnerWavelength)*sin(phaseShift*0.4 + 0.5*posWS.y/gerstnerWavelength); // slowly crawling worldspace aligned checkerboard pattern that damps gerstner waves further
+ float depthMultiplier = saturate((gerstnerWavelength*0.5 + tdData.y)*0.5); // Shore waves fade in when depth is less than half the wave length
+ float gerstnerMultiplier = distanceMultiplier*depthMultiplier*groupSpeedMultiplier*worldSpacePosMultiplier; // final scale factor applied to base Gerstner amplitude and used to mix between ocean waves and shore waves
+
+ float steepness = g_GerstnerSteepness;
+ float baseAmplitude = gerstnerMultiplier * gerstnerAmplitude; //amplitude gradually increases as wave runs over shallower seabed
+ float breakerMultiplier = saturate((baseAmplitude*2.0*1.28 + tdData.y)/gerstnerAmplitude); // Wave height is 2*amplitude, a wave will start to break when it approximately reaches a water depth of 1.28 times the wave height, empirically: http://passyworldofmathematics.com/mathematics-of-ocean-waves-and-surfing/
+
+ // calculating Gerstner offset
+ float s,c;
+ sincos(gerstnerPhase + gerstnerOmega*gerstnerSpeed*phaseShift, s, c);
+ float waveVerticalOffset = s * baseAmplitude;
+ offsetOut.y += waveVerticalOffset;
+ offsetOut.xz += c * propagationDirection * steepness * baseAmplitude; // trochoidal Gerstner wave
+ offsetOut.xz -= propagationDirection * s * baseAmplitude * breakerMultiplier * 2.0; // adding wave forward skew due to its bottom slowing down, so the forward wave front gradually becomes vertical
+ float breakerPhase = gerstnerPhase + gerstnerOmega*gerstnerSpeed*phaseShift + 3.141592*0.05;
+ float fp = frac(breakerPhase/(3.141592*2.0));
+ offsetOut.xz -= 0.5*baseAmplitude*propagationDirection*breakerMultiplier*(saturate(fp*10.0) - saturate(-1.0 + fp*10.0)); // moving breaking area of the wave further forward
+
+ // updating the parameters for next wave
+ gerstnerWavelength *= 0.66;
+ gerstnerOmega /= 0.66;
+ gerstnerSpeed *= 0.66;
+ gerstnerAmplitude *= 0.66;
+ gerstnerParallelness *= 0.66;
+ windDirection.xy *= float2(-1.0,1.0)*windDirection.yx; // rotating wind direction
+
+ offsetOut.y += baseAmplitude*1.2; // Adding vertical displacement as the wave increases while rolling on the shallow area
+ }
+
+}
+
+void GetGerstnerSurfaceAttributes( float2 sdfUV, float2 posWS, out float3 normalOut, out float breakerOut, out float foamTrailOut)
+{
+ // initializing the outputs
+ normalOut = float3 (0.0,1.0,0.0);
+ foamTrailOut = 0.0;
+ breakerOut = 0.0;
+
+ // getting SDF
+ const float4 tdData = g_DataTexture.SampleLevel(SamplerTrilinearBorder, sdfUV, 0 );
+
+ // initializing variables common to all Gerstner waves
+ float phaseShift = g_Time;
+ float sdfPhase = tdData.x*kMaxDistance/kTopDownDataPixelsPerMeter;
+ float distanceMultiplier = saturate(1.0-tdData.x); // Shore waves linearly fade in on the edges of SDF
+
+ // initializing variables to be changed along summing up the waves
+ float gerstnerWavelength = g_BaseGerstnerWavelength;
+ float gerstnerOmega = 2.0*3.141592 / g_BaseGerstnerWavelength; // angular speed of gerstner wave
+ float gerstnerParallelness = g_BaseGerstnerParallelness; // "parallelness" of shore waves. 0 means the waves are parallel to shore, 1 means the waves are parallel to wind gradient
+ float gerstnerSpeed = g_BaseGerstnerSpeed; // phase speed of gerstner waves
+ float gerstnerAmplitude = g_BaseGerstnerAmplitude;
+ float2 windDirection = g_WindDirection;
+
+ // summing up the waves
+ for(float i = 0.0; i < kNumWaves; i+=1.0)
+ {
+ float windPhase = dot(windDirection, posWS.xy);
+ float gerstnerPhase = 2.0*3.141592*(lerp( sdfPhase, windPhase, gerstnerParallelness)/gerstnerWavelength);
+ float2 propagationDirection = normalize( lerp(-tdData.zw + windDirection * 0.000001f, g_WindDirection, gerstnerParallelness*gerstnerParallelness));
+ float gerstnerGroupSpeedPhase = 2.0*3.141592*(lerp( sdfPhase, windPhase, gerstnerParallelness*3.0)/gerstnerWavelength); // letting the group speed phase to be non-parallel to propagation phase, so altering parallelness modificator fot this
+
+ float groupSpeedMultiplier = 0.5 + 0.5*cos((gerstnerGroupSpeedPhase + gerstnerOmega*gerstnerSpeed*phaseShift/2.0)/2.7); // Group speed for water waves is half of the phase speed, we allow 2.7 wavelengths to be in wave group, not so much as breaking shore waves lose energy quickly
+ float worldSpacePosMultiplier = 0.75 + 0.25*sin(phaseShift*0.3 + 0.5*posWS.x/gerstnerWavelength)*sin(phaseShift*0.4 + 0.5*posWS.y/gerstnerWavelength); // slowly crawling worldspace aligned checkerboard pattern that damps gerstner waves further
+ float depthMultiplier = saturate((gerstnerWavelength*0.5 + tdData.y)*0.5); // Shore waves fade in when depth is less than half the wave length
+ float gerstnerMultiplier = distanceMultiplier*depthMultiplier*groupSpeedMultiplier*worldSpacePosMultiplier; // final scale factor applied to base Gerstner amplitude and used to mix between ocean waves and shore waves
+
+ float steepness = g_GerstnerSteepness;
+ float baseAmplitude = gerstnerMultiplier * gerstnerAmplitude; //amplitude gradually increases as wave runs over shallower seabed
+
+ // calculating normal
+ float s,c;
+ sincos(gerstnerPhase + gerstnerOmega*gerstnerSpeed*phaseShift, s, c);
+ normalOut.y -= gerstnerOmega*steepness*baseAmplitude*s;
+ normalOut.xz -= gerstnerOmega*baseAmplitude*c*propagationDirection; // orienting normal according to direction of wave propagation. No need to normalize, it is unit length.
+
+ // calculating foam parameters
+ float breakerMultiplier = saturate((baseAmplitude*2.0*1.28 + tdData.y)/gerstnerAmplitude); // Wave height is 2*amplitude, a wave will start to break when it approximately reaches a water depth of 1.28 times the wave height, empirically: http://passyworldofmathematics.com/mathematics-of-ocean-waves-and-surfing/
+
+ float foamTrailPhase = gerstnerPhase + gerstnerOmega*gerstnerSpeed*phaseShift + 3.141592*0.05; // delaying foam trail a bit so it's following the breaker
+ float fp = frac(foamTrailPhase/(3.141592*2.0));
+ foamTrailOut += gerstnerMultiplier*breakerMultiplier*(saturate(fp*10.0) - saturate(fp*1.1)); // only breaking waves leave foamy trails
+ breakerOut += gerstnerMultiplier*breakerMultiplier*(saturate(fp*10.0) - saturate(-1.0 + fp*10.0)); // making narrow sawtooth pattern
+
+ // updating the parameters for next wave
+ gerstnerWavelength *= 0.66;
+ gerstnerOmega /= 0.66;
+ gerstnerSpeed *= 0.66;
+ gerstnerAmplitude *= 0.66;
+ gerstnerParallelness *= 0.66;
+ windDirection.xy *= float2(-1.0,1.0)*windDirection.yx; // rotating wind direction
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Name: OceanWaveVS
+// Type: Vertex shader
+// Desc:
+//-----------------------------------------------------------------------------
+VS_OUTPUT OceanWaveVS(GFSDK_WAVEWORKS_VERTEX_INPUT In)
+{
+ VS_OUTPUT Output;
+ Output.worldspace_position = float4(GFSDK_WaveWorks_GetUndisplacedVertexWorldPosition(In),0.0);
+ return Output;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: HS_Constant
+// Type: Hull shader
+// Desc:
+//-----------------------------------------------------------------------------
+HS_ConstantOutput HS_Constant( InputPatch<VS_OUTPUT, 3> I )
+{
+ HS_ConstantOutput O;
+ O.fTessFactor[0] = GFSDK_WaveWorks_GetEdgeTessellationFactor(I[1].worldspace_position,I[2].worldspace_position);
+ O.fTessFactor[1] = GFSDK_WaveWorks_GetEdgeTessellationFactor(I[2].worldspace_position,I[0].worldspace_position);
+ O.fTessFactor[2] = GFSDK_WaveWorks_GetEdgeTessellationFactor(I[0].worldspace_position,I[1].worldspace_position);
+ O.fInsideTessFactor = (O.fTessFactor[0] + O.fTessFactor[1] + O.fTessFactor[2])/3.0f;
+ return O;
+}
+
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_cw")]
+[patchconstantfunc("HS_Constant")]
+[outputcontrolpoints(3)]
+VS_OUTPUT HS_FlatTriangles( InputPatch<VS_OUTPUT, 3> I, uint uCPID : SV_OutputControlPointID )
+{
+ VS_OUTPUT O = (VS_OUTPUT)I[uCPID];
+ return O;
+}
+
+//--------------------------------------------------------------------------------------
+// This domain shader applies contol point weighting to the barycentric coords produced by the FF tessellator
+//--------------------------------------------------------------------------------------
+[domain("tri")]
+DS_OUTPUT DS_FlatTriangles_Shore( HS_ConstantOutput HSConstantData, const OutputPatch<VS_OUTPUT, 3> I, float3 f3BarycentricCoords : SV_DomainLocation )
+{
+ DS_OUTPUT Output = (DS_OUTPUT)0;
+
+ GFSDK_WAVEWORKS_VERTEX_OUTPUT NV_ocean = GFSDK_WaveWorks_GetDisplacedVertexAfterTessellation(I[0].worldspace_position, I[1].worldspace_position, I[2].worldspace_position, f3BarycentricCoords);
+
+ float3 gerstnerDisplacement = float3(0,0,0);
+ float2 sdfUV = float2(0,0);
+ float gerstnerMultiplier = 0;
+
+ if(g_enableShoreEffects > 0)
+ {
+ GetGerstnerVertexAttributes(NV_ocean.pos_world_undisplaced.xzy, sdfUV, gerstnerDisplacement, gerstnerMultiplier);
+ }
+
+ NV_ocean.world_displacement *= 1.0 - 0.7*gerstnerMultiplier;
+ NV_ocean.world_displacement += gerstnerDisplacement.xzy*gerstnerMultiplier;
+
+ NV_ocean.pos_world = NV_ocean.pos_world_undisplaced + NV_ocean.world_displacement;
+ Output.positionWS = NV_ocean.pos_world;
+ Output.displacementWS = NV_ocean.world_displacement;
+ Output.positionClip = mul(float4(NV_ocean.pos_world,1.0), g_ModelViewProjectionMatrix);
+ Output.world_pos_undisplaced = NV_ocean.pos_world_undisplaced;
+ Output.gerstner_displacement = gerstnerDisplacement.xzy;
+ Output.gerstner_sdfUV = sdfUV;
+ Output.gerstner_multiplier = gerstnerMultiplier;
+ Output.NV_ocean_interp = NV_ocean.interp;
+
+ return Output;
+}
+
+//--------------------------------------------------------------------------------------
+// This geometry shader enables solid wireframe mode
+//--------------------------------------------------------------------------------------
+[maxvertexcount(3)]
+void GSSolidWire( triangle DS_OUTPUT input[3], inout TriangleStream<PS_INPUT> outStream )
+{
+ PS_INPUT output;
+
+ float2 p0 = g_WinSize * input[0].positionClip.xy/input[0].positionClip.w;
+ float2 p1 = g_WinSize * input[1].positionClip.xy/input[1].positionClip.w;
+ float2 p2 = g_WinSize * input[2].positionClip.xy/input[2].positionClip.w;
+ float2 v0 = p2 - p1;
+ float2 v1 = p2 - p0;
+ float2 v2 = p1 - p0;
+ float area = abs(v1.x*v2.y - v1.y * v2.x);
+
+
+
+ // Generate vertices
+ output.positionClip = input[0].positionClip;
+ output.NV_ocean_interp = input[0].NV_ocean_interp;
+ output.displacementWS = input[0].displacementWS;
+ output.positionWS = input[0].positionWS;
+ output.world_pos_undisplaced = input[0].world_pos_undisplaced;
+ output.gerstner_displacement = input[0].gerstner_displacement;
+ output.gerstner_sdfUV = input[0].gerstner_sdfUV;
+ output.gerstner_multiplier = input[0].gerstner_multiplier;
+ output.v_dist = float3(area/length(v0),0,0);
+ outStream.Append( output );
+
+ output.positionClip = input[1].positionClip;
+ output.NV_ocean_interp = input[1].NV_ocean_interp;
+ output.displacementWS = input[1].displacementWS;
+ output.positionWS = input[1].positionWS;
+ output.world_pos_undisplaced = input[1].world_pos_undisplaced;
+ output.gerstner_displacement = input[1].gerstner_displacement;
+ output.gerstner_sdfUV = input[1].gerstner_sdfUV;
+ output.gerstner_multiplier = input[1].gerstner_multiplier;
+ output.v_dist = float3(0,area/length(v1),0);
+ outStream.Append( output );
+
+ output.positionClip = input[2].positionClip;
+ output.NV_ocean_interp = input[2].NV_ocean_interp;
+ output.displacementWS = input[2].displacementWS;
+ output.positionWS = input[2].positionWS;
+ output.world_pos_undisplaced = input[2].world_pos_undisplaced;
+ output.gerstner_displacement = input[2].gerstner_displacement;
+ output.gerstner_sdfUV = input[2].gerstner_sdfUV;
+ output.gerstner_multiplier = input[2].gerstner_multiplier;
+ output.v_dist = float3(0,0,area/length(v2));
+ outStream.Append( output );
+
+ outStream.RestartStrip();
+}
+
+float GetRefractionDepth(float2 position)
+{
+ return g_RefractionDepthTextureResolved.SampleLevel(SamplerLinearClamp,position,0).r;
+}
+
+// primitive simulation of non-uniform atmospheric fog
+float3 CalculateFogColor(float3 pixel_to_light_vector, float3 pixel_to_eye_vector)
+{
+ return lerp(g_AtmosphereDarkColor,g_AtmosphereBrightColor,0.5*dot(pixel_to_light_vector,-pixel_to_eye_vector)+0.5);
+}
+
+//-----------------------------------------------------------------------------
+// Name: OceanWaveShorePS
+// Type: Pixel shader
+// Desc:
+//-----------------------------------------------------------------------------
+float4 OceanWaveShorePS(PS_INPUT In) : SV_Target
+{
+ float3 color;
+ float3 normal;
+ float fresnel_factor;
+ float specular_factor;
+ float scatter_factor;
+ float3 refraction_color;
+ float3 reflection_color;
+ float4 disturbance_eyespace;
+
+
+ float water_depth;
+
+ float3 water_vertex_positionWS = In.positionWS.xzy;
+
+ float3 pixel_to_light_vector = normalize(g_LightPosition-water_vertex_positionWS);
+ float3 pixel_to_eye_vector = normalize(g_CameraPosition-water_vertex_positionWS);
+
+ GFSDK_WAVEWORKS_SURFACE_ATTRIBUTES surface_attributes = GFSDK_WaveWorks_GetSurfaceAttributes(In.NV_ocean_interp);
+
+ float3 gerstner_normal = float3(0.0,1.0,0.0);
+ float gerstner_breaker = 0;
+ float gerstner_foamtrail = 0;
+
+ if(g_enableShoreEffects > 0)
+ {
+ if(In.gerstner_multiplier > 0)
+ {
+ GetGerstnerSurfaceAttributes( In.gerstner_sdfUV, In.world_pos_undisplaced.xy, gerstner_normal, gerstner_breaker, gerstner_foamtrail);
+ }
+ surface_attributes.normal = lerp(float3(0,1,0),surface_attributes.normal.xzy, 1.0-0.9*In.gerstner_multiplier*In.gerstner_multiplier); // Leaving just 10% of original open ocean normals in areas affected by shore waves
+ surface_attributes.foam_turbulent_energy += gerstner_foamtrail*3.0;
+ surface_attributes.foam_wave_hats += gerstner_breaker*15.0; // 15.0*breaker so the breaker foam has rough edges
+
+ // using PD normal combination
+ normal = normalize(float3(surface_attributes.normal.xz*gerstner_normal.y + gerstner_normal.xz*surface_attributes.normal.y, surface_attributes.normal.y*gerstner_normal.y));
+ normal = normal.xzy;
+ }
+ else
+ {
+ normal = surface_attributes.normal.xzy;
+ }
+
+ float3 reflected_eye_to_pixel_vector=-pixel_to_eye_vector+2*dot(pixel_to_eye_vector,normal)*normal;
+
+ // calculating pixel position in light space
+ float4 positionLS = mul(float4(water_vertex_positionWS,1),g_LightModelViewProjectionMatrix);
+ positionLS.xyz/=positionLS.w;
+ positionLS.x=(positionLS.x+1)*0.5;
+ positionLS.y=(1-positionLS.y)*0.5;
+ positionLS.z = min(0.99,positionLS.z);
+
+ // calculating shadow multiplier to be applied to diffuse/scatter/specular light components
+ float shadow_factor = g_ShadowmapTexture.SampleCmp(SamplerDepthAnisotropic,positionLS.xy,positionLS.z* 0.995f).r;
+
+ // simulating scattering/double refraction: light hits the side of wave, travels some distance in water, and leaves wave on the other side
+ // it's difficult to do it physically correct without photon mapping/ray tracing, so using simple but plausible emulation below
+
+ // only the crests of water waves generate double refracted light
+ scatter_factor = g_WaterScatterIntensity*
+ // the waves that lie between camera and light projection on water plane generate maximal amount of double refracted light
+ pow(max(0.0,dot(normalize(float3(pixel_to_light_vector.x,0.0,pixel_to_light_vector.z)),-pixel_to_eye_vector)),2.0)*
+ // the slopes of waves that are oriented back to light generate maximal amount of double refracted light
+ shadow_factor*pow(max(0.0,1.0-dot(pixel_to_light_vector,normal)),2.0);
+
+ scatter_factor += g_WaterScatterIntensity*
+ // the scattered light is best seen if observing direction is normal to slope surface
+ max(0,dot(pixel_to_eye_vector,normal));//*
+
+ // calculating fresnel factor
+ float r=(1.0 - 1.33)*(1.0 - 1.33)/((1.0 + 1.33)*(1.0 + 1.33));
+ fresnel_factor = r + (1.0-r)*pow(saturate(1.0 - dot(normal,pixel_to_eye_vector)),5.0);
+
+
+ // calculating specular factor
+ specular_factor=shadow_factor*pow(max(0,dot(pixel_to_light_vector,reflected_eye_to_pixel_vector)),g_WaterSpecularPower);
+
+ // calculating disturbance which has to be applied to planar reflections/refractions to give plausible results
+ disturbance_eyespace=mul(float4(normal.x,normal.z,0,0),g_ModelViewMatrix);
+
+ float2 reflection_disturbance = float2(disturbance_eyespace.x,disturbance_eyespace.z)*0.06;
+ float2 refraction_disturbance = float2(-disturbance_eyespace.x,disturbance_eyespace.y)*0.9*
+ // fading out refraction disturbance at distance so refraction doesn't look noisy at distance
+ (100.0/(100+length(g_CameraPosition-water_vertex_positionWS)));
+
+ // picking refraction depth at non-displaced point, need it to scale the refraction texture displacement amount according to water depth
+ float refraction_depth = GetRefractionDepth(In.positionClip.xy*g_ScreenSizeInv);
+ refraction_depth = g_ZFar*g_ZNear / (g_ZFar-refraction_depth*(g_ZFar-g_ZNear));
+ float4 vertex_in_viewspace = mul(float4(In.positionWS.xyz,1),g_ModelViewMatrix);
+ water_depth = refraction_depth-vertex_in_viewspace.z;
+
+ if(water_depth < 0)
+ {
+ refraction_disturbance = 0;
+ }
+ water_depth = max(0,water_depth);
+ refraction_disturbance *= min(1.0f,water_depth*0.03);
+
+ // getting refraction depth again, at displaced point now
+ refraction_depth = GetRefractionDepth(In.positionClip.xy*g_ScreenSizeInv+refraction_disturbance);
+ refraction_depth = g_ZFar*g_ZNear / (g_ZFar-refraction_depth*(g_ZFar-g_ZNear));
+ vertex_in_viewspace= mul(float4(In.positionWS.xyz,1),g_ModelViewMatrix);
+ water_depth = max(water_depth,refraction_depth-vertex_in_viewspace.z);
+ water_depth = max(0,water_depth);
+ float depth_damper = min(1,water_depth*3.0);
+ float depth_damper_sss = min(1,water_depth*0.5);
+
+ // getting reflection and refraction color at disturbed texture coordinates
+ reflection_color = g_ReflectionTexture.SampleLevel(SamplerLinearClamp,float2(In.positionClip.x*g_ScreenSizeInv.x,1.0-In.positionClip.y*g_ScreenSizeInv.y)+reflection_disturbance,0).rgb;
+ refraction_color = g_RefractionTexture.SampleLevel(SamplerLinearClamp,In.positionClip.xy*g_ScreenSizeInv+refraction_disturbance,0).rgb;
+
+ // fading fresnel factor to 0 to soften water surface edges
+ fresnel_factor*=depth_damper;
+
+ // fading fresnel factor to 0 for rays that reflect below water surface
+ fresnel_factor*= 1.0 - 1.0*saturate(-2.0*reflected_eye_to_pixel_vector.y);
+
+ // applying water absorbtion according to distance that refracted ray travels in water
+ // note that we multiply this by 2 since light travels through water twice: from light to seafloor then from seafloor back to eye
+ refraction_color.r *= exp(-1.0*water_depth*2.0*g_WaterTransmittance.r);
+ refraction_color.g *= exp(-1.0*water_depth*2.0*g_WaterTransmittance.g);
+ refraction_color.b *= exp(-1.0*water_depth*2.0*g_WaterTransmittance.b);
+
+ // applying water scatter factor
+ refraction_color += scatter_factor*shadow_factor*g_WaterScatterColor*depth_damper_sss;
+
+ // adding milkiness due to mixed-in foam
+ refraction_color += g_FoamUnderwaterColor*saturate(surface_attributes.foam_turbulent_energy*0.2)*depth_damper_sss;
+
+ // combining final water color
+ color = lerp(refraction_color, reflection_color, fresnel_factor);
+ // adding specular
+ color.rgb += specular_factor*g_WaterSpecularIntensity*g_WaterSpecularColor*shadow_factor*depth_damper;
+
+ // applying surface foam provided by turbulent energy
+
+ // low frequency foam map
+ float foam_intensity_map_lf = 1.0*g_FoamIntensityTexture.Sample(SamplerLinearWrap, In.world_pos_undisplaced.xy*0.04*float2(1,1)).x - 1.0;
+
+ // high frequency foam map
+ float foam_intensity_map_hf = 1.0*g_FoamIntensityTexture.Sample(SamplerLinearWrap, In.world_pos_undisplaced.xy*0.15*float2(1,1)).x - 1.0;
+
+ // ultra high frequency foam map
+ float foam_intensity_map_uhf = 1.0*g_FoamIntensityTexture.Sample(SamplerLinearWrap, In.world_pos_undisplaced.xy*0.3*float2(1,1)).x;
+
+ float foam_intensity;
+ foam_intensity = saturate(foam_intensity_map_hf + min(3.5,1.0*surface_attributes.foam_turbulent_energy-0.2));
+ foam_intensity += (foam_intensity_map_lf + min(1.5,1.0*surface_attributes.foam_turbulent_energy));
+
+
+ foam_intensity -= 0.1*saturate(-surface_attributes.foam_surface_folding);
+
+ foam_intensity = max(0,foam_intensity);
+
+ foam_intensity *= 1.0+0.8*saturate(surface_attributes.foam_surface_folding);
+
+ float foam_bubbles = g_FoamDiffuseTexture.Sample(SamplerLinearWrap, In.world_pos_undisplaced.xy*0.5).r;
+ foam_bubbles = saturate(5.0*(foam_bubbles-0.8));
+
+ // applying foam hats
+ foam_intensity += max(0,foam_intensity_map_uhf*2.0*surface_attributes.foam_wave_hats);
+
+ foam_intensity = pow(foam_intensity, 0.7);
+ foam_intensity = saturate(foam_intensity*foam_bubbles*1.0);
+
+ foam_intensity*=depth_damper;
+
+ // foam diffuse color
+ float foam_diffuse_factor = max(0,0.8+max(0,0.2*dot(pixel_to_light_vector,surface_attributes.normal)));
+
+ color = lerp(color, foam_diffuse_factor*float3(1.0,1.0,1.0),foam_intensity);
+
+ // applying atmospheric fog to water surface
+ float fog_factor = min(1,exp(-length(g_CameraPosition-water_vertex_positionWS)*g_FogDensity));
+ color = lerp(color, CalculateFogColor(normalize(g_LightPosition),pixel_to_eye_vector).rgb, fresnel_factor*(1.0-fog_factor));
+
+ // applying solid wireframe
+ float d = min(In.v_dist.x,min(In.v_dist.y,In.v_dist.z));
+ float I = exp2(-2.0*d*d);
+ return float4(color + g_Wireframe*I*0.5, 1.0);
+}
+
+//-----------------------------------------------------------------------------
+// Name: OceanWaveTech
+// Type: Technique
+// Desc:
+//-----------------------------------------------------------------------------
+technique11 RenderOceanSurfTech
+{
+
+ // With shoreline
+ pass Pass_Solid_WithShoreline
+ {
+ SetVertexShader( CompileShader( vs_5_0, OceanWaveVS() ) );
+ SetHullShader( CompileShader( hs_5_0, HS_FlatTriangles() ) );
+ SetDomainShader( CompileShader( ds_5_0, DS_FlatTriangles_Shore() ) );
+ SetGeometryShader( CompileShader( gs_5_0, GSSolidWire() ) );
+ SetPixelShader( CompileShader( ps_5_0, OceanWaveShorePS() ) );
+
+ SetDepthStencilState( DepthNormal, 0 );
+ SetRasterizerState( CullBackMS );
+ SetBlendState(NoBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
+ }
+}
+
+
+struct VS_LOGO_OUTPUT
+{
+ float4 positionClip : SV_Position;
+ float2 tex_coord : TEXCOORD1;
+};
+
+//-----------------------------------------------------------------------------
+// Name: DisplayLogoVS
+// Type: Vertex shader
+//-----------------------------------------------------------------------------
+VS_LOGO_OUTPUT DisplayLogoVS(float4 vPos : POSITION, float2 vTexCoord : TEXCOORD0)
+{
+ VS_LOGO_OUTPUT Output;
+ Output.positionClip = vPos;
+ Output.tex_coord = vTexCoord;
+ return Output;
+}
+
+//-----------------------------------------------------------------------------
+// Name: DisplayLogoPS
+// Type: Pixel shader
+//-----------------------------------------------------------------------------
+float4 DisplayLogoPS(VS_LOGO_OUTPUT In) : SV_Target
+{
+ return g_LogoTexture.Sample(SamplerLinearWrap, In.tex_coord);
+}
+
+//-----------------------------------------------------------------------------
+// Name: DisplayBufferTech
+// Type: Technique
+// Desc: Logo rendering
+//-----------------------------------------------------------------------------
+technique11 DisplayLogoTech
+{
+ pass P0
+ {
+ SetVertexShader( CompileShader( vs_5_0, DisplayLogoVS() ) );
+ SetGeometryShader( NULL );
+ SetPixelShader( CompileShader( ps_5_0, DisplayLogoPS() ) );
+
+ SetDepthStencilState( DepthAlways, 0 );
+ SetRasterizerState( NoCullMS );
+ SetBlendState( Translucent, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
+ }
+}
+
+float4 g_OriginPosition;
+float4 g_ContactPosition;
+float4 g_RayDirection;
+
+struct RAY_CONTACT_VS_INPUT
+{
+ float4 PositionWS : POSITION;
+};
+
+struct RAY_CONTACT_VS_OUTPUT
+{
+ float4 PositionClip : SV_Position;
+};
+
+//-----------------------------------------------------------------------------
+// Name: ContactVS
+// Type: Vertex shader
+// Desc:
+//-----------------------------------------------------------------------------
+RAY_CONTACT_VS_OUTPUT ContactVS(RAY_CONTACT_VS_INPUT In)
+{
+ RAY_CONTACT_VS_OUTPUT Output;
+ Output.PositionClip = mul(float4(In.PositionWS.xzy*0.5 + g_ContactPosition.xyz, 1.0), g_ModelViewProjectionMatrix);
+ return Output;
+}
+
+//-----------------------------------------------------------------------------
+// Name: RayVS
+// Type: Vertex shader
+// Desc:
+//-----------------------------------------------------------------------------
+RAY_CONTACT_VS_OUTPUT RayVS(RAY_CONTACT_VS_INPUT In)
+{
+ RAY_CONTACT_VS_OUTPUT Output;
+ Output.PositionClip = mul(float4(g_OriginPosition.xzy + In.PositionWS.y*g_RayDirection.xzy,1.0), g_ModelViewProjectionMatrix);
+ return Output;
+}
+
+//-----------------------------------------------------------------------------
+// Name: RayContactPS
+// Type: Pixel shader
+// Desc:
+//-----------------------------------------------------------------------------
+float4 RayContactPS(RAY_CONTACT_VS_OUTPUT In) : SV_Target
+{
+ return float4(0, 1.0, 0, 1.0);
+}
+
+//-----------------------------------------------------------------------------
+// Name: RenderRayContactTech
+// Type: Technique
+// Desc:
+//-----------------------------------------------------------------------------
+technique11 RenderRayContactTech
+{
+
+ // Contact
+ pass Pass_Contact
+ {
+ SetVertexShader( CompileShader( vs_5_0, ContactVS() ) );
+ SetHullShader( NULL );
+ SetDomainShader( NULL );
+ SetGeometryShader( NULL );
+ SetPixelShader( CompileShader( ps_5_0, RayContactPS() ) );
+
+ SetDepthStencilState( DepthNormal, 0 );
+ SetRasterizerState( NoCullMS );
+ SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
+ }
+
+ // Ray
+ pass Pass_Ray
+ {
+ SetVertexShader( CompileShader( vs_5_0, RayVS() ) );
+ SetHullShader( NULL );
+ SetDomainShader( NULL );
+ SetGeometryShader( NULL );
+ SetPixelShader( CompileShader( ps_5_0, RayContactPS() ) );
+
+ SetDepthStencilState( DepthNormal, 0 );
+ SetRasterizerState( Wireframe );
+ SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
+ }
+}