summaryrefslogtreecommitdiff
path: root/demo/ocean_surface_heights.cpp
diff options
context:
space:
mode:
authorJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
committerJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
commit79b3462799c28af8ba586349bd671b1b56e72353 (patch)
tree3b06e36c390254c0dc7f3733a0d32af213d87293 /demo/ocean_surface_heights.cpp
downloadwaveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz
waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.zip
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'demo/ocean_surface_heights.cpp')
-rw-r--r--demo/ocean_surface_heights.cpp779
1 files changed, 779 insertions, 0 deletions
diff --git a/demo/ocean_surface_heights.cpp b/demo/ocean_surface_heights.cpp
new file mode 100644
index 0000000..a5dc8d9
--- /dev/null
+++ b/demo/ocean_surface_heights.cpp
@@ -0,0 +1,779 @@
+// 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 "DXUT.h"
+#include "ocean_surface_heights.h"
+#include "GFSDK_WaveWorks.h"
+#include "GFSDK_WaveWorks_D3D_Util.h"
+#include <math.h>
+
+extern HRESULT LoadFile(LPCTSTR FileName, ID3DXBuffer** ppBuffer);
+
+namespace {
+
+ gfsdk_float2 do_rot(const gfsdk_float2& coord, const gfsdk_float2& rot) {
+ gfsdk_float2 result;
+ result.x = coord.x * rot.x + coord.y * rot.y;
+ result.y = -coord.x * rot.y + coord.y * rot.x;
+ return result;
+ }
+
+ gfsdk_float2 do_scale_and_rot(const gfsdk_float2& coord, const gfsdk_float2& scale, const gfsdk_float2& rot) {
+
+ gfsdk_float2 scaled;
+ scaled.x = coord.x * scale.x;
+ scaled.y = coord.y * scale.y;
+
+ return do_rot(scaled,rot);
+ }
+
+ gfsdk_float2 do_inv_scale_and_rot(const gfsdk_float2& coord, const gfsdk_float2& scale, const gfsdk_float2& rot) {
+
+ gfsdk_float2 inv_rot;
+ inv_rot.x = rot.x;
+ inv_rot.y = -rot.y;
+
+ gfsdk_float2 rotated = do_rot(coord,inv_rot);
+
+ gfsdk_float2 result;
+ result.x = rotated.x * 1.f/scale.x;
+ result.y = rotated.y * 1.f/scale.y;
+
+ return result;
+ }
+
+ const int kGPUSampleDensityMultiplier = 4;
+
+ const float kMaxError = 0.01f;
+
+ const int kMaxConvergenceIterations = 20; // Empirically determined
+ const float kConvergenceMultiplier = 0.975f; // Empirically determined
+ const float kProgressiveConvergenceMultiplier = 0.99f; // Empirically determined
+
+ UINT GetShaderInputRegisterMapping( ID3D11ShaderReflection* pReflectionVS,
+ ID3D11ShaderReflection* pReflectionHS,
+ ID3D11ShaderReflection* pReflectionDS,
+ ID3D11ShaderReflection* pReflectionPS,
+ const GFSDK_WaveWorks_ShaderInput_Desc& inputDesc
+ )
+ {
+ ID3D11ShaderReflection* pReflection = NULL;
+ switch(inputDesc.Type)
+ {
+ case GFSDK_WaveWorks_ShaderInput_Desc::VertexShader_FloatConstant:
+ case GFSDK_WaveWorks_ShaderInput_Desc::VertexShader_Sampler:
+ case GFSDK_WaveWorks_ShaderInput_Desc::VertexShader_Texture:
+ case GFSDK_WaveWorks_ShaderInput_Desc::VertexShader_ConstantBuffer:
+ pReflection = pReflectionVS;
+ break;
+ case GFSDK_WaveWorks_ShaderInput_Desc::HullShader_FloatConstant:
+ case GFSDK_WaveWorks_ShaderInput_Desc::HullShader_Sampler:
+ case GFSDK_WaveWorks_ShaderInput_Desc::HullShader_Texture:
+ case GFSDK_WaveWorks_ShaderInput_Desc::HullShader_ConstantBuffer:
+ pReflection = pReflectionHS;
+ break;
+ case GFSDK_WaveWorks_ShaderInput_Desc::DomainShader_FloatConstant:
+ case GFSDK_WaveWorks_ShaderInput_Desc::DomainShader_Sampler:
+ case GFSDK_WaveWorks_ShaderInput_Desc::DomainShader_Texture:
+ case GFSDK_WaveWorks_ShaderInput_Desc::DomainShader_ConstantBuffer:
+ pReflection = pReflectionDS;
+ break;
+ case GFSDK_WaveWorks_ShaderInput_Desc::PixelShader_FloatConstant:
+ case GFSDK_WaveWorks_ShaderInput_Desc::PixelShader_Sampler:
+ case GFSDK_WaveWorks_ShaderInput_Desc::PixelShader_Texture:
+ case GFSDK_WaveWorks_ShaderInput_Desc::PixelShader_ConstantBuffer:
+ pReflection = pReflectionPS;
+ break;
+ default:
+ pReflection = NULL;
+ break;
+ }
+
+ assert(pReflection);
+ D3D11_SHADER_INPUT_BIND_DESC desc;
+ HRESULT hr = pReflection->GetResourceBindingDescByName(inputDesc.Name, &desc);
+ if(FAILED(hr))
+ {
+ // Shader doesn't use this input, mark it as unused
+ return 0xFFFFFFFF;
+ }
+
+ return desc.BindPoint;
+ }
+
+ ID3D11ShaderReflection* GetReflection(const D3DX11_PASS_SHADER_DESC& passShader)
+ {
+ D3DX11_EFFECT_SHADER_DESC shaderDesc;
+ passShader.pShaderVariable->GetShaderDesc(passShader.ShaderIndex, &shaderDesc);
+ ID3D11ShaderReflection* pResult = NULL;
+ D3DReflect(shaderDesc.pBytecode, shaderDesc.BytecodeLength, IID_ID3D11ShaderReflection, (void**)&pResult);
+
+ return pResult;
+ }
+}
+
+OceanSurfaceHeights::OceanSurfaceHeights(int max_num_samples, const gfsdk_float2& UVToWorldScale) :
+ m_UVToWorldScale(UVToWorldScale)
+{
+ // Figure out how to allocate samples to area
+ int num_intervals_l = 1;
+ int num_intervals_w = 1;
+ int num_intervals_stride = 1;
+ if(m_UVToWorldScale.x > m_UVToWorldScale.y) {
+ num_intervals_w = (int)floorf(0.5f + m_UVToWorldScale.x/m_UVToWorldScale.y);
+ } else {
+ num_intervals_l = (int)floorf(0.5f + m_UVToWorldScale.y/m_UVToWorldScale.x);
+ }
+
+ while(((2*num_intervals_l+1)*(2*num_intervals_w+1)) <= max_num_samples) {
+ num_intervals_l *= 2;
+ num_intervals_w *= 2;
+ num_intervals_stride *= 2;
+ }
+
+ m_num_samples_l = num_intervals_l + 1;
+ m_num_samples_w = num_intervals_w + 1;
+ m_max_num_intervals_stride = num_intervals_stride;
+
+ m_num_gpu_samples_l = m_num_samples_l*kGPUSampleDensityMultiplier;
+ m_num_gpu_samples_w = m_num_samples_w*kGPUSampleDensityMultiplier;
+
+ int num_samples = m_num_samples_l * m_num_samples_w;
+
+ m_pTargetSamplePositions = new gfsdk_float2[num_samples];
+ m_pAdjustedSamplePositions = new gfsdk_float2[num_samples];
+ m_pSampleDisplacements = new gfsdk_float4[num_samples];
+ m_pSampleGradients = new gfsdk_float2[num_samples];
+
+ m_pScratchSampleDisplacements = new gfsdk_float4[num_samples];
+ m_pScratchTargetSampleInputs = new gfsdk_float2[num_samples];
+ m_pScratchAdjustedSampleInputs = new gfsdk_float2[num_samples];
+
+ m_pFX = NULL;
+ m_pRenderSurfaceToReverseLookupTechnique = NULL;
+ m_pRenderQuadToUITechnique = NULL;
+ m_pRenderMarkerTechnique = NULL;
+
+ m_pNumQuadsWVariable = NULL;
+ m_pNumQuadsHVariable = NULL;
+ m_pQuadUVDimsVariable = NULL;
+ m_pSrcUVToWorldScaleVariable = NULL;
+ m_pSrcUVToWorldRotationVariable = NULL;
+ m_pSrcUVToWorldOffsetVariable = NULL;
+ m_pWorldToClipScaleVariable = NULL;
+ m_pClipToWorldRotationVariable = NULL;
+ m_pClipToWorldOffsetVariable = NULL;
+ m_pTexDiffuseVariable = NULL;
+ m_pTexLookupVariable = NULL;
+
+ m_pMatViewProjVariable = NULL;
+ m_pMatWorldVariable = NULL;
+ m_pWorldToUVScaleVariable = NULL;
+ m_pWorldToUVRotationVariable = NULL;
+ m_pWorldToUVOffsetVariable = NULL;
+
+ m_pWaterSimulationShaderInputMappings = NULL;
+
+ m_pd3dDevice = DXUTGetD3D11Device();
+ m_pLookupSRV = 0;
+ m_pLookupRTV = 0;
+}
+
+OceanSurfaceHeights::~OceanSurfaceHeights()
+{
+ SAFE_RELEASE(m_pLookupSRV);
+ SAFE_RELEASE(m_pLookupRTV);
+
+ SAFE_RELEASE(m_pFX);
+
+ SAFE_DELETE(m_pTargetSamplePositions);
+ SAFE_DELETE(m_pAdjustedSamplePositions);
+ SAFE_DELETE(m_pSampleDisplacements);
+ SAFE_DELETE(m_pSampleGradients);
+
+ SAFE_DELETE(m_pScratchSampleDisplacements);
+ SAFE_DELETE(m_pScratchTargetSampleInputs);
+ SAFE_DELETE(m_pScratchAdjustedSampleInputs);
+
+ SAFE_DELETE_ARRAY(m_pWaterSimulationShaderInputMappings);
+}
+
+void OceanSurfaceHeights::updateHeights(ID3D11DeviceContext* pDC, GFSDK_WaveWorks_SimulationHandle hSim, const gfsdk_float2& UVToWorldRotation, const gfsdk_float2& worldCentroid)
+{
+ m_UVToWorldRotation = UVToWorldRotation;
+
+ // To get the offset, add rotated and scaled (-0.5,-0.5) to worldCentroid
+ gfsdk_float2 minus_half = {-0.5f,-0.5f};
+ minus_half = do_scale_and_rot(minus_half,m_UVToWorldScale,m_UVToWorldRotation);
+ m_UVToWorldOffset = worldCentroid;
+ m_UVToWorldOffset.x += minus_half.x;
+ m_UVToWorldOffset.y += minus_half.y;
+
+ const int num_intervals_w = m_num_samples_w-1;
+ const int num_intervals_l = m_num_samples_l-1;
+
+ // Initialise sample inputs - note that we slop one sample over in each direction in order
+ // to calculate gradients
+ for(int vi = 0; vi != m_num_samples_l; ++vi) {
+ float v = float(vi-1)/float(num_intervals_l-2);
+ for(int ui = 0; ui != m_num_samples_w; ++ui) {
+ float u = float(ui-1)/float(num_intervals_w-2);
+ gfsdk_float2 coord;
+ coord.x = u;
+ coord.y = v;
+ coord = do_scale_and_rot(coord,m_UVToWorldScale,m_UVToWorldRotation);
+ coord.x += m_UVToWorldOffset.x;
+ coord.y += m_UVToWorldOffset.y;
+ m_pTargetSamplePositions[ui + vi * m_num_samples_w] = coord;
+ }
+ }
+
+ // Initialise coarse samples
+ int num_samples = 0;
+ int num_intervals_stride = m_max_num_intervals_stride;
+ for(int vi = 0; vi < m_num_samples_l; vi += num_intervals_stride) {
+ for(int ui = 0; ui < m_num_samples_w; ui += num_intervals_stride) {
+ gfsdk_float2 coord = m_pTargetSamplePositions[ui + vi * m_num_samples_w];
+ m_pScratchTargetSampleInputs[num_samples] = coord;
+ m_pScratchAdjustedSampleInputs[num_samples] = coord;
+ ++num_samples;
+ }
+ }
+
+ // Do the coarse converge
+ float initial_conv_amt = 1.f;
+ int num_sample_queries = converge_scratch(hSim,num_samples,initial_conv_amt);
+
+ // Copy out into the results area
+ num_samples = 0;
+ for(int vi = 0; vi < m_num_samples_l; vi += num_intervals_stride) {
+ for(int ui = 0; ui < m_num_samples_w; ui += num_intervals_stride) {
+ const int results_ix = ui + vi * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+ }
+ }
+
+ // Progressive refinement
+ while(num_intervals_stride > 1) {
+
+ const int half_stride = num_intervals_stride >> 1;
+
+ // Initialise samples
+ num_samples = 0;
+ for(int vi = 0; vi != num_intervals_l; vi += num_intervals_stride) {
+ for(int ui = 0; ui != num_intervals_w; ui += num_intervals_stride) {
+
+ gfsdk_float2 adj_corner_0 = m_pAdjustedSamplePositions[(ui+0) + (vi+0) * m_num_samples_w];
+ gfsdk_float2 adj_corner_1 = m_pAdjustedSamplePositions[(ui+num_intervals_stride) + (vi+0) * m_num_samples_w];
+ gfsdk_float2 adj_corner_2 = m_pAdjustedSamplePositions[(ui+0) + (vi+num_intervals_stride) * m_num_samples_w];
+ gfsdk_float2 adj_corner_3 = m_pAdjustedSamplePositions[(ui+num_intervals_stride) + (vi+num_intervals_stride) * m_num_samples_w];
+
+ gfsdk_float2 e01, e23, e02, e13, c;
+ e01.x = 0.5f * adj_corner_0.x + 0.5f * adj_corner_1.x;
+ e01.y = 0.5f * adj_corner_0.y + 0.5f * adj_corner_1.y;
+ e23.x = 0.5f * adj_corner_2.x + 0.5f * adj_corner_3.x;
+ e23.y = 0.5f * adj_corner_2.y + 0.5f * adj_corner_3.y;
+ e02.x = 0.5f * adj_corner_0.x + 0.5f * adj_corner_2.x;
+ e02.y = 0.5f * adj_corner_0.y + 0.5f * adj_corner_2.y;
+ e13.x = 0.5f * adj_corner_1.x + 0.5f * adj_corner_3.x;
+ e13.y = 0.5f * adj_corner_1.y + 0.5f * adj_corner_3.y;
+ c.x = 0.5f * e01.x + 0.5f * e23.x;
+ c.y = 0.5f * e01.y + 0.5f * e23.y;
+
+ if(0 == vi) {
+ m_pScratchTargetSampleInputs[num_samples] = m_pTargetSamplePositions[(ui+half_stride) + (vi+0) * m_num_samples_w];
+ m_pScratchAdjustedSampleInputs[num_samples] = e01;
+ ++num_samples;
+ }
+
+ if(0 == ui) {
+ m_pScratchTargetSampleInputs[num_samples] = m_pTargetSamplePositions[(ui+0) + (vi+half_stride) * m_num_samples_w];
+ m_pScratchAdjustedSampleInputs[num_samples] = e02;
+ ++num_samples;
+ }
+
+ m_pScratchTargetSampleInputs[num_samples] = m_pTargetSamplePositions[(ui+num_intervals_stride) + (vi+half_stride) * m_num_samples_w];
+ m_pScratchAdjustedSampleInputs[num_samples] = e13;
+ ++num_samples;
+
+ m_pScratchTargetSampleInputs[num_samples] = m_pTargetSamplePositions[(ui+half_stride) + (vi+num_intervals_stride) * m_num_samples_w];
+ m_pScratchAdjustedSampleInputs[num_samples] = e23;
+ ++num_samples;
+
+ m_pScratchTargetSampleInputs[num_samples] = m_pTargetSamplePositions[(ui+half_stride) + (vi+half_stride) * m_num_samples_w];
+ m_pScratchAdjustedSampleInputs[num_samples] = c;
+ ++num_samples;
+ }
+ }
+
+ // Converge
+ num_sample_queries += converge_scratch(hSim,num_samples,initial_conv_amt);
+
+ // Copy out results
+ num_samples = 0;
+ for(int vi = 0; vi != num_intervals_l; vi += num_intervals_stride) {
+ for(int ui = 0; ui != num_intervals_w; ui += num_intervals_stride) {
+
+ int results_ix;
+
+ if(0 == vi) {
+ results_ix = (ui+half_stride) + (vi+0) * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+ }
+
+ if(0 == ui) {
+ results_ix = (ui+0) + (vi+half_stride) * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+ }
+
+ results_ix = (ui+num_intervals_stride) + (vi+half_stride) * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+
+ results_ix = (ui+half_stride) + (vi+num_intervals_stride) * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+
+ results_ix = (ui+half_stride) + (vi+half_stride) * m_num_samples_w;
+ m_pAdjustedSamplePositions[results_ix] = m_pScratchAdjustedSampleInputs[num_samples];
+ m_pSampleDisplacements[results_ix] = m_pScratchSampleDisplacements[num_samples];
+ ++num_samples;
+ }
+ }
+
+ num_intervals_stride = half_stride;
+ initial_conv_amt *= kProgressiveConvergenceMultiplier;
+ }
+
+ /*
+ static int max_num_sample_queries = 0;
+ if(num_sample_queries > max_num_sample_queries) {
+ max_num_sample_queries = num_sample_queries;
+ char buff[256];
+ sprintf(buff, "Max queries: %d\n", max_num_sample_queries);
+ OutputDebugStringA(buff);
+ }
+ */
+
+ updateGradients();
+}
+
+int OceanSurfaceHeights::converge_scratch(GFSDK_WaveWorks_SimulationHandle hSim, int num_samples, float initial_conv_amt)
+{
+ int num_sample_queries = 0;
+
+ // Converge the scratch samples
+ float rms_error;
+ float convergence_amount = initial_conv_amt;
+ int num_iterations = 0;
+ do {
+
+ GFSDK_WaveWorks_Simulation_GetDisplacements(hSim, m_pScratchAdjustedSampleInputs, m_pScratchSampleDisplacements, num_samples);
+ num_sample_queries += num_samples;
+
+ rms_error = 0.f;
+ for(int sample = 0; sample != num_samples; ++sample) {
+ gfsdk_float2 coord;
+ coord.x = m_pScratchAdjustedSampleInputs[sample].x + m_pScratchSampleDisplacements[sample].x;
+ coord.y = m_pScratchAdjustedSampleInputs[sample].y + m_pScratchSampleDisplacements[sample].y;
+ gfsdk_float2 error;
+ error.x = coord.x - m_pScratchTargetSampleInputs[sample].x;
+ error.y = coord.y - m_pScratchTargetSampleInputs[sample].y;
+ float sqr_error = error.x*error.x + error.y*error.y;
+ rms_error += sqr_error;
+ }
+
+ rms_error = sqrtf(rms_error/float(num_samples));
+
+ if(rms_error > kMaxError) {
+ for(int sample = 0; sample != num_samples; ++sample) {
+ gfsdk_float2 coord;
+ coord.x = m_pScratchAdjustedSampleInputs[sample].x + m_pScratchSampleDisplacements[sample].x;
+ coord.y = m_pScratchAdjustedSampleInputs[sample].y + m_pScratchSampleDisplacements[sample].y;
+ gfsdk_float2 error;
+ error.x = coord.x - m_pScratchTargetSampleInputs[sample].x;
+ error.y = coord.y - m_pScratchTargetSampleInputs[sample].y;
+ m_pScratchAdjustedSampleInputs[sample].x -= convergence_amount * error.x;
+ m_pScratchAdjustedSampleInputs[sample].y -= convergence_amount * error.y;
+ }
+ }
+
+ convergence_amount *= kConvergenceMultiplier; // Converge a bit less each time round
+ ++num_iterations;
+
+ } while (rms_error > kMaxError && num_iterations != kMaxConvergenceIterations);
+
+ // assert(num_iterations != kMaxConvergenceIterations); // Useful to know if we ran out of road!
+
+ /*
+ static int max_num_iterations = 0;
+ if(num_iterations > max_num_iterations) {
+ max_num_iterations = num_iterations;
+ char buff[256];
+ sprintf(buff, "Max iterations: %d\n", max_num_iterations);
+ OutputDebugStringA(buff);
+ }
+ */
+
+ return num_sample_queries;
+}
+
+void OceanSurfaceHeights::getDisplacements(const gfsdk_float2* inSamplePoints, gfsdk_float4* outDisplacements, gfsdk_U32 numSamples) const
+{
+ const float num_intervals_w = float(m_num_samples_w-3); // Not including the 'slop' samples
+ const float num_intervals_l = float(m_num_samples_l-3); // Not including the 'slop' samples
+ for(gfsdk_U32 sample = 0; sample != numSamples; ++sample) {
+
+ // Transform the sample point to UV
+ gfsdk_float2 coord;
+ coord.x = inSamplePoints[sample].x - m_UVToWorldOffset.x;
+ coord.y = inSamplePoints[sample].y - m_UVToWorldOffset.y;
+ coord = do_inv_scale_and_rot(coord,m_UVToWorldScale,m_UVToWorldRotation);
+
+ // Transform UV to non-slop samples
+ coord.x *= num_intervals_w;
+ coord.y *= num_intervals_l;
+ assert(coord.x >= 0.f);
+ assert(coord.x <= num_intervals_w);
+ assert(coord.y >= 0.f);
+ assert(coord.y <= num_intervals_l);
+
+ // Then allow for the slop
+ coord.x += 1.f;
+ coord.y += 1.f;
+
+ float flower_x = floorf(coord.x);
+ float flower_y = floorf(coord.y);
+ int lower_x = int(flower_x);
+ int lower_y = int(flower_y);
+
+ gfsdk_float4* p00 = &m_pSampleDisplacements[(lower_x+0) + (lower_y+0)*m_num_samples_w];
+ gfsdk_float4* p01 = &m_pSampleDisplacements[(lower_x+1) + (lower_y+0)*m_num_samples_w];
+ gfsdk_float4* p10 = &m_pSampleDisplacements[(lower_x+0) + (lower_y+1)*m_num_samples_w];
+ gfsdk_float4* p11 = &m_pSampleDisplacements[(lower_x+1) + (lower_y+1)*m_num_samples_w];
+
+ float frac_x = coord.x - float(lower_x);
+ float frac_y = coord.y - float(lower_y);
+
+ outDisplacements[sample].x = (1.f-frac_x)*(1.f-frac_y)*p00->x + frac_x*(1.f-frac_y)*p01->x + (1.f-frac_x)*frac_y*p10->x + frac_x*frac_y*p11->x;
+ outDisplacements[sample].y = (1.f-frac_x)*(1.f-frac_y)*p00->y + frac_x*(1.f-frac_y)*p01->y + (1.f-frac_x)*frac_y*p10->y + frac_x*frac_y*p11->y;
+ outDisplacements[sample].z = (1.f-frac_x)*(1.f-frac_y)*p00->z + frac_x*(1.f-frac_y)*p01->z + (1.f-frac_x)*frac_y*p10->z + frac_x*frac_y*p11->z;
+ outDisplacements[sample].w = (1.f-frac_x)*(1.f-frac_y)*p00->w + frac_x*(1.f-frac_y)*p01->w + (1.f-frac_x)*frac_y*p10->w + frac_x*frac_y*p11->w;
+ }
+}
+
+void OceanSurfaceHeights::getGradients(const gfsdk_float2* inSamplePoints, gfsdk_float2* outGradients, gfsdk_U32 numSamples) const
+{
+ const float num_intervals_w = float(m_num_samples_w-3); // Not including the 'slop' samples
+ const float num_intervals_l = float(m_num_samples_l-3); // Not including the 'slop' samples
+ for(gfsdk_U32 sample = 0; sample != numSamples; ++sample) {
+
+ // Transform the sample point to UV
+ gfsdk_float2 coord;
+ coord.x = inSamplePoints[sample].x - m_UVToWorldOffset.x;
+ coord.y = inSamplePoints[sample].y - m_UVToWorldOffset.y;
+ coord = do_inv_scale_and_rot(coord,m_UVToWorldScale,m_UVToWorldRotation);
+
+ // Transform UV to non-slop samples
+ coord.x *= num_intervals_w;
+ coord.y *= num_intervals_l;
+ assert(coord.x >= 0.f);
+ assert(coord.x <= num_intervals_w);
+ assert(coord.y >= 0.f);
+ assert(coord.y <= num_intervals_l);
+
+ // Then allow for the slop
+ coord.x += 1.f;
+ coord.y += 1.f;
+
+ float flower_x = floorf(coord.x);
+ float flower_y = floorf(coord.y);
+ int lower_x = int(flower_x);
+ int lower_y = int(flower_y);
+
+ gfsdk_float2* p00 = &m_pSampleGradients[(lower_x+0) + (lower_y+0)*m_num_samples_w];
+ gfsdk_float2* p01 = &m_pSampleGradients[(lower_x+1) + (lower_y+0)*m_num_samples_w];
+ gfsdk_float2* p10 = &m_pSampleGradients[(lower_x+0) + (lower_y+1)*m_num_samples_w];
+ gfsdk_float2* p11 = &m_pSampleGradients[(lower_x+1) + (lower_y+1)*m_num_samples_w];
+
+ float frac_x = coord.x - float(lower_x);
+ float frac_y = coord.y - float(lower_y);
+
+ outGradients[sample].x = (1.f-frac_x)*(1.f-frac_y)*p00->x + frac_x*(1.f-frac_y)*p01->x + (1.f-frac_x)*frac_y*p10->x + frac_x*frac_y*p11->x;
+ outGradients[sample].y = (1.f-frac_x)*(1.f-frac_y)*p00->y + frac_x*(1.f-frac_y)*p01->y + (1.f-frac_x)*frac_y*p10->y + frac_x*frac_y*p11->y;
+ }
+}
+
+void OceanSurfaceHeights::updateGradients()
+{
+ const float u_scale = 0.5f*float(m_num_samples_w-3)/m_UVToWorldScale.x;
+ const float v_scale = 0.5f*float(m_num_samples_l-3)/m_UVToWorldScale.y;
+ for(int vi = 1; vi != m_num_samples_l-1; ++vi) {
+ for(int ui = 1; ui != m_num_samples_w-1; ++ui) {
+ float u_neg = m_pSampleDisplacements[(ui-1) + (vi+0)*m_num_samples_w].z;
+ float u_pos = m_pSampleDisplacements[(ui+1) + (vi+0)*m_num_samples_w].z;
+ float v_neg = m_pSampleDisplacements[(ui+0) + (vi-1)*m_num_samples_w].z;
+ float v_pos = m_pSampleDisplacements[(ui+0) + (vi+1)*m_num_samples_w].z;
+
+ gfsdk_float2 grad;
+ grad.x = u_scale*(u_pos-u_neg);
+ grad.y = v_scale*(v_pos-v_neg);
+
+ m_pSampleGradients[ui + vi*m_num_samples_w] = do_rot(grad,m_UVToWorldRotation);
+ }
+ }
+}
+
+HRESULT OceanSurfaceHeights::init()
+{
+ HRESULT hr;
+
+ SAFE_RELEASE(m_pFX);
+ ID3DXBuffer* pEffectBuffer = NULL;
+ V_RETURN(LoadFile(TEXT(".\\Media\\ocean_surface_heights_d3d11.fxo"), &pEffectBuffer));
+ V_RETURN(D3DX11CreateEffectFromMemory(pEffectBuffer->GetBufferPointer(), pEffectBuffer->GetBufferSize(), 0, m_pd3dDevice, &m_pFX));
+ pEffectBuffer->Release();
+
+ m_pRenderSurfaceToReverseLookupTechnique = m_pFX->GetTechniqueByName("RenderSurfaceToReverseLookupTech");
+ m_pRenderQuadToUITechnique = m_pFX->GetTechniqueByName("RenderQuadToUITech");
+ m_pRenderMarkerTechnique = m_pFX->GetTechniqueByName("RenderMarkerTech");
+
+ m_pNumQuadsWVariable = m_pFX->GetVariableByName("g_numQuadsW")->AsScalar();
+ m_pNumQuadsHVariable = m_pFX->GetVariableByName("g_numQuadsH")->AsScalar();
+ m_pQuadUVDimsVariable = m_pFX->GetVariableByName("g_quadUVDims")->AsVector();
+ m_pSrcUVToWorldScaleVariable = m_pFX->GetVariableByName("g_srcUVToWorldScale")->AsVector();
+ m_pSrcUVToWorldRotationVariable = m_pFX->GetVariableByName("g_srcUVToWorldRot")->AsVector();
+ m_pSrcUVToWorldOffsetVariable = m_pFX->GetVariableByName("g_srcUVToWorldOffset")->AsVector();
+ m_pWorldToClipScaleVariable = m_pFX->GetVariableByName("g_worldToClipScale")->AsVector();
+ m_pClipToWorldRotationVariable = m_pFX->GetVariableByName("g_clipToWorldRot")->AsVector();
+ m_pClipToWorldOffsetVariable = m_pFX->GetVariableByName("g_clipToWorldOffset")->AsVector();
+ m_pTexDiffuseVariable = m_pFX->GetVariableByName("g_texDiffuse")->AsShaderResource();
+ m_pTexLookupVariable = m_pFX->GetVariableByName("g_texLookup")->AsShaderResource();
+
+ m_pMatViewProjVariable = m_pFX->GetVariableByName("g_matViewProj")->AsMatrix();
+ m_pMatWorldVariable = m_pFX->GetVariableByName("g_matWorld")->AsMatrix();
+ m_pWorldToUVScaleVariable =m_pFX->GetVariableByName("g_worldToUVScale")->AsVector();
+ m_pWorldToUVRotationVariable =m_pFX->GetVariableByName("g_worldToUVRot")->AsVector();
+ m_pWorldToUVOffsetVariable =m_pFX->GetVariableByName("g_worldToUVOffset")->AsVector();
+
+ UINT NumSimulationShaderInputs = GFSDK_WaveWorks_Simulation_GetShaderInputCountD3D11();
+ m_pWaterSimulationShaderInputMappings = new UINT[NumSimulationShaderInputs];
+
+ D3DX11_PASS_SHADER_DESC passShaderDesc;
+ ID3DX11EffectPass* pRenderSurfaceToReverseLookupPass = m_pRenderSurfaceToReverseLookupTechnique->GetPassByIndex(0);
+
+ V_RETURN(pRenderSurfaceToReverseLookupPass->GetVertexShaderDesc(&passShaderDesc));
+ ID3D11ShaderReflection* pShadedReflectionVS = GetReflection(passShaderDesc);
+
+ V_RETURN(pRenderSurfaceToReverseLookupPass->GetHullShaderDesc(&passShaderDesc));
+ ID3D11ShaderReflection* pShadedReflectionHS = GetReflection(passShaderDesc);
+
+ V_RETURN(pRenderSurfaceToReverseLookupPass->GetDomainShaderDesc(&passShaderDesc));
+ ID3D11ShaderReflection* pShadedReflectionDS = GetReflection(passShaderDesc);
+
+ V_RETURN(pRenderSurfaceToReverseLookupPass->GetPixelShaderDesc(&passShaderDesc));
+ ID3D11ShaderReflection* pShadedReflectionPS = GetReflection(passShaderDesc);
+
+ for(UINT i = 0; i != NumSimulationShaderInputs; ++i)
+ {
+ GFSDK_WaveWorks_ShaderInput_Desc inputDesc;
+ GFSDK_WaveWorks_Simulation_GetShaderInputDescD3D11(i, &inputDesc);
+
+ m_pWaterSimulationShaderInputMappings[i] = GetShaderInputRegisterMapping(pShadedReflectionVS, pShadedReflectionHS, pShadedReflectionDS, pShadedReflectionPS, inputDesc);
+ }
+
+ {
+ SAFE_RELEASE(m_pLookupSRV);
+ SAFE_RELEASE(m_pLookupRTV);
+ ID3D11Texture2D* pTexture = NULL;
+
+ // Set up textures for rendering hull profile
+ D3D11_TEXTURE2D_DESC tex_desc;
+ tex_desc.Width = (m_num_gpu_samples_w-2);
+ tex_desc.Height = (m_num_gpu_samples_l-2);
+ tex_desc.ArraySize = 1;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ tex_desc.CPUAccessFlags = 0;
+ tex_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
+ tex_desc.MipLevels = 1;
+ tex_desc.MiscFlags = 0;
+ tex_desc.SampleDesc.Count = 1;
+ tex_desc.SampleDesc.Quality = 0;
+ tex_desc.Usage = D3D11_USAGE_DEFAULT;
+
+ V_RETURN(m_pd3dDevice->CreateTexture2D(&tex_desc,NULL,&pTexture));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pTexture,NULL,&m_pLookupSRV));
+ V_RETURN(m_pd3dDevice->CreateRenderTargetView(pTexture,NULL,&m_pLookupRTV));
+ SAFE_RELEASE(pTexture);
+ }
+
+ return S_OK;
+}
+
+void OceanSurfaceHeights::renderTextureToUI(ID3D11DeviceContext* pDC) const
+{
+ m_pTexDiffuseVariable->SetResource(getGPULookupSRV());
+ m_pRenderQuadToUITechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ pDC->IASetInputLayout(NULL);
+ pDC->Draw(4,0);
+
+ m_pTexDiffuseVariable->SetResource(NULL);
+ m_pRenderQuadToUITechnique->GetPassByIndex(0)->Apply(0, pDC);
+}
+
+void OceanSurfaceHeights::getGPUWorldToUVTransform(gfsdk_float2& offset, gfsdk_float2& rot, gfsdk_float2& scale) const
+{
+ // To match CPU sampling, a sample at the min corner of the footprint (worldToUVOffset) should map to (0,0) whereas a sample
+ // at the max corner should map to (m_num_gpu_samples_w-3,m_num_gpu_samples_l-3), hence...
+ const float world_quad_size_w = m_UVToWorldScale.x/float(m_num_gpu_samples_w-3);
+ const float world_quad_size_h = m_UVToWorldScale.y/float(m_num_gpu_samples_l-3);
+ scale.x = 1.f/(m_UVToWorldScale.x+world_quad_size_w);
+ scale.y = 1.f/(m_UVToWorldScale.y+world_quad_size_h);
+ offset.x = -m_UVToWorldOffset.x;
+ offset.y = -m_UVToWorldOffset.y;
+ rot.x = m_UVToWorldRotation.x;
+ rot.y = -m_UVToWorldRotation.y;
+}
+
+void OceanSurfaceHeights::renderMarkerArray(ID3D11DeviceContext* pDC, const D3DXMATRIX& matViewProj, const D3DXMATRIX& matWorld) const
+{
+ m_pTexLookupVariable->SetResource(getGPULookupSRV());
+ m_pMatViewProjVariable->SetMatrix((float*)&matViewProj);
+ m_pMatWorldVariable->SetMatrix((float*)&matWorld);
+
+ gfsdk_float2 worldToUVScale;
+ gfsdk_float2 worldToUVOffset;
+ gfsdk_float2 worldToUVRot;
+ getGPUWorldToUVTransform(worldToUVOffset, worldToUVRot, worldToUVScale);
+
+ m_pWorldToUVScaleVariable->SetFloatVector((float*)&worldToUVScale);
+ m_pWorldToUVRotationVariable->SetFloatVector((float*)&worldToUVRot);
+ m_pWorldToUVOffsetVariable->SetFloatVector((float*)&worldToUVOffset);
+
+ m_pRenderMarkerTechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ pDC->IASetInputLayout(NULL);
+ pDC->Draw(300,0);
+
+ m_pTexLookupVariable->SetResource(NULL);
+ m_pRenderMarkerTechnique->GetPassByIndex(0)->Apply(0, pDC);
+}
+
+void OceanSurfaceHeights::updateGPUHeights(ID3D11DeviceContext* pDC, GFSDK_WaveWorks_SimulationHandle hSim, const D3DXMATRIX& matView)
+{
+ // Not strictly necessary, but good for debugging and SLI
+ FLOAT clearColor[] = {1.f,0.f,1.f,1.f};
+ pDC->ClearRenderTargetView(m_pLookupRTV, clearColor);
+
+ // We inflate the rendered area by the conservative displacement amount to make sure we overlap the target
+ // with enough slop to absorb displacements
+ const float min_inflate_amount = GFSDK_WaveWorks_Simulation_GetConservativeMaxDisplacementEstimate(hSim);
+
+ // Expand number of quads to match slop
+ const float world_quad_size_w = m_UVToWorldScale.x/float(m_num_gpu_samples_w-3);
+ const float world_quad_size_h = m_UVToWorldScale.y/float(m_num_gpu_samples_l-3);
+ const int extra_quads_w = (int)ceilf(min_inflate_amount/world_quad_size_w);
+ const int extra_quads_h = (int)ceilf(min_inflate_amount/world_quad_size_h);
+ const float inflate_w = float(extra_quads_w)*world_quad_size_w;
+ const float inflate_h = float(extra_quads_h)*world_quad_size_h;
+ const int quads_w = (m_num_gpu_samples_w-2) + 2 * extra_quads_w;
+ const int quads_h = (m_num_gpu_samples_l-2) + 2 * extra_quads_h;
+
+ // Note that our CPU sampling scheme is somewhat different from conventional GPU sampling,
+ // hence we have an extra quad's worth of world space in play to ensure coverage of all the
+ // texels in the lookup
+ gfsdk_float2 srcUVToWorld_additional_offset = {-inflate_w-0.5f*world_quad_size_w,-inflate_h-0.5f*world_quad_size_h};
+ srcUVToWorld_additional_offset = do_rot(srcUVToWorld_additional_offset,m_UVToWorldRotation);
+
+ gfsdk_float2 srcUVToWorldOffset = m_UVToWorldOffset;
+ srcUVToWorldOffset.x += srcUVToWorld_additional_offset.x;
+ srcUVToWorldOffset.y += srcUVToWorld_additional_offset.y;
+
+ gfsdk_float2 srcUVToWorldScale = m_UVToWorldScale;
+ srcUVToWorldScale.x += 2.f * inflate_w + world_quad_size_w;
+ srcUVToWorldScale.y += 2.f * inflate_h + world_quad_size_h;
+
+ m_pSrcUVToWorldScaleVariable->SetFloatVector((FLOAT*)&srcUVToWorldScale);
+ m_pSrcUVToWorldRotationVariable->SetFloatVector((FLOAT*)&m_UVToWorldRotation);
+ m_pSrcUVToWorldOffsetVariable->SetFloatVector((FLOAT*)&srcUVToWorldOffset);
+
+ // World to clip are inverse of vanilla forwards, but with the additional half-quad offset to
+ // match CPU sampling scheme
+ gfsdk_float2 worldToClipScale;
+ worldToClipScale.x = 1.f/(m_UVToWorldScale.x+world_quad_size_w);
+ worldToClipScale.y = 1.f/(m_UVToWorldScale.y+world_quad_size_h);
+
+ gfsdk_float2 clipToWorld_additional_offset = {-0.5f*world_quad_size_w,-0.5f*world_quad_size_h};
+ clipToWorld_additional_offset = do_rot(clipToWorld_additional_offset,m_UVToWorldRotation);
+
+ gfsdk_float2 clipToWorldOffset = m_UVToWorldOffset;
+ clipToWorldOffset.x += clipToWorld_additional_offset.x;
+ clipToWorldOffset.y += clipToWorld_additional_offset.y;
+
+ m_pWorldToClipScaleVariable->SetFloatVector((FLOAT*)&worldToClipScale);
+ m_pClipToWorldRotationVariable->SetFloatVector((FLOAT*)&m_UVToWorldRotation);
+ m_pClipToWorldOffsetVariable->SetFloatVector((FLOAT*)&clipToWorldOffset);
+
+ // Quads setup
+ float quadsWH[] = {float(quads_w),float(quads_h)};
+ m_pNumQuadsWVariable->SetFloat(quadsWH[0]);
+ m_pNumQuadsHVariable->SetFloat(quadsWH[1]);
+ float quadUVdims[] = {1.f/float(quads_w),1.f/float(quads_h)};
+ m_pQuadUVDimsVariable->SetFloatVector(quadUVdims);
+
+ // Preserve original viewports
+ D3D11_VIEWPORT original_viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ UINT num_original_viewports = sizeof(original_viewports)/sizeof(original_viewports[0]);
+ pDC->RSGetViewports( &num_original_viewports, original_viewports);
+
+ // RTV setup
+ pDC->OMSetRenderTargets(1,&m_pLookupRTV,NULL);
+ const D3D11_VIEWPORT viewport = {0.f, 0.f, FLOAT(m_num_gpu_samples_w-2), FLOAT(m_num_gpu_samples_l-2), 0.f, 1.f };
+ pDC->RSSetViewports(1,&viewport);
+
+ // Render
+ m_pRenderSurfaceToReverseLookupTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ GFSDK_WaveWorks_Simulation_SetRenderStateD3D11(hSim, pDC, NvFromDX(matView), m_pWaterSimulationShaderInputMappings, NULL);
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST);
+ pDC->IASetInputLayout(NULL);
+ pDC->Draw(4*quads_w*quads_h,0);
+
+ // Restore viewports
+ pDC->RSSetViewports(num_original_viewports,original_viewports);
+}