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_smoke.cpp | |
| download | waveworks_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.cpp | 820 |
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); +} |