summaryrefslogtreecommitdiff
path: root/demo/ocean_smoke.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_smoke.cpp
downloadwaveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz
waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.zip
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'demo/ocean_smoke.cpp')
-rw-r--r--demo/ocean_smoke.cpp820
1 files changed, 820 insertions, 0 deletions
diff --git a/demo/ocean_smoke.cpp b/demo/ocean_smoke.cpp
new file mode 100644
index 0000000..a9447e4
--- /dev/null
+++ b/demo/ocean_smoke.cpp
@@ -0,0 +1,820 @@
+// 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_smoke.h"
+
+#include "DXUTcamera.h"
+#include "ocean_psm.h"
+#include "ocean_shader_common.h"
+#include "ocean_env.h"
+
+extern HRESULT LoadFile(LPCTSTR FileName, ID3DXBuffer** ppBuffer);
+
+namespace {
+
+ enum { NumRandomUV = (RAND_MAX/2) };
+
+ const float kMaxSimulationTimeStep = 0.06f;
+
+ // noise permutation table
+ const unsigned char kNoisePerms[] = { 151,160,137,91,90,15,
+ 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+ 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+ 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+ 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+ 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+ 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+ 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+ 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+ 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+ 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+ 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+ 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
+ };
+
+ enum { NumNoisePerms = sizeof(kNoisePerms)/sizeof(kNoisePerms[0]) };
+
+ const int kNoiseG4[] = {
+ 0, -1, -1, -1,
+ 0, -1, -1, 1,
+ 0, -1, 1, -1,
+ 0, -1, 1, 1,
+ 0, 1, -1, -1,
+ 0, 1, -1, 1,
+ 0, 1, 1, -1,
+ 0, 1, 1, 1,
+ -1, -1, 0, -1,
+ -1, 1, 0, -1,
+ 1, -1, 0, -1,
+ 1, 1, 0, -1,
+ -1, -1, 0, 1,
+ -1, 1, 0, 1,
+ 1, -1, 0, 1,
+ 1, 1, 0, 1,
+
+ -1, 0, -1, -1,
+ 1, 0, -1, -1,
+ -1, 0, -1, 1,
+ 1, 0, -1, 1,
+ -1, 0, 1, -1,
+ 1, 0, 1, -1,
+ -1, 0, 1, 1,
+ 1, 0, 1, 1,
+ 0, -1, -1, 0,
+ 0, -1, -1, 0,
+ 0, -1, 1, 0,
+ 0, -1, 1, 0,
+ 0, 1, -1, 0,
+ 0, 1, -1, 0,
+ 0, 1, 1, 0,
+ 0, 1, 1, 0,
+ };
+
+ unsigned char encode_noiseg4(int val) {
+ switch(val)
+ {
+ case -1: return 0x80;
+ case 1: return 0x7F;
+ default: return 0;
+ }
+ }
+
+ enum { NumNoiseG4s = sizeof(kNoiseG4)/(4*sizeof(kNoiseG4[0])) };
+
+ enum { kPSMLayersPerSlice = 2 };
+}
+
+OceanSmoke::OceanSmoke()
+{
+ m_pFX = NULL;
+
+ m_pRenderToSceneTechnique = NULL;
+ m_pRenderToPSMTechnique = NULL;
+ m_pEmitParticlesTechnique = NULL;
+ m_pSimulateParticlesTechnique = NULL;
+ m_pBitonicSortTechnique = NULL;
+ m_pMatrixTransposeTechnique = NULL;
+
+ m_pParticleIndexOffsetVariable = NULL;
+ m_pParticleCountVariable = NULL;
+ m_pTimeStepVariable = NULL;
+ m_pPreRollEndTimeVariable = NULL;
+ m_pBuoyancyParamsVariable = NULL;
+ m_pNoiseTimeVariable = NULL;
+ m_pParticleDepthSortUAVVariable = NULL;
+ m_pParticleDepthSortSRVVariable = NULL;
+
+ m_pSimulationInstanceDataVariable = NULL;
+ m_pSimulationVelocitiesVariable = NULL;
+ m_pRandomUVVariable = NULL;
+ m_pRandomOffsetVariable = NULL;
+ m_pCurrEmitterMatrixVariable = NULL;
+ m_pPrevEmitterMatrixVariable = NULL;
+ m_pEmitInterpScaleAndOffsetVariable = NULL;
+ m_pEmitMinMaxVelocityAndSpreadVariable = NULL;
+ m_pEmitAreaScaleVariable = NULL;
+
+ m_pWindDragVariable = NULL;
+ m_pWindVectorAndNoiseMultVariable = NULL;
+
+ m_pTexDiffuseVariable = NULL;
+ m_pRenderInstanceDataVariable = NULL;
+ m_pMatProjVariable = NULL;
+ m_pMatViewVariable = NULL;
+ m_pLightDirectionVariable = NULL;
+ m_pLightColorVariable = NULL;
+ m_pAmbientColorVariable = NULL;
+ m_pFogExponentVariable = NULL;
+ m_pParticleBeginEndScaleVariable = NULL;
+ m_pInvParticleLifeTimeVariable = NULL;
+
+ m_pLightningPositionVariable = NULL;
+ m_pLightningColorVariable = NULL;
+
+ m_ppermTextureVariable = NULL;
+ m_pgradTexture4dVariable = NULL;
+
+ m_pPSMParams = NULL;
+ m_pMatViewToPSMVariable = NULL;
+
+ m_piDepthSortLevelVariable = NULL;
+ m_piDepthSortLevelMaskVariable = NULL;
+ m_piDepthSortWidthVariable = NULL;
+ m_piDepthSortHeightVariable = NULL;
+
+ m_pd3dDevice = DXUTGetD3D11Device();
+ m_pSmokeTextureSRV = NULL;
+ m_pRandomUVSRV = NULL;
+ m_pRenderInstanceDataSRV = NULL;
+ m_pSimulationInstanceDataUAV = NULL;
+ m_pSimulationVelocitiesUAV = NULL;
+ m_ppermTextureSRV = NULL;
+ m_pgradTexture4dSRV = NULL;
+
+ m_pDepthSort1SRV = NULL;
+ m_pDepthSort1UAV = NULL;
+ m_pDepthSort2SRV = NULL;
+ m_pDepthSort2UAV = NULL;
+
+ m_MaxNumParticles = 0;
+ m_ActiveNumParticles = 0;
+ m_NumDepthSortParticles = 0;
+ m_EmitParticleIndex = 0;
+ m_EmitParticleRandomOffset = 0;
+
+ m_ParticleBeginSize = 1.f;
+ m_ParticleEndSize = 1.f;
+ m_EmitMinVelocity = 0.f;
+ m_EmitMaxVelocity = 0.f;
+ m_EmitSpread = 1.f;
+ m_ActualEmitRate = 0.f;
+ m_NominalEmitRate = 0.f;
+ m_TimeToNextEmit = 0.f;
+ m_WindDrag = 1.f;
+ m_MinBuoyancy = 0.f;
+ m_MaxBuoyancy = 1.f;
+ m_CoolingRate = 0.5f;
+ m_NoiseTime = 0.f;
+ m_EmitAreaScale = D3DXVECTOR2(1.f,1.f);
+
+ D3DXMatrixIdentity(&m_EmitterMatrix);
+ m_EmitterMatrixIsValid = false;
+ m_WindVector = D3DXVECTOR3(0.f,0.f,0.f);
+ m_WindVectorIsValid = false;
+}
+
+OceanSmoke::~OceanSmoke()
+{
+ SAFE_RELEASE(m_pFX);
+ SAFE_DELETE(m_pPSMParams);
+
+ SAFE_RELEASE(m_pDepthSort1SRV);
+ SAFE_RELEASE(m_pDepthSort1UAV);
+ SAFE_RELEASE(m_pDepthSort2SRV);
+ SAFE_RELEASE(m_pDepthSort2UAV);
+
+ SAFE_RELEASE(m_pSmokeTextureSRV);
+ SAFE_RELEASE(m_pRandomUVSRV);
+ SAFE_RELEASE(m_pRenderInstanceDataSRV);
+ SAFE_RELEASE(m_pSimulationInstanceDataUAV);
+ SAFE_RELEASE(m_pSimulationVelocitiesUAV);
+ SAFE_RELEASE(m_ppermTextureSRV);
+ SAFE_RELEASE(m_pgradTexture4dSRV);
+}
+
+HRESULT OceanSmoke::init( ID3D11ShaderResourceView* pSmokeTexture,
+ int num_particles,
+ float emit_rate,
+ float particle_begin_size,
+ float particle_end_size,
+ float emit_min_velocity,
+ float emit_max_velocity,
+ float emit_spread,
+ float wind_drag,
+ float min_buoyancy,
+ float max_buoyancy,
+ float cooling_rate,
+ const D3DXVECTOR2& emitAreaScale,
+ float psm_bounds_fade_margin,
+ float shadow_opacity_multiplier,
+ const D3DXVECTOR3& tint_color,
+ float wind_noise_spatial_scale,
+ float wind_noise_time_scale
+ )
+{
+ HRESULT hr;
+
+ m_MaxNumParticles = num_particles;
+ m_ActiveNumParticles = 0;
+ m_EmitParticleIndex = 0;
+ m_EmitParticleRandomOffset = 0;
+ m_ParticleBeginSize = particle_begin_size;
+ m_ParticleEndSize = particle_end_size;
+ m_EmitMinVelocity = emit_min_velocity;
+ m_EmitMaxVelocity = emit_max_velocity;
+ m_EmitSpread = emit_spread;
+ m_NominalEmitRate = emit_rate;
+ m_ActualEmitRate = 0.f;
+ m_TimeToNextEmit = 0.f;
+ m_EmitterMatrixIsValid = false;
+ m_WindVectorIsValid = false;
+ m_WindDrag = wind_drag;
+ m_MinBuoyancy = min_buoyancy;
+ m_MaxBuoyancy = max_buoyancy;
+ m_CoolingRate = cooling_rate;
+ m_NoiseTime = 0.f;
+ m_EmitAreaScale = emitAreaScale;
+ m_TintColor = tint_color;
+
+ // Depth sort works to power of two, so...
+ m_NumDepthSortParticles = 1024;
+ while(m_NumDepthSortParticles < m_MaxNumParticles)
+ m_NumDepthSortParticles *= 2;
+
+ SAFE_RELEASE(m_pSmokeTextureSRV);
+ m_pSmokeTextureSRV = pSmokeTexture;
+ m_pSmokeTextureSRV->AddRef();
+
+ SAFE_RELEASE(m_pFX);
+ ID3DXBuffer* pEffectBuffer = NULL;
+ V_RETURN(LoadFile(TEXT(".\\Media\\ocean_smoke_d3d11.fxo"), &pEffectBuffer));
+ V_RETURN(D3DX11CreateEffectFromMemory(pEffectBuffer->GetBufferPointer(), pEffectBuffer->GetBufferSize(), 0, m_pd3dDevice, &m_pFX));
+ pEffectBuffer->Release();
+
+ m_pRenderToSceneTechnique = m_pFX->GetTechniqueByName("RenderSmokeToSceneTech");
+ m_pRenderToPSMTechnique = m_pFX->GetTechniqueByName("RenderSmokeToPSMTech");
+ m_pEmitParticlesTechnique = m_pFX->GetTechniqueByName("EmitParticlesTech");
+ m_pSimulateParticlesTechnique = m_pFX->GetTechniqueByName("SimulateParticlesTech");
+ m_pBitonicSortTechnique = m_pFX->GetTechniqueByName("BitonicSortTech");
+ m_pMatrixTransposeTechnique = m_pFX->GetTechniqueByName("MatrixTransposeTech");
+
+ m_pParticleIndexOffsetVariable = m_pFX->GetVariableByName("g_ParticleIndexOffset")->AsScalar();
+ m_pParticleCountVariable = m_pFX->GetVariableByName("g_ParticleCount")->AsScalar();
+ m_pTimeStepVariable = m_pFX->GetVariableByName("g_TimeStep")->AsScalar();
+ m_pPreRollEndTimeVariable = m_pFX->GetVariableByName("g_PreRollEndTime")->AsScalar();
+ m_pBuoyancyParamsVariable = m_pFX->GetVariableByName("g_BuoyancyParams")->AsVector();
+ m_pNoiseTimeVariable = m_pFX->GetVariableByName("g_NoiseTime")->AsScalar();
+ m_pParticleDepthSortUAVVariable = m_pFX->GetVariableByName("g_ParticleDepthSortUAV")->AsUnorderedAccessView();
+ m_pParticleDepthSortSRVVariable = m_pFX->GetVariableByName("g_ParticleDepthSortSRV")->AsShaderResource();
+
+ m_pSimulationInstanceDataVariable = m_pFX->GetVariableByName("g_SimulationInstanceData")->AsUnorderedAccessView();
+ m_pSimulationVelocitiesVariable = m_pFX->GetVariableByName("g_SimulationVelocities")->AsUnorderedAccessView();
+ m_pRandomUVVariable = m_pFX->GetVariableByName("g_RandomUV")->AsShaderResource();
+ m_pRandomOffsetVariable = m_pFX->GetVariableByName("g_RandomOffset")->AsScalar();
+ m_pCurrEmitterMatrixVariable = m_pFX->GetVariableByName("g_CurrEmitterMatrix")->AsMatrix();
+ m_pPrevEmitterMatrixVariable = m_pFX->GetVariableByName("g_PrevEmitterMatrix")->AsMatrix();
+ m_pEmitInterpScaleAndOffsetVariable = m_pFX->GetVariableByName("g_EmitInterpScaleAndOffset")->AsVector();
+ m_pEmitMinMaxVelocityAndSpreadVariable = m_pFX->GetVariableByName("g_EmitMinMaxVelocityAndSpread")->AsVector();
+ m_pEmitAreaScaleVariable = m_pFX->GetVariableByName("g_EmitAreaScale")->AsVector();
+
+ m_pWindDragVariable = m_pFX->GetVariableByName("g_WindDrag")->AsScalar();
+ m_pWindVectorAndNoiseMultVariable = m_pFX->GetVariableByName("g_WindVectorAndNoiseMult")->AsVector();
+
+ m_pTexDiffuseVariable = m_pFX->GetVariableByName("g_texDiffuse")->AsShaderResource();
+ m_pRenderInstanceDataVariable = m_pFX->GetVariableByName("g_RenderInstanceData")->AsShaderResource();
+ m_pMatProjVariable = m_pFX->GetVariableByName("g_matProj")->AsMatrix();
+ m_pMatViewVariable = m_pFX->GetVariableByName("g_matView")->AsMatrix();
+ m_pLightDirectionVariable = m_pFX->GetVariableByName("g_LightDirection")->AsVector();
+ m_pLightColorVariable = m_pFX->GetVariableByName("g_LightColor")->AsVector();
+ m_pAmbientColorVariable = m_pFX->GetVariableByName("g_AmbientColor")->AsVector();
+ m_pFogExponentVariable = m_pFX->GetVariableByName("g_FogExponent")->AsScalar();
+ m_pParticleBeginEndScaleVariable = m_pFX->GetVariableByName("g_ParticleBeginEndScale")->AsVector();
+ m_pInvParticleLifeTimeVariable = m_pFX->GetVariableByName("g_InvParticleLifeTime")->AsScalar();
+
+ m_pLightningPositionVariable = m_pFX->GetVariableByName("g_LightningPosition")->AsVector();
+ m_pLightningColorVariable = m_pFX->GetVariableByName("g_LightningColor")->AsVector();
+
+ m_ppermTextureVariable = m_pFX->GetVariableByName("permTexture")->AsShaderResource();
+ m_pgradTexture4dVariable = m_pFX->GetVariableByName("gradTexture4d")->AsShaderResource();
+
+ m_pMatViewToPSMVariable = m_pFX->GetVariableByName("g_matViewToPSM")->AsMatrix();
+ m_pPSMParams = new OceanPSMParams(m_pFX);
+
+ m_piDepthSortLevelVariable = m_pFX->GetVariableByName("g_iDepthSortLevel")->AsScalar();
+ m_piDepthSortLevelMaskVariable = m_pFX->GetVariableByName("g_iDepthSortLevelMask")->AsScalar();
+ m_piDepthSortWidthVariable = m_pFX->GetVariableByName("g_iDepthSortWidth")->AsScalar();
+ m_piDepthSortHeightVariable = m_pFX->GetVariableByName("g_iDepthSortHeight")->AsScalar();
+
+ // Fire-and-forgets
+ m_pFX->GetVariableByName("g_NoiseSpatialScale")->AsScalar()->SetFloat(wind_noise_spatial_scale);
+ m_pFX->GetVariableByName("g_NoiseTimeScale")->AsScalar()->SetFloat(wind_noise_time_scale);
+ m_pFX->GetVariableByName("g_PSMOpacityMultiplier")->AsScalar()->SetFloat(shadow_opacity_multiplier);
+ m_pFX->GetVariableByName("g_PSMFadeMargin")->AsScalar()->SetFloat(psm_bounds_fade_margin);
+
+ // Create buffer for random unit circle
+ {
+ srand(0);
+ FLOAT randomUV[NumRandomUV*2];
+ for(int i = 0; i != NumRandomUV; ++i) {
+ randomUV[2*i+0] = (FLOAT(rand())/RAND_MAX);
+ randomUV[2*i+1] = (FLOAT(rand())/RAND_MAX);
+ }
+
+ D3D11_BUFFER_DESC buffer_desc;
+ buffer_desc.ByteWidth = sizeof(randomUV);
+ buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
+ buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ buffer_desc.CPUAccessFlags = 0;
+ buffer_desc.MiscFlags = 0;
+ buffer_desc.StructureByteStride = 0;
+
+ D3D11_SUBRESOURCE_DATA srd;
+ srd.pSysMem = randomUV;
+ srd.SysMemPitch = 0;
+ srd.SysMemSlicePitch = 0;
+
+ ID3D11Buffer* pBuffer = NULL;
+ V_RETURN(m_pd3dDevice->CreateBuffer(&buffer_desc, &srd, &pBuffer));
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ srv_desc.Format = DXGI_FORMAT_R32G32_FLOAT;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ srv_desc.Buffer.FirstElement = 0;
+ srv_desc.Buffer.NumElements = NumRandomUV;
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pBuffer, &srv_desc, &m_pRandomUVSRV));
+
+ SAFE_RELEASE(pBuffer);
+ }
+
+ // Create noise buffers
+ {
+ D3D11_TEXTURE1D_DESC tex_desc;
+ tex_desc.Width = NumNoisePerms;
+ tex_desc.MipLevels = 1;
+ tex_desc.ArraySize = 1;
+ tex_desc.Format = DXGI_FORMAT_R8_UNORM;
+ tex_desc.Usage = D3D11_USAGE_IMMUTABLE;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ tex_desc.CPUAccessFlags = 0;
+ tex_desc.MiscFlags = 0;
+
+ D3D11_SUBRESOURCE_DATA srd;
+ srd.pSysMem = kNoisePerms;
+ srd.SysMemPitch = sizeof(kNoisePerms);
+ srd.SysMemSlicePitch = 0;
+
+ ID3D11Texture1D* pTex = NULL;
+ V_RETURN(m_pd3dDevice->CreateTexture1D(&tex_desc, &srd, &pTex));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pTex, NULL, &m_ppermTextureSRV));
+
+ SAFE_RELEASE(pTex);
+ }
+
+ {
+ D3D11_TEXTURE1D_DESC tex_desc;
+ tex_desc.Width = NumNoiseG4s;
+ tex_desc.MipLevels = 1;
+ tex_desc.ArraySize = 1;
+ tex_desc.Format = DXGI_FORMAT_R8G8B8A8_SNORM;
+ tex_desc.Usage = D3D11_USAGE_IMMUTABLE;
+ tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ tex_desc.CPUAccessFlags = 0;
+ tex_desc.MiscFlags = 0;
+
+ DWORD tex_data[NumNoiseG4s];
+ for(int i = 0; i != NumNoiseG4s; ++i)
+ {
+ unsigned char r = encode_noiseg4(kNoiseG4[4*i+0]);
+ unsigned char g = encode_noiseg4(kNoiseG4[4*i+1]);
+ unsigned char b = encode_noiseg4(kNoiseG4[4*i+2]);
+ unsigned char a = encode_noiseg4(kNoiseG4[4*i+3]);
+ tex_data[i] = (r << 24) | (g << 16) | (b << 8) | a;
+ }
+
+ D3D11_SUBRESOURCE_DATA srd;
+ srd.pSysMem = tex_data;
+ srd.SysMemPitch = sizeof(tex_data);
+ srd.SysMemSlicePitch = 0;
+
+ ID3D11Texture1D* pTex = NULL;
+ V_RETURN(m_pd3dDevice->CreateTexture1D(&tex_desc, &srd, &pTex));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pTex, NULL, &m_pgradTexture4dSRV));
+
+ SAFE_RELEASE(pTex);
+ }
+
+ // Create simulation buffers
+ {
+ D3D11_BUFFER_DESC buffer_desc;
+ buffer_desc.ByteWidth = m_MaxNumParticles * sizeof(D3DXVECTOR4);
+ buffer_desc.Usage = D3D11_USAGE_DEFAULT;
+ buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
+ buffer_desc.CPUAccessFlags = 0;
+ buffer_desc.MiscFlags = 0;
+ buffer_desc.StructureByteStride = 0;
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ srv_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ srv_desc.Buffer.FirstElement = 0;
+ srv_desc.Buffer.NumElements = m_MaxNumParticles;
+
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc;
+ uav_desc.Format = DXGI_FORMAT_R32_FLOAT;
+ uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ uav_desc.Buffer.FirstElement = 0;
+ uav_desc.Buffer.NumElements = m_MaxNumParticles * 4;
+ uav_desc.Buffer.Flags = 0;
+
+ ID3D11Buffer* pBuffer = NULL;
+ V_RETURN(m_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &pBuffer));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pBuffer, &srv_desc, &m_pRenderInstanceDataSRV));
+ V_RETURN(m_pd3dDevice->CreateUnorderedAccessView(pBuffer, &uav_desc, &m_pSimulationInstanceDataUAV));
+ SAFE_RELEASE(pBuffer);
+
+ V_RETURN(m_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &pBuffer));
+ V_RETURN(m_pd3dDevice->CreateUnorderedAccessView(pBuffer, &uav_desc, &m_pSimulationVelocitiesUAV));
+ SAFE_RELEASE(pBuffer);
+ }
+
+ // Create depth sort buffers
+ {
+ D3D11_BUFFER_DESC buffer_desc;
+ buffer_desc.ByteWidth = 2 * m_NumDepthSortParticles * sizeof(float);
+ buffer_desc.Usage = D3D11_USAGE_DEFAULT;
+ buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
+ buffer_desc.CPUAccessFlags = 0;
+ buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
+ buffer_desc.StructureByteStride = 2 * sizeof(float);
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ srv_desc.Format = DXGI_FORMAT_UNKNOWN;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ srv_desc.Buffer.FirstElement = 0;
+ srv_desc.Buffer.NumElements = m_NumDepthSortParticles;
+
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc;
+ uav_desc.Format = DXGI_FORMAT_UNKNOWN;
+ uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ uav_desc.Buffer.FirstElement = 0;
+ uav_desc.Buffer.NumElements = m_NumDepthSortParticles;
+ uav_desc.Buffer.Flags = 0;
+
+ ID3D11Buffer* pBuffer = NULL;
+ V_RETURN(m_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &pBuffer));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pBuffer, &srv_desc, &m_pDepthSort1SRV));
+ V_RETURN(m_pd3dDevice->CreateUnorderedAccessView(pBuffer, &uav_desc, &m_pDepthSort1UAV));
+ SAFE_RELEASE(pBuffer);
+
+ V_RETURN(m_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &pBuffer));
+ V_RETURN(m_pd3dDevice->CreateShaderResourceView(pBuffer, &srv_desc, &m_pDepthSort2SRV));
+ V_RETURN(m_pd3dDevice->CreateUnorderedAccessView(pBuffer, &uav_desc, &m_pDepthSort2UAV));
+ SAFE_RELEASE(pBuffer);
+ }
+
+ return S_OK;
+}
+
+void OceanSmoke::updateSimulation(ID3D11DeviceContext* pDC, const CBaseCamera& camera, FLOAT time_delta, const D3DXMATRIX& emitterMatrix, const D3DXVECTOR3& wind_vector, const FLOAT wind_noise, FLOAT emit_rate_scale)
+{
+ const D3DXMATRIX prevEmitterMatrix = m_EmitterMatrix;
+ const bool prevEmitterMatrixIsValid = m_EmitterMatrixIsValid;
+
+ m_ActualEmitRate = m_NominalEmitRate * emit_rate_scale;
+
+ // Clear the depth sort (this ensures that pow-2 pad entries are set to -1.f view-space,
+ // which will force them to sort to end)
+ const FLOAT depthSortClearValues[] = {-1.f, -1.f, -1.f, -1.f};
+ pDC->ClearUnorderedAccessViewUint(m_pDepthSort1UAV,(UINT*)depthSortClearValues);
+
+ // Set common params
+ D3DXVECTOR4 vWindVector(wind_vector.x,wind_vector.y,wind_vector.z,wind_noise);
+ m_pWindVectorAndNoiseMultVariable->SetFloatVector((FLOAT*)&vWindVector);
+ m_pWindDragVariable->SetFloat(m_WindDrag);
+
+ D3DXVECTOR4 vBuoyancyParams(m_MinBuoyancy, m_MaxBuoyancy, -m_CoolingRate, 0.f);
+ m_pBuoyancyParamsVariable->SetFloatVector((FLOAT*)&vBuoyancyParams);
+
+ m_ppermTextureVariable->SetResource(m_ppermTextureSRV);
+ m_pgradTexture4dVariable->SetResource(m_pgradTexture4dSRV);
+
+ D3DXMATRIX matView = *camera.GetViewMatrix();
+ m_pMatViewVariable->SetMatrix((FLOAT*)&matView);
+
+ int num_steps = int(ceilf(time_delta/kMaxSimulationTimeStep));
+ FLOAT time_step = time_delta/float(num_steps);
+ FLOAT step_interp_scale = 1.f/float(num_steps);
+ if(0 == num_steps) {
+ // Force through at least one sim step, in order to update depth sort
+ num_steps = 1;
+ time_step = 0.f;
+ step_interp_scale = 1.f;
+ }
+ for(int step = 0; step != num_steps; ++step)
+ {
+ const FLOAT step_interp_offset = float(step) * step_interp_scale;
+ m_pNoiseTimeVariable->SetFloat(m_NoiseTime);
+
+ // Can/should emit?
+ int num_particles_emitted = 0;
+ if(prevEmitterMatrixIsValid) {
+
+ if(time_step < m_TimeToNextEmit) {
+
+ // Time slice too short to emit
+ m_TimeToNextEmit -= time_step;
+
+ } else {
+
+ // Emit particles
+ const float emit_interval = 1.f/m_ActualEmitRate;
+ const int num_particles_to_emit = (int)ceilf((time_step - m_TimeToNextEmit)/emit_interval);
+ if(num_particles_to_emit) {
+
+ m_pTimeStepVariable->SetFloat(time_delta); // NB: We set the entire time slice when emitting, so that we can
+ // interpolate emit positions etc. in a consistent way
+
+ // But this means that we need to subtract the remainder of the timeslice when calculating pre-roll
+ const float pre_roll_end_time = time_step * float(num_steps - step - 1);
+ m_pPreRollEndTimeVariable->SetFloat(pre_roll_end_time);
+
+ m_pParticleIndexOffsetVariable->SetInt(m_EmitParticleIndex);
+ m_pParticleCountVariable->SetInt(num_particles_to_emit);
+
+ m_pSimulationInstanceDataVariable->SetUnorderedAccessView(m_pSimulationInstanceDataUAV);
+ m_pSimulationVelocitiesVariable->SetUnorderedAccessView(m_pSimulationVelocitiesUAV);
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(m_pDepthSort1UAV);
+ m_pRandomUVVariable->SetResource(m_pRandomUVSRV);
+
+ m_pRandomOffsetVariable->SetInt(m_EmitParticleRandomOffset);
+ m_pCurrEmitterMatrixVariable->SetMatrix((FLOAT*)&emitterMatrix);
+ m_pPrevEmitterMatrixVariable->SetMatrix((FLOAT*)&prevEmitterMatrix);
+
+ D3DXVECTOR4 vEmitInterpScaleAndOffset;
+ vEmitInterpScaleAndOffset.y = step_interp_offset + step_interp_scale * m_TimeToNextEmit/time_step;
+ vEmitInterpScaleAndOffset.x = step_interp_scale * emit_interval/time_step;
+ vEmitInterpScaleAndOffset.z = vEmitInterpScaleAndOffset.w = 0.f;
+ m_pEmitInterpScaleAndOffsetVariable->SetFloatVector((FLOAT*)&vEmitInterpScaleAndOffset);
+
+ D3DXVECTOR4 vEmitVelocityMinMaxAndSpread;
+ vEmitVelocityMinMaxAndSpread.x = m_EmitMinVelocity;
+ vEmitVelocityMinMaxAndSpread.y = m_EmitMaxVelocity;
+ vEmitVelocityMinMaxAndSpread.z = m_EmitSpread;
+ vEmitVelocityMinMaxAndSpread.w = 0.f;
+ m_pEmitMinMaxVelocityAndSpreadVariable->SetFloatVector((FLOAT*)&vEmitVelocityMinMaxAndSpread);
+
+ D3DXVECTOR4 vEmitAreaScale;
+ vEmitAreaScale.x = m_EmitAreaScale.x;
+ vEmitAreaScale.y = m_EmitAreaScale.y;
+ vEmitAreaScale.z = 0.f;
+ vEmitAreaScale.w = 0.f;
+ m_pEmitAreaScaleVariable->SetFloatVector((FLOAT*)&vEmitAreaScale);
+
+ const int num_groups = 1+ (num_particles_to_emit-1)/EmitParticlesCSBlocksSize;
+ m_pEmitParticlesTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch(num_groups,1,1);
+
+ // Clear resource usage
+ m_pSimulationInstanceDataVariable->SetUnorderedAccessView(NULL);
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(NULL);
+ m_pEmitParticlesTechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ // Update particle counts/indices
+ num_particles_emitted = num_particles_to_emit;
+ m_EmitParticleIndex = (m_EmitParticleIndex + num_particles_to_emit) % m_MaxNumParticles;
+ m_ActiveNumParticles = min(m_MaxNumParticles,m_ActiveNumParticles+num_particles_to_emit);
+ m_EmitParticleRandomOffset = (m_EmitParticleRandomOffset + 2 * num_particles_to_emit) % NumRandomUV;
+ m_TimeToNextEmit = m_TimeToNextEmit + float(num_particles_to_emit) * emit_interval - time_step;
+ }
+ }
+ }
+
+ // Do simulation (exclude just-emitted particles, which will have had pre-roll)
+ const int num_particles_to_simulate = m_ActiveNumParticles - num_particles_emitted;
+ if(num_particles_to_simulate) {
+
+ int simulate_start_index = 0;
+ if(m_ActiveNumParticles == m_MaxNumParticles) {
+ simulate_start_index = m_EmitParticleIndex;
+ }
+
+ m_pTimeStepVariable->SetFloat(time_step);
+ m_pParticleIndexOffsetVariable->SetInt(simulate_start_index);
+ m_pParticleCountVariable->SetInt(num_particles_to_simulate);
+
+ m_pSimulationInstanceDataVariable->SetUnorderedAccessView(m_pSimulationInstanceDataUAV);
+ m_pSimulationVelocitiesVariable->SetUnorderedAccessView(m_pSimulationVelocitiesUAV);
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(m_pDepthSort1UAV);
+
+ const int num_groups = 1+ (num_particles_to_simulate-1)/SimulateParticlesCSBlocksSize;
+ m_pSimulateParticlesTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch(num_groups,1,1);
+
+ // Clear resource usage
+ m_pSimulationInstanceDataVariable->SetUnorderedAccessView(NULL);
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(NULL);
+ m_pSimulateParticlesTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ }
+
+ // Evolve procedural noise
+ m_NoiseTime += time_step;
+ }
+
+ // Update emitter matrix
+ m_EmitterMatrix = emitterMatrix;
+ m_EmitterMatrixIsValid = true;
+
+ // Update wind
+ m_WindVector = wind_vector;
+ m_WindVectorIsValid = true;
+
+ // Depth-sort ready for rendering
+ if(m_ActiveNumParticles) {
+ depthSortParticles(pDC);
+ }
+}
+
+void OceanSmoke::renderToScene( ID3D11DeviceContext* pDC,
+ const CBaseCamera& camera,
+ OceanPSM* pPSM,
+ const OceanEnvironment& ocean_env
+ )
+{
+ if(0==m_ActiveNumParticles)
+ return;
+
+ // Matrices
+ D3DXMATRIX matView = *camera.GetViewMatrix();
+ D3DXMATRIX matProj = *camera.GetProjMatrix();
+
+ // View-proj
+ m_pMatProjVariable->SetMatrix((FLOAT*)&matProj);
+ m_pMatViewVariable->SetMatrix((FLOAT*)&matView);
+
+ // Global lighting
+ m_pLightDirectionVariable->SetFloatVector((FLOAT*)&ocean_env.main_light_direction);
+ m_pLightColorVariable->SetFloatVector((FLOAT*)&ocean_env.main_light_color);
+ m_pAmbientColorVariable->SetFloatVector((FLOAT*)&ocean_env.sky_color);
+
+ // Lightnings
+ m_pLightningColorVariable->SetFloatVector((FLOAT*)&ocean_env.lightning_light_intensity);
+ m_pLightningPositionVariable->SetFloatVector((FLOAT*)&ocean_env.lightning_light_position);
+
+ // Fog
+ m_pFogExponentVariable->SetFloat(ocean_env.fog_exponent);
+
+ // PSM
+ pPSM->setReadParams(*m_pPSMParams,m_TintColor);
+
+ D3DXMATRIX matInvView;
+ D3DXMatrixInverse(&matInvView, NULL, &matView);
+ D3DXMATRIX matViewToPSM = matInvView * *pPSM->getWorldToPSMUV();
+ m_pMatViewToPSMVariable->SetMatrix((FLOAT*)&matViewToPSM);
+
+ renderParticles(pDC,m_pRenderToSceneTechnique);
+
+ pPSM->clearReadParams(*m_pPSMParams);
+ m_pRenderToSceneTechnique->GetPassByIndex(0)->Apply(0,pDC);
+}
+
+void OceanSmoke::renderToPSM( ID3D11DeviceContext* pDC,
+ OceanPSM* pPSM,
+ const OceanEnvironment& ocean_env
+ )
+{
+ if(0==m_ActiveNumParticles)
+ return;
+
+ m_pMatViewVariable->SetMatrix((FLOAT*)pPSM->getPSMView());
+ m_pMatProjVariable->SetMatrix((FLOAT*)pPSM->getPSMProj());
+ pPSM->setWriteParams(*m_pPSMParams);
+
+ renderParticles(pDC,m_pRenderToPSMTechnique);
+}
+
+void OceanSmoke::renderParticles(ID3D11DeviceContext* pDC, ID3DX11EffectTechnique* pTech)
+{
+ // Particle
+ D3DXVECTOR4 vParticleBeginEndScale(m_ParticleBeginSize, m_ParticleEndSize, 0.f, 0.f);
+ m_pParticleBeginEndScaleVariable->SetFloatVector((FLOAT*)&vParticleBeginEndScale);
+ m_pTexDiffuseVariable->SetResource(m_pSmokeTextureSRV);
+ m_pRenderInstanceDataVariable->SetResource(m_pRenderInstanceDataSRV);
+ m_pParticleDepthSortSRVVariable->SetResource(m_pDepthSort1SRV);
+ m_pInvParticleLifeTimeVariable->SetFloat(m_ActualEmitRate/float(m_MaxNumParticles));
+
+ const int num_particles_to_render = m_ActiveNumParticles;
+ pTech->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->IASetInputLayout(NULL);
+ pDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
+ pDC->Draw(num_particles_to_render,0);
+
+ // Clear resource usage
+ m_pRenderInstanceDataVariable->SetResource(NULL);
+ m_pParticleDepthSortSRVVariable->SetResource(NULL);
+ pTech->GetPassByIndex(0)->Apply(0, pDC);
+}
+
+void OceanSmoke::depthSortParticles(ID3D11DeviceContext* pDC)
+{
+ int num_elements = 1;
+ while(num_elements < m_ActiveNumParticles)
+ {
+ num_elements *= 2;
+ }
+
+ const UINT matrix_width = BitonicSortCSBlockSize;
+ const UINT matrix_height = num_elements / BitonicSortCSBlockSize;
+
+ // First sort the rows for the levels <= to the block size
+ for( UINT level = 2 ; level <= BitonicSortCSBlockSize ; level = level * 2 )
+ {
+ setDepthSortConstants( level, level, matrix_height, matrix_width );
+
+ // Sort the row data
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(m_pDepthSort1UAV);
+ m_pBitonicSortTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch( num_elements / BitonicSortCSBlockSize, 1, 1 );
+ }
+
+ // Then sort the rows and columns for the levels > than the block size
+ // Transpose. Sort the Columns. Transpose. Sort the Rows.
+ for( int level = (BitonicSortCSBlockSize * 2) ; level <= num_elements ; level = level * 2 )
+ {
+ setDepthSortConstants( (level / BitonicSortCSBlockSize), (level & ~num_elements) / BitonicSortCSBlockSize, matrix_width, matrix_height );
+
+ // Transpose the data from buffer 1 into buffer 2
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(m_pDepthSort2UAV);
+ m_pParticleDepthSortSRVVariable->SetResource(m_pDepthSort1SRV);
+ m_pMatrixTransposeTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch( matrix_width / TransposeCSBlockSize, matrix_height / TransposeCSBlockSize, 1 );
+ m_pParticleDepthSortSRVVariable->SetResource(NULL);
+ m_pMatrixTransposeTechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ // Sort the transposed column data
+ m_pBitonicSortTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch( num_elements / BitonicSortCSBlockSize, 1, 1 );
+
+ setDepthSortConstants( BitonicSortCSBlockSize, level, matrix_height, matrix_width );
+
+ // Transpose the data from buffer 2 back into buffer 1
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(m_pDepthSort1UAV);
+ m_pParticleDepthSortSRVVariable->SetResource(m_pDepthSort2SRV);
+ m_pMatrixTransposeTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch( matrix_height / TransposeCSBlockSize, matrix_width / TransposeCSBlockSize, 1 );
+ m_pParticleDepthSortSRVVariable->SetResource(NULL);
+ m_pMatrixTransposeTechnique->GetPassByIndex(0)->Apply(0, pDC);
+
+ // Sort the row data
+ m_pBitonicSortTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ pDC->Dispatch( num_elements / BitonicSortCSBlockSize, 1, 1 );
+ }
+
+ // Release outputs
+ m_pParticleDepthSortUAVVariable->SetUnorderedAccessView(NULL);
+ m_pMatrixTransposeTechnique->GetPassByIndex(0)->Apply(0, pDC);
+ m_pBitonicSortTechnique->GetPassByIndex(0)->Apply(0, pDC);
+}
+
+void OceanSmoke::setDepthSortConstants( UINT iLevel, UINT iLevelMask, UINT iWidth, UINT iHeight )
+{
+ m_piDepthSortLevelVariable->SetInt(iLevel);
+ m_piDepthSortLevelMaskVariable->SetInt(iLevelMask);
+ m_piDepthSortWidthVariable->SetInt(iWidth);
+ m_piDepthSortHeightVariable->SetInt(iHeight);
+}