diff options
| author | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
|---|---|---|
| committer | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
| commit | 79b3462799c28af8ba586349bd671b1b56e72353 (patch) | |
| tree | 3b06e36c390254c0dc7f3733a0d32af213d87293 /demo/ocean_spray.fx | |
| download | waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.zip | |
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'demo/ocean_spray.fx')
| -rw-r--r-- | demo/ocean_spray.fx | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/demo/ocean_spray.fx b/demo/ocean_spray.fx new file mode 100644 index 0000000..d136b2a --- /dev/null +++ b/demo/ocean_spray.fx @@ -0,0 +1,1035 @@ +// 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. +// + +#include "ocean_shader_common.h" +#include "ocean_spray_common.h" +#include "atmospheric.fxh" +#include "shader_common.fxh" +#include "ocean_psm.fxh" + +//------------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------------ + +float4x4 g_matProj; +float4x4 g_matView; +float4x4 g_matProjInv; +float3 g_LightDirection; +float3 g_LightColor; +float3 g_AmbientColor; +float g_FogExponent; +float g_InvParticleLifeTime; + +float3 g_LightningPosition; +float3 g_LightningColor; +float g_SimpleParticles; + +int g_LightsNum; +float4 g_SpotlightPosition[MaxNumSpotlights]; +float4 g_SpotLightAxisAndCosAngle[MaxNumSpotlights]; +float4 g_SpotlightColor[MaxNumSpotlights]; + +#if ENABLE_SHADOWS +float4x4 g_SpotlightMatrix[MaxNumSpotlights]; +Texture2D g_SpotlightResource[MaxNumSpotlights]; +#endif + +Buffer<float4> g_RenderInstanceData; +Buffer<float4> g_RenderOrientationAndDecimationData; +Buffer<float4> g_RenderVelocityAndTimeData; + +float g_PSMOpacityMultiplier; + +// Data for GPU simulation +struct SprayParticleData +{ + float4 position_and_mass; + float4 velocity_and_time; +}; + +int g_ParticlesNum; +float g_SimulationTime; +float3 g_WindSpeed; + +// We use these for ensuring particles do not intersect ship +float4x4 g_worldToVessel; +float4x4 g_vesselToWorld; + +// We use these to kill particles +float2 g_worldToHeightLookupScale; +float2 g_worldToHeightLookupOffset; +float2 g_worldToHeightLookupRot; +Texture2D g_texHeightLookup; + +// We use these to feed particles back into foam map +float4x4 g_matWorldToFoam; + +static const float kVesselLength = 63.f; +static const float kVesselWidth = 9.f; +static const float kVesselDeckHeight = 0.f; +static const float kMaximumCollisionAcceleration = 10.f; +static const float kCollisionAccelerationRange = 0.5f; + +static const float kSceneParticleTessFactor = 8.f; + +struct DepthSortEntry { + int ParticleIndex; + float ViewZ; +}; + +StructuredBuffer <DepthSortEntry> g_ParticleDepthSortSRV; +StructuredBuffer<SprayParticleData> g_SprayParticleDataSRV; + +RWStructuredBuffer <DepthSortEntry> g_ParticleDepthSortUAV : register(u0); +AppendStructuredBuffer<SprayParticleData> g_SprayParticleData : register(u1); + +uint g_iDepthSortLevel; +uint g_iDepthSortLevelMask; +uint g_iDepthSortWidth; +uint g_iDepthSortHeight; + +float4 g_AudioVisualizationRect; // litterbug +float2 g_AudioVisualizationMargin; +float g_AudioVisualizationLevel; + +//------------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------------ +static const float2 kParticleCornerCoords[4] = { + {-1, 1}, + { 1, 1}, + {-1,-1}, + { 1,-1} +}; + +static const float3 kFoamColor = {0.5f, 0.5f, 0.5f}; + +//----------------------------------------------------------------------------------- +// Texture & Samplers +//----------------------------------------------------------------------------------- +Texture2D g_texSplash; + +sampler g_SamplerTrilinearClamp +{ + Filter = MIN_MAG_MIP_LINEAR; + AddressU = Clamp; + AddressV = Clamp; +}; + +//-------------------------------------------------------------------------------------- +// Structs +//-------------------------------------------------------------------------------------- +struct VS_DUMMY_PARTICLE_OUTPUT +{ +}; + +struct PARTICLE_INSTANCE_DATA { + float4 position_and_mass : PosMass; + float3 orientation_and_decimation : OriDec; + float3 velocity : Vel; + float time : T; +}; + +struct VS_SCENE_PARTICLE_OUTPUT { + PARTICLE_INSTANCE_DATA InstanceData; + float FogFactor : FogFactor; +}; + +struct HS_PARTICLE_COORDS { + float3 ViewPos; + float3 TextureUVAndOpacity; +}; + +struct HS_SCENE_PARTICLE_OUTPUT { + float3 ViewPos : ViewPos; + float3 TextureUVAndOpacity : TEXCOORD0; + // NOT USED float3 PSMCoords : PSMCoords; + float FogFactor : FogFactor; +}; + +struct DS_SCENE_PARTICLE_OUTPUT { + float4 Position : SV_Position; + float3 ViewPos : ViewPos; + float3 TextureUVAndOpacity : TEXCOORD0; + // NOT USED float3 PSMCoords : PSMCoords; + float FogFactor : FogFactor; + float3 Lighting : LIGHTING; +}; + +struct HS_SCENE_PARTICLE_OUTPUT_CONST +{ + float fTessFactor[4] : SV_TessFactor; + float fInsideTessFactor[2] : SV_InsideTessFactor; +}; + +struct GS_FOAM_PARTICLE_OUTPUT { + float4 Position : SV_Position; + float3 ViewPos : ViewPos; + float3 TextureUVAndOpacity : TEXCOORD0; + float FoamAmount : FOAMAMOUNT; +}; + +struct GS_PSM_PARTICLE_OUTPUT +{ + float4 Position : SV_Position; + nointerpolation uint LayerIndex : SV_RenderTargetArrayIndex; + float3 TextureUVAndOpacity : TEXCOORD0; + nointerpolation uint SubLayer : TEXCOORD1; +}; + +//-------------------------------------------------------------------------------------- +// Functions +//-------------------------------------------------------------------------------------- +PARTICLE_INSTANCE_DATA GetParticleInstanceData(in uint PrimID) +{ + uint particle_index = PrimID; // one day? - g_ParticleDepthSortSRV[PrimID].ParticleIndex; + + PARTICLE_INSTANCE_DATA result; +#if ENABLE_GPU_SIMULATION +#if SPRAY_PARTICLE_SORTING + particle_index = g_ParticleDepthSortSRV[particle_index].ParticleIndex; +#endif + SprayParticleData particleData = g_SprayParticleDataSRV[particle_index]; + result.position_and_mass = particleData.position_and_mass; + result.orientation_and_decimation.xy = float2(1.0, 0.0); + result.velocity = particleData.velocity_and_time.xyz; + result.time = particleData.velocity_and_time.w; + + result.orientation_and_decimation.z = 1.f; +#else + result.position_and_mass = g_RenderInstanceData.Load(particle_index); + result.orientation_and_decimation = g_RenderOrientationAndDecimationData.Load(particle_index).xyz; + result.velocity = 0; +#endif + + return result; +} + +float CalcVelocityScale(float speed) +{ + return log2(speed * 0.2f + 2.0f); +} + +float CalcTimeScale(float time) +{ + return 0.5+0.5*time; +} + +void CalcParticleCoords( PARTICLE_INSTANCE_DATA InstanceData, in float2 CornerCoord, out float3 ViewPos, out float2 UV, out float Opacity) +{ + // Transform to camera space + ViewPos = mul(float4(InstanceData.position_and_mass.xyz,1), g_matView).xyz; + + float2 coords = CornerCoord*CalcTimeScale(InstanceData.time); + coords *= 0.7f; // Make particles a little smaller to keep the look crisp + + float3 velocityView = mul(InstanceData.velocity.xyz, (float3x3)g_matView).xyz; + float velocityScale = CalcVelocityScale(length(velocityView.xy)); + coords.x /= (velocityScale * 0.25f + 0.75f); + coords.y *= velocityScale; + + float angle = atan2(velocityView.x,velocityView.y); + + float2 orientation = float2(cos(angle), sin(angle));//InstanceData.orientation_and_decimation.xy; + float2 rotatedCornerCoord; + rotatedCornerCoord.x = coords.x * orientation.x + coords.y * orientation.y; + rotatedCornerCoord.y = -coords.x * orientation.y + coords.y * orientation.x; + + // Inflate corners, applying scale from instance data + ViewPos.xy += g_SimpleParticles>0?CornerCoord*0.02:rotatedCornerCoord; + + const float mass = InstanceData.position_and_mass.w; + float cosAngle = cos(mass * 8.0f); + float sinAngle = sin(mass * 8.0f); + + float2 rotatedUV = CornerCoord; + UV.x = rotatedUV.x * cosAngle + rotatedUV.y * sinAngle; + UV.y =-rotatedUV.x * sinAngle + rotatedUV.y * cosAngle; + + UV = 0.5f * (UV + 1.f); + + Opacity = InstanceData.orientation_and_decimation.z; +} + +HS_PARTICLE_COORDS CalcParticleCoords(in PARTICLE_INSTANCE_DATA InstanceData, int i) +{ + HS_PARTICLE_COORDS result; + CalcParticleCoords( InstanceData, kParticleCornerCoords[i], result.ViewPos, result.TextureUVAndOpacity.xy, result.TextureUVAndOpacity.z); + return result; +} + +float4 GetParticleRGBA(SamplerState s, float2 uv, float alphaMult) +{ + float4 splash = g_texSplash.SampleBias(s, uv, -1.0); + float alpha_threshold = 1.0 - alphaMult * 0.6; + clip(splash.r-alpha_threshold); + return float4(kFoamColor, 1.0); +} + +VS_DUMMY_PARTICLE_OUTPUT DummyVS( ) +{ + VS_DUMMY_PARTICLE_OUTPUT Output; + return Output; +} + +VS_SCENE_PARTICLE_OUTPUT RenderParticlesToSceneVS(in uint vID : SV_VertexID) +{ + VS_SCENE_PARTICLE_OUTPUT Output; + Output.InstanceData = GetParticleInstanceData(vID); + float3 CentreViewPos = mul(float4(Output.InstanceData.position_and_mass.xyz,1), g_matView).xyz; + Output.FogFactor = exp(dot(CentreViewPos,CentreViewPos)*g_FogExponent); + return Output; +} + + +HS_SCENE_PARTICLE_OUTPUT_CONST RenderParticlesToSceneHS_Constant(InputPatch<VS_SCENE_PARTICLE_OUTPUT, 1> I) +{ + HS_SCENE_PARTICLE_OUTPUT_CONST O; + O.fTessFactor[0] = kSceneParticleTessFactor; + O.fTessFactor[1] = kSceneParticleTessFactor; + O.fTessFactor[2] = kSceneParticleTessFactor; + O.fTessFactor[3] = kSceneParticleTessFactor; + O.fInsideTessFactor[0] = kSceneParticleTessFactor; + O.fInsideTessFactor[1] = kSceneParticleTessFactor; + return O; +} + +[domain("quad")] +[partitioning("integer")] +[outputtopology("triangle_cw")] +[patchconstantfunc("RenderParticlesToSceneHS_Constant")] +[outputcontrolpoints(4)] +HS_SCENE_PARTICLE_OUTPUT RenderParticlesToSceneHS( InputPatch<VS_SCENE_PARTICLE_OUTPUT, 1> I, uint uCPID : SV_OutputControlPointID ) +{ + HS_PARTICLE_COORDS particleCoords = CalcParticleCoords(I[0].InstanceData,uCPID); + + // NOT USED float4 PSMCoords = mul(float4(particleCoords.ViewPos,1.f), g_matViewToPSM); + + HS_SCENE_PARTICLE_OUTPUT outvert; + outvert.TextureUVAndOpacity = particleCoords.TextureUVAndOpacity; + outvert.ViewPos = particleCoords.ViewPos; + // NOT USED outvert.PSMCoords = float3(PSMCoords.xyz); + outvert.FogFactor = I[0].FogFactor; + + return outvert; +} + +#define QUAD_INTERP(member) (f0*I[0].member + f1*I[1].member + f2*I[2].member + f3*I[3].member) + +[domain("quad")] +DS_SCENE_PARTICLE_OUTPUT RenderParticlesToSceneDS( HS_SCENE_PARTICLE_OUTPUT_CONST HSConstantData, const OutputPatch<HS_SCENE_PARTICLE_OUTPUT, 4> I, float2 f2BilerpCoords : SV_DomainLocation ) +{ + float f0 = f2BilerpCoords.x * f2BilerpCoords.y; + float f1 = (1.f-f2BilerpCoords.x) * f2BilerpCoords.y; + float f2 = f2BilerpCoords.x * (1.f-f2BilerpCoords.y); + float f3 = (1.f-f2BilerpCoords.x) * (1.f-f2BilerpCoords.y); + + DS_SCENE_PARTICLE_OUTPUT outvert; + outvert.ViewPos = QUAD_INTERP(ViewPos); + outvert.TextureUVAndOpacity = QUAD_INTERP(TextureUVAndOpacity); + outvert.FogFactor = QUAD_INTERP(FogFactor); + outvert.Position = mul(float4(outvert.ViewPos,1.f), g_matProj); + + //////////////////////////////////////////////////////////////////////////////// + // Lighting calcs hoisted from PS from here... + //////////////////////////////////////////////////////////////////////////////// + + // randomize ppsition in view space to reduce shading banding + float displacementScale = RND_1d(outvert.TextureUVAndOpacity.xy / 10); + outvert.ViewPos.z += (displacementScale * 2.0f - 1.0f) * 0.25f; + + // Fake ship AO + float3 vessel_pos = mul(float4(outvert.ViewPos,1),g_worldToVessel).xyz; + float ao_profile = 0.5f*kVesselWidth*saturate((0.5f*kVesselLength-abs(vessel_pos.z))/(kVesselWidth)); + float ao_horizontal_range = abs(vessel_pos.x) - ao_profile; + float ao_vertical_range = vessel_pos.y; + float ao = 0.2f+ 0.8f*(1.f -saturate(1.f-ao_horizontal_range/5.f)* saturate(1.f-ao_vertical_range/5.f)); + + float3 dynamic_lighting = ao*(g_LightColor + g_AmbientColor*2.0) + g_LightningColor; + + [unroll] + for(int ix = 0; ix != g_LightsNum; ++ix) { + float3 pixel_to_light = g_SpotlightPosition[ix].xyz - outvert.ViewPos; + float3 pixel_to_light_nml = normalize(pixel_to_light); + float beam_attn = saturate(1.f*(-dot(g_SpotLightAxisAndCosAngle[ix].xyz,pixel_to_light_nml)-g_SpotLightAxisAndCosAngle[ix].w)/(1.f-g_SpotLightAxisAndCosAngle[ix].w)); + beam_attn *= 1.f/dot(pixel_to_light,pixel_to_light); + float shadow = 1.0f; +#if ENABLE_SHADOWS + if (beam_attn * dot(g_SpotlightColor[ix].xyz, g_SpotlightColor[ix].xyz) > 0.01f) + { + shadow = GetShadowValue(g_SpotlightResource[ix], g_SpotlightMatrix[ix], outvert.ViewPos.xyz, true); + } +#endif + dynamic_lighting += beam_attn * g_SpotlightColor[ix].xyz * shadow; + } + + outvert.Lighting = dynamic_lighting; + + return outvert; +} + +#define USE_DOWNSAMPLING 0 + +#if USE_DOWNSAMPLING +Texture2D<float> g_texDepth; +#else +Texture2DMS<float> g_texDepth; +#endif + +[earlydepthstencil] +float4 RenderParticlesToScenePS(DS_SCENE_PARTICLE_OUTPUT In) : SV_Target +{ + if(g_SimpleParticles>0) + { + return float4(0.5,0.0,0.0,1.0); + } + + // disable PSM on spray dynamic_lighting *= CalcPSMShadowFactor(In.PSMCoords); + float4 result = GetParticleRGBA(g_SamplerTrilinearClamp, In.TextureUVAndOpacity.xy, In.TextureUVAndOpacity.z); + + result.rgb *= In.Lighting; + + result.rgb = lerp(g_AmbientColor + g_LightningColor,result.rgb,In.FogFactor); + result.a = 0.125 * In.TextureUVAndOpacity.z; + +#if USE_DOWNSAMPLING + float depth = g_texDepth[(int2)In.Position.xy]; // coarse depth +#else + float depth = g_texDepth.Load((int2)In.Position.xy, 0); // fine depth +#endif + + float4 clipPos = float4(0, 0, depth, 1.0); + float4 viewSpace = mul(clipPos, g_matProjInv); + viewSpace.z /= viewSpace.w; + + result.a *= saturate(abs(In.ViewPos.z - viewSpace.z) * 0.5); + + return result; +} + +[maxvertexcount(4)] +void RenderParticlesToPSMGS( in point VS_DUMMY_PARTICLE_OUTPUT dummy[1], in uint PrimID : SV_PrimitiveID, inout TriangleStream<GS_PSM_PARTICLE_OUTPUT> outstream ) +{ + PARTICLE_INSTANCE_DATA InstanceData = GetParticleInstanceData(PrimID); + float3 CentreViewPos = mul(float4(InstanceData.position_and_mass.xyz,1), g_matView).xyz; + + // Dispatch to PSM layer-slice + float linearZ = mul(float4(CentreViewPos,1.f), g_matProj).z; + float slice = g_PSMSlices * linearZ + 1.f; // +1 because zero slice reserved for coverage + uint sublayer = 2.f * frac(slice); + + if(slice < 0.f || slice > g_PSMSlices) + return; + + slice = floor(slice); + + [unroll] + for(uint i = 0; i != 4; ++i) { + + HS_PARTICLE_COORDS particleCoords = CalcParticleCoords(InstanceData,i); + + GS_PSM_PARTICLE_OUTPUT outvert; + outvert.TextureUVAndOpacity = particleCoords.TextureUVAndOpacity; + outvert.Position = mul(float4(particleCoords.ViewPos,1.f), g_matProj); + outvert.SubLayer = sublayer; + outvert.LayerIndex = slice; + outstream.Append(outvert); + } + outstream.RestartStrip(); +} + +float4 RenderParticlesToPSMPS( GS_PSM_PARTICLE_OUTPUT In) : SV_Target +{ + float4 tex = GetParticleRGBA(g_SamplerTrilinearClamp,In.TextureUVAndOpacity.xy,In.TextureUVAndOpacity.z); + + float4 Output = tex.a; + Output *= g_PSMOpacityMultiplier; + if(In.SubLayer == 0) + Output *= float4(1,0,0,0); + else if(In.SubLayer == 1) + Output *= float4(0,1,0,0); + else if(In.SubLayer == 2) + Output *= float4(0,0,1,0); + else + Output *= float4(0,0,0,1); + + return Output; +} + +float2 rotate_2d(float2 v, float2 rot) +{ + return float2(v.x * rot.x + v.y * rot.y, v.x * -rot.y + v.y * rot.x); +} + +[maxvertexcount(4)] +void RenderParticlesToFoamGS( in point VS_DUMMY_PARTICLE_OUTPUT dummy[1], in uint PrimID : SV_PrimitiveID, inout TriangleStream<GS_FOAM_PARTICLE_OUTPUT> outstream ) +{ + PARTICLE_INSTANCE_DATA InstanceData = GetParticleInstanceData(PrimID); + + // Only downward-moving particles are eligible for foam injection + if(InstanceData.velocity.y > 0.f) + return; + + // Particles that fall outside our lookup cannot be rendered to foam, because we have no way of knowing when they hit the sea surface + float2 lookup_uv = rotate_2d(InstanceData.position_and_mass.xz+g_worldToHeightLookupOffset,g_worldToHeightLookupRot)*g_worldToHeightLookupScale; + if(lookup_uv.x < 0.f || lookup_uv.y < 0.f || lookup_uv.x > 1.f || lookup_uv.y > 1.f) + return; + + float particle_scale = CalcTimeScale(InstanceData.time); + float3 lookup_value = g_texHeightLookup.SampleLevel(g_SamplerTrilinearClamp,lookup_uv,0.f).xyz; + float height_of_centre_above_water = InstanceData.position_and_mass.y-lookup_value.z; + if( height_of_centre_above_water < -particle_scale || height_of_centre_above_water > particle_scale) + return; // No intersection + + // The proportion of foam applied depends on how much foam is falling through the surface on this update + // Note that this does not take account of the normal or speed of the water surface, which would be + // necessary for perfection here... + float relative_penetration = 0.15f*(-InstanceData.velocity.y * g_SimulationTime)/particle_scale; + + [unroll] + for(uint i = 0; i != 4; ++i) { + + HS_PARTICLE_COORDS particleCoords = CalcParticleCoords(InstanceData,i); + + // Lookup undisplaced coords + float2 world_xy = float2(particleCoords.ViewPos.xy); + // DISABLED: use world space float2 corner_lookup_uv = rotate_2d(world_xy+g_worldToHeightLookupOffset,g_worldToHeightLookupRot)*g_worldToHeightLookupScale; + // DISABLED: use world space world_xy = g_texHeightLookup.SampleLevel(g_SamplerTrilinearClamp,corner_lookup_uv,0.f).xy; + + float2 clip_xy = mul(float4(world_xy.x,0.0,world_xy.y,1.0),g_matWorldToFoam).xz; + clip_xy *= g_WakeTexScale; + clip_xy += g_WakeTexOffset; + clip_xy *= 2.f; + clip_xy -= 1.f; + + GS_FOAM_PARTICLE_OUTPUT outvert; + outvert.TextureUVAndOpacity = particleCoords.TextureUVAndOpacity; + outvert.Position = float4(clip_xy,0.5f,1.f); + outvert.ViewPos = particleCoords.ViewPos; + outvert.FoamAmount = relative_penetration; + outstream.Append(outvert); + } + outstream.RestartStrip(); +} + +float4 RenderParticlesToFoamPS( GS_FOAM_PARTICLE_OUTPUT In) : SV_Target +{ + return In.FoamAmount * GetParticleRGBA(g_SamplerTrilinearClamp, In.TextureUVAndOpacity.xy, In.TextureUVAndOpacity.z).a; +} + +//-------------------------------------------------------------------------------------- +// DepthStates +//-------------------------------------------------------------------------------------- +DepthStencilState EnableDepth +{ + DepthEnable = TRUE; + DepthWriteMask = ALL; + DepthFunc = LESS_EQUAL; + StencilEnable = FALSE; +}; + +DepthStencilState NoDepthStencil +{ + DepthEnable = FALSE; + StencilEnable = FALSE; +}; + +DepthStencilState ReadDepth +{ + DepthEnable = TRUE; + DepthWriteMask = ZERO; + DepthFunc = LESS_EQUAL; +}; + +//-------------------------------------------------------------------------------------- +// RasterStates +//-------------------------------------------------------------------------------------- +RasterizerState SolidNoCull +{ + FillMode = SOLID; + CullMode = NONE; + + MultisampleEnable = True; +}; + +//-------------------------------------------------------------------------------------- +// BlendStates +//-------------------------------------------------------------------------------------- +BlendState Opaque +{ + BlendEnable[0] = FALSE; + RenderTargetWriteMask[0] = 0xF; +}; + +BlendState Translucent +{ + BlendEnable[0] = TRUE; + RenderTargetWriteMask[0] = 0xF; + + SrcBlend = SRC_ALPHA; + DestBlend = INV_SRC_ALPHA; + BlendOp = Add; + + SrcBlendAlpha = ZERO; + DestBlendAlpha = INV_SRC_ALPHA; + BlendOpAlpha = Add; +}; + +BlendState AddBlend +{ + BlendEnable[0] = TRUE; + RenderTargetWriteMask[0] = 0xF; + + SrcBlend = ONE; + DestBlend = ONE; + BlendOp = Add; +}; + +//-------------------------------------------------------------------------------------- +// Techniques +//-------------------------------------------------------------------------------------- +technique10 RenderSprayToSceneTech +{ + pass + { + SetVertexShader( CompileShader( vs_5_0, RenderParticlesToSceneVS() ) ); + SetGeometryShader( NULL ); + SetHullShader( CompileShader( hs_5_0, RenderParticlesToSceneHS() ) ); + SetDomainShader( CompileShader( ds_5_0, RenderParticlesToSceneDS() ) ); + SetPixelShader( CompileShader( ps_5_0, RenderParticlesToScenePS() ) ); + + SetDepthStencilState( ReadDepth, 0 ); + SetRasterizerState( SolidNoCull ); + SetBlendState( Translucent, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); + } + +} + +technique10 RenderSprayToFoamTech +{ + pass + { + SetVertexShader( CompileShader( vs_4_0, DummyVS() ) ); + SetGeometryShader( CompileShader( gs_4_0, RenderParticlesToFoamGS() ) ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( CompileShader( ps_5_0, RenderParticlesToFoamPS() ) ); + + SetDepthStencilState( NoDepthStencil, 0 ); + SetRasterizerState( SolidNoCull ); + SetBlendState( AddBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); + } +} + +technique11 RenderSprayToPSMTech +{ + pass + { + SetVertexShader( CompileShader( vs_4_0, DummyVS() ) ); + SetGeometryShader( CompileShader( gs_4_0, RenderParticlesToPSMGS() ) ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( CompileShader( ps_4_0, RenderParticlesToPSMPS() ) ); + + SetDepthStencilState( NoDepthStencil, 0 ); + SetRasterizerState( SolidNoCull ); + SetBlendState( PSMBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); + } +} + +//-------------------------------------------------------------------------------------- +// Compute shaders +//-------------------------------------------------------------------------------------- + +cbuffer DispatchArguments : register(b2) +{ + uint g_ParticleCount; +} + +float3 CollisionAvoidanceAcceleration(float3 position) +{ + float3 vessel_pos = mul(float4(position,1),g_worldToVessel).xyz; + float3 accel_vessel_direction = 0.f; + float accel_magnitude = 0.f; + + // Apply at all heights + { + float collison_profile = 0.5f*kVesselWidth*saturate((0.5f*kVesselLength-vessel_pos.z)/(kVesselWidth)); + float rear_exclude = (vessel_pos.z < -20.f && vessel_pos.y > 0.f) ? 0.f : 1.f; + float range = abs(vessel_pos.x) - collison_profile; + float range_mult = saturate(1.f-range/kCollisionAccelerationRange); + accel_magnitude = kMaximumCollisionAcceleration * range_mult * rear_exclude; + accel_vessel_direction = float3(vessel_pos.x/abs(vessel_pos.x),0,0); + } + + return accel_magnitude * mul(accel_vessel_direction,(float3x3)g_vesselToWorld); +} + +[numthreads(SprayParticlesCSBlocksSize, 1, 1)] +void InitSprayParticlesCS(uint3 globalIdx : SV_DispatchThreadID) +{ + uint particleID = globalIdx.x; + + if (particleID >= g_ParticlesNum) return; + + SprayParticleData particleData; + particleData.position_and_mass = g_RenderInstanceData.Load(particleID); + particleData.velocity_and_time = g_RenderVelocityAndTimeData.Load(particleID); + + particleData.velocity_and_time.w = 0; + + g_SprayParticleData.Append(particleData); +} + +[numthreads(SprayParticlesCSBlocksSize, 1, 1)] +void SimulateSprayParticlesCS(uint3 globalIdx : SV_DispatchThreadID) +{ + uint particleID = globalIdx.x; + + if (particleID >= min(g_ParticleCount, SPRAY_PARTICLE_COUNT)) return; + + SprayParticleData particleData = g_SprayParticleDataSRV[particleID]; + + int num_steps = ceil(g_SimulationTime / kMaxSimulationTimeStep); + num_steps = min(num_steps, 3); + float time_step = g_SimulationTime / float(num_steps); + + // kill particles by life-time + if (particleData.velocity_and_time.w + time_step * num_steps > kParticleTTL) return; + + // Kill rules: + // 1/ particle must be heading down + // 2/ particle must be its own size inside the surface + if(particleData.velocity_and_time.y < 0.f) { + float2 lookup_uv = rotate_2d(particleData.position_and_mass.xz+g_worldToHeightLookupOffset,g_worldToHeightLookupRot)*g_worldToHeightLookupScale; + if(lookup_uv.x > 0.f && lookup_uv.y > 0.f && lookup_uv.x < 1.f && lookup_uv.y < 1.f) { + float3 lookup_value = g_texHeightLookup.SampleLevel(g_SamplerTrilinearClamp,lookup_uv,0.f).xyz; + float depth_of_centre_below = lookup_value.z - particleData.position_and_mass.y; + float conservative_velocity_scale = CalcVelocityScale(length(particleData.velocity_and_time.xyz)) * CalcTimeScale(particleData.velocity_and_time.w); + if(depth_of_centre_below > conservative_velocity_scale) { + return; // KILLED! + } + } + } + + // updating particle times + particleData.velocity_and_time.w += time_step * num_steps; + for(int step = 0; step != num_steps; ++step) + { + // updating spray particles positions + float3 positionDelta = particleData.velocity_and_time.xyz * time_step; + particleData.position_and_mass.xyz += positionDelta; + + // updating spray particles speeds + float3 accel = -kParticleDrag * (particleData.velocity_and_time.xyz - g_WindSpeed)/particleData.position_and_mass.w; + accel.y -= kGravity;//*1.1*particleData.position_and_mass.w; + accel += CollisionAvoidanceAcceleration(particleData.position_and_mass.xyz); + particleData.velocity_and_time.xyz += accel * time_step; + } + + g_SprayParticleData.Append(particleData); +} + +[numthreads(SprayParticlesCSBlocksSize, 1, 1)] +void InitSortCS(uint3 globalIdx : SV_DispatchThreadID) +{ + uint particle_index = globalIdx.x; + + SprayParticleData particleData = g_SprayParticleDataSRV[particle_index]; + float view_z = max(0,mul(float4(particleData.position_and_mass.xyz,1), g_matView).z); + + if (particle_index >= g_ParticleCount) view_z = 0; + + g_ParticleDepthSortUAV[particle_index].ParticleIndex = particle_index; + g_ParticleDepthSortUAV[particle_index].ViewZ = view_z; +} + +RWBuffer<uint4> u_DispatchArgumentsBuffer : register(u0); + +[numthreads(1, 1, 1)] +void DispatchArgumentsCS(uint3 globalIdx : SV_DispatchThreadID) +{ + uint blocksNum = ceil((float)g_ParticleCount / SimulateSprayParticlesCSBlocksSize); + + u_DispatchArgumentsBuffer[0] = uint4(blocksNum, 1, 1, 0); +} + +groupshared DepthSortEntry shared_data[BitonicSortCSBlockSize]; + +[numthreads(BitonicSortCSBlockSize, 1, 1)] +void BitonicSortCS( uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + // Load shared data + shared_data[GI] = g_ParticleDepthSortUAV[DTid.x]; + GroupMemoryBarrierWithGroupSync(); + + // Sort the shared data + for (unsigned int j = g_iDepthSortLevel >> 1 ; j > 0 ; j >>= 1) + { + DepthSortEntry result; + if((bool)(shared_data[GI & ~j].ViewZ > shared_data[GI | j].ViewZ) == (bool)(g_iDepthSortLevelMask & DTid.x)) + result = shared_data[GI ^ j]; + else + result = shared_data[GI]; + GroupMemoryBarrierWithGroupSync(); + shared_data[GI] = result; + GroupMemoryBarrierWithGroupSync(); + } + + // Store shared data + g_ParticleDepthSortUAV[DTid.x] = shared_data[GI]; +} + +groupshared DepthSortEntry transpose_shared_data[TransposeCSBlockSize * TransposeCSBlockSize]; + +[numthreads(TransposeCSBlockSize, TransposeCSBlockSize, 1)] +void MatrixTransposeCS( uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + transpose_shared_data[GI] = g_ParticleDepthSortSRV[DTid.y * g_iDepthSortWidth + DTid.x]; + GroupMemoryBarrierWithGroupSync(); + uint2 XY = DTid.yx - GTid.yx + GTid.xy; + g_ParticleDepthSortUAV[XY.y * g_iDepthSortHeight + XY.x] = transpose_shared_data[GTid.x * TransposeCSBlockSize + GTid.y]; +} + +technique11 InitSprayParticles +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + + SetComputeShader( CompileShader( cs_5_0, InitSprayParticlesCS() ) ); + } +} + +technique11 SimulateSprayParticles +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + + SetComputeShader( CompileShader( cs_5_0, SimulateSprayParticlesCS() ) ); + } +} + +technique11 PrepareDispatchArguments +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + + SetComputeShader( CompileShader( cs_5_0, DispatchArgumentsCS() ) ); + } +} + +technique11 InitSortTech +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + + SetComputeShader( CompileShader( cs_5_0, InitSortCS() ) ); + } +} + +technique11 BitonicSortTech +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + SetComputeShader( CompileShader( cs_5_0, BitonicSortCS() ) ); + } +} + +technique11 MatrixTransposeTech +{ + pass + { + SetVertexShader( NULL ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( NULL ); + SetComputeShader( CompileShader( cs_5_0, MatrixTransposeCS() ) ); + } +} + +//-------------------------------------------------------------------------------------- +// Sensor visualization shaders +//-------------------------------------------------------------------------------------- + +RasterizerState Solid +{ + FillMode = SOLID; + CullMode = NONE; + + MultisampleEnable = True; +}; + +struct SENSOR_VISUALIZATION_VS_OUT +{ + float4 position : SV_Position; + float3 color : SENSOR_COLOR; + float2 uv : TEXCOORD; +}; + +SENSOR_VISUALIZATION_VS_OUT SensorVisualizationVS(float3 vPos : POSITION, float intensity : INTENSITY, float2 uv : TEXCOORD) +{ + SENSOR_VISUALIZATION_VS_OUT output; + float4x4 matViewProj = mul(g_matView,g_matProj); + float c_intensity = abs(intensity*0.7)+0.3; + output.position = mul(float4(vPos,1.0), matViewProj); + output.color = intensity>0?float3(c_intensity,c_intensity,c_intensity) : float3(c_intensity,c_intensity,0); + output.uv = uv; + return output; +} + +float4 SensorVisualizationPS( SENSOR_VISUALIZATION_VS_OUT i) : SV_Target +{ + float r = length(i.uv - float2(0.5,0.5)); + clip(0.5f-r); + return float4(i.color,1.f); +} + +//-------------------------------------------------------------------------------------- +// Sensor visualization technique +//-------------------------------------------------------------------------------------- + +technique10 SensorVisualizationTech +{ + pass + { + SetVertexShader( CompileShader( vs_4_0, SensorVisualizationVS() ) ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( CompileShader( ps_4_0, SensorVisualizationPS() ) ); + + SetDepthStencilState( EnableDepth, 0 ); + SetRasterizerState( Solid ); + SetBlendState( Opaque, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); + } +} + +//-------------------------------------------------------------------------------------- +// Audio trigger visualization +//-------------------------------------------------------------------------------------- + +static const float2 kAudioVizCornerCoords[6] = { + { 0, 0}, + { 1, 1}, + { 1, 0}, + { 0, 0}, + { 0, 1}, + { 1, 1} +}; + + +struct AUDIO_VISUALIZATION_VS_OUT +{ + float4 position : SV_Position; + float2 uv : TEXCOORD; + float element_index : ELIX; +}; + +AUDIO_VISUALIZATION_VS_OUT AudioVisualizationVS(uint vID : SV_VertexID) +{ + AUDIO_VISUALIZATION_VS_OUT Out; + Out.uv = kAudioVizCornerCoords[vID%6]; + float4 element_rect = g_AudioVisualizationRect; + if(vID<6) { + // Background element + Out.element_index = 0.f; + } else { + // Level meter element + Out.element_index = 1.f; + element_rect.x += g_AudioVisualizationMargin.x; + element_rect.y -= g_AudioVisualizationMargin.y; + element_rect.z -= g_AudioVisualizationMargin.x; + element_rect.w += g_AudioVisualizationMargin.y; + Out.uv.y *= g_AudioVisualizationLevel; + } + + Out.position = float4( element_rect.x + (element_rect.z-element_rect.x)*Out.uv.x, + element_rect.w - (element_rect.w-element_rect.y)*Out.uv.y, + 0.5f, + 1.f + ); + + return Out; +} + +float4 AudioVisualizationPS( AUDIO_VISUALIZATION_VS_OUT i) : SV_Target +{ + float sin_pattern = 0.5f+0.5f*sin(400.f*i.uv.y); + return float4( i.element_index * (i.uv.y > 0.5f ? sin_pattern : 0.f), + i.element_index * (i.uv.y <= 0.5f ? sin_pattern : 0.f), + 0.f, + 0.5f+0.5f*i.element_index); +} + +technique10 AudioVisualizationTech +{ + pass + { + SetVertexShader( CompileShader( vs_4_0, AudioVisualizationVS() ) ); + SetGeometryShader( NULL ); + SetHullShader( NULL ); + SetDomainShader( NULL ); + SetPixelShader( CompileShader( ps_4_0, AudioVisualizationPS() ) ); + + SetDepthStencilState( NoDepthStencil, 0 ); + SetRasterizerState( SolidNoCull ); + SetBlendState( Translucent, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF ); + } +}
\ No newline at end of file |