123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #pragma once
- #include <AzCore/base.h>
- #include <AzCore/Math/Vector3.h>
- #include <Atom/RHI/DeviceBufferView.h>
- #include <Atom/RHI/DrawPacketBuilder.h>
- #include <Atom/RHI/GeometryView.h>
- // Hair specific
- #include <TressFX/AMD_TressFX.h>
- #include <TressFX/AMD_Types.h>
- #include <TressFX/TressFXConstantBuffers.h>
- #include <Rendering/HairCommon.h>
- #include <Rendering/SharedBuffer.h>
- #include <Rendering/HairDispatchItem.h>
- #include <Rendering/HairBuffersSemantics.h>
- #define TRESSFX_MIN_VERTS_PER_STRAND_FOR_GPU_ITERATION 64
- namespace AMD
- {
- struct float4x4;
- class TressFXAsset;
- class TressFXRenderingSettings;
- class TressFXSimulationSettings;
- }
- namespace AZ
- {
- namespace RHI
- {
- class DrawPacket;
- }
- namespace RPI
- {
- class Model;
- class Scene;
- class Shader;
- }
- namespace Render
- {
- namespace Hair
- {
- class HairFeatureProcessor;
- //! TressFXStrandLevelData represents blended bone data per hair strand that once calculated
- //! is passed between the skinning pass and the simulation shape constraints pass
- struct TressFXStrandLevelData
- {
- AMD::float4 skinningQuat;
- AMD::float4 vspQuat;
- AMD::float4 vspTranslation;
- };
- //!-----------------------------------------------------------------------------------------
- //!
- //! DynamicHairData
- //!
- //!-----------------------------------------------------------------------------------------
- //! Contains the writable data that is passed and used by 3 modules:
- //! simulation, signed distance field (collisions), and rendering.
- //! Rendering uses current position and tangent as SRVs in VS for computing creation and skinning.
- //! Since this data is per object (hence per object dispatch) and requires sync point (barrier) between the
- //! the passes, a single buffer is allocated and is shared by all hair objects and their 'streams'
- //! where each have buffer view so that it points to its own portion of the original buffer's data.
- //! The shared buffer is therefore declared in the pass Srg to result in an execution dependency
- //! so that a barrier will be created. It also represents less overhead since we are using a single
- //! coordinated / shared buffer sync point rather than many barriers (per object per buffer).
- //!-----------------------------------------------------------------------------------------
- class DynamicHairData
- {
- friend class HairRenderObject;
- public:
- //! Creates the GPU dynamic buffers of a single hair object
- //! Equivalent to TressFXDynamicHairData::CreateGPUResources
- bool CreateDynamicGPUResources(
- Data::Instance<RPI::Shader> computeShader,
- Data::Instance<RPI::Shader> rasterShader,
- uint32_t vertexCount, uint32_t strandsCount);
- //! Data upload - copy the hair mesh asset data (positions and tangents) into the buffers.
- //! In the following line I assume that positions and tangents are of the same size.
- //! Equivalent to: TressFXDynamicHairData::UploadGPUData
- bool UploadGPUData(const char* name, void* positions, void* tangents);
- //! Preparation of the descriptors table of all the dynamic stream buffers within the class.
- //! Do not call this method before calling CreateAndBindGPUResources as it is already called
- //! from CreateAndBindGPUResources.
- //! This method can be called also for retrieving the descriptors table (SharedBuffer)
- static void PrepareSrgDescriptors(
- AZStd::vector<SrgBufferDescriptor>& descriptorArray,
- int32_t vertexCount, uint32_t strandsCount);
- void PrepareSrgDescriptors(int32_t vertexCount, uint32_t strandsCount)
- {
- PrepareSrgDescriptors(m_dynamicBuffersDescriptors, vertexCount, strandsCount);
- }
-
- Data::Instance<RPI::ShaderResourceGroup> GetSimSrgForCompute()
- {
- return m_initialized ? m_simSrgForCompute : nullptr;
- }
- Data::Instance<RPI::ShaderResourceGroup> GetSimSrgForRaster()
- {
- return m_initialized ? m_simSrgForRaster : nullptr; }
- bool IsInitialized() { return m_initialized; }
- private:
- //! Matching between the buffers Srg and its buffers descriptors, this method fills the Srg with
- //! the views of the buffers to be used by the hair instance.
- bool BindPerObjectSrgForCompute();
- bool BindPerObjectSrgForRaster();
- //! The descriptors required to allocate and associate the dynamic buffers with the SRGs
- //! Each descriptor also contains the byte offsets of the sub-buffers in the global dynamic
- //! array for the data copy.
- AZStd::vector<SrgBufferDescriptor> m_dynamicBuffersDescriptors;
- //! The following dynamic buffer views are views 'sub-buffers' located within a global large
- //! dynamic buffer exposed and connected as an attachment between the passes and therefore
- //! creates both dependency order between passes execution and sync point barrier.
- //! This indirectly forces the sync to be applied to all 'sub-buffers' used by each of the
- //! HairObjects / HairDispatches and therefore allows us to change their data in the shader
- //! between passes.
- AZStd::vector<Data::Instance<RHI::BufferView>> m_dynamicBuffersViews; // RW used for the Compute
- AZStd::vector<Data::Instance<RHI::BufferView>> m_readBuffersViews; // Read only used for the Raster fill
- //! The following vector is required in order to keep the allocators 'alive' or
- //! else they are cleared from the buffer via the reference mechanism.
- AZStd::vector<Data::Instance<HairSharedBufferAllocation>> m_dynamicViewAllocators;
- //------------------------------------------------------------------
- //! The following SRGs are the ones represented by this class' data.
- //! These Srgs are required for the changed dynamic data passed between the
- //! skinning, simulation and rendering passes / shaders.
- //! It is the TressFX equivalent of the set:
- //! - pSimPosTanLayout / m_pSimBindSets
- //------------------------------------------------------------------
- Data::Instance<RPI::ShaderResourceGroup> m_simSrgForCompute; //! TressFX equivalent: pSimPosTanLayout / m_pSimBindSets
- Data::Instance<RPI::ShaderResourceGroup> m_simSrgForRaster; //! Targeting only the Fill pass / shader
- bool m_initialized = false;
- };
- //!-----------------------------------------------------------------------------------------
- //!
- //! HairRenderObject
- //!
- //!-----------------------------------------------------------------------------------------
- //! This class is equivalent to TressFXHairObject and HairStrands (the later is mainly a wrapper).
- //! This is the class that holds all the raw data used by all the hair passes and shaders.
- //!-----------------------------------------------------------------------------------------
- class HairRenderObject final
- : public Data::InstanceData
- {
- friend HairFeatureProcessor;
- public:
- AZ_RTTI(HairRenderObject, "{58F48A58-C5B9-4CAE-9AFD-9B3AF3A01C73}");
- HairRenderObject() = default;
- ~HairRenderObject();
- void Release();
- bool Init(
- HairFeatureProcessor* featureProcessor, const char* assetName, AMD::TressFXAsset* asset,
- AMD::TressFXSimulationSettings* simSettings, AMD::TressFXRenderingSettings* renderSettings
- );
- bool BuildDrawPacket(RPI::Shader* geometryShader, RHI::DrawPacketBuilder::DrawRequest& drawRequest);
- const RHI::DrawPacket* GetGeometrylDrawPacket(RPI::Shader* geometryShader);
- //! Creates and fill the dispatch item associated with the compute shader
- bool BuildDispatchItem(RPI::Shader* computeShader, DispatchLevel dispatchLevel);
- const RHI::DispatchItem* GetDispatchItem(RPI::Shader* computeShader);
- void PrepareHairGenerationSrgDescriptors(uint32_t vertexCount, uint32_t numStrands);
- // Based on SkinnedMeshInputLod::CreateStaticBuffer
- bool CreateAndBindHairGenerationBuffers(uint32_t vertexCount, uint32_t strandsCount);
- //! Updates the buffers data for the hair generation.
- //! Does NOT update the bone matrices - they will be updated every frame.
- bool UploadGPUData(const char* name, AMD::TressFXAsset* asset);
- Data::Instance<RPI::ShaderResourceGroup> GetHairGenerationSrg()
- {
- return m_hairGenerationSrg;
- }
- bool BindPerObjectSrgForCompute()
- {
- return m_dynamicHairData.IsInitialized() ? m_dynamicHairData.BindPerObjectSrgForCompute() : false;
- }
- bool BindPerObjectSrgForRaster()
- {
- return m_dynamicHairData.IsInitialized() ? m_dynamicHairData.BindPerObjectSrgForRaster() : false;
- }
- //!-----------------------------------------------------------------
- //! Methods partially imported from TressFXHairObject
- //!-----------------------------------------------------------------
- int GetNumTotalHairVertices() const { return m_NumTotalVertices; }
- int GetNumTotalHairStrands() const { return m_NumTotalStrands; }
- int GetNumVerticesPerStrand() const { return m_NumVerticesPerStrand; }
- int GetCPULocalShapeIterations() const { return m_CPULocalShapeIterations; }
- int GetNumFollowHairsPerGuideHair() const { return m_NumFollowHairsPerGuideHair; }
- int GetNumGuideHairs() const
- {
- return GetNumTotalHairStrands() / (GetNumFollowHairsPerGuideHair() + 1);
- }
- //! This method is mainly a wrapper around BindRenderSrgResources to keep the
- //! connection in code to the TressFX method.
- //! Bind Render Srg (m_hairRenderSrg) resources. No resources data update should be doe here
- //! Notice that this also loads the images and is slower if a new asset is required.
- //! If the image was not changed it should only bind without the retrieve operation.
- bool PopulateDrawStrandsBindSet(AMD::TressFXRenderingSettings* pRenderSettings/*=nullptr*/);
- // This function will be called when the image asset changed for the component.
- bool LoadImageAsset(AMD::TressFXRenderingSettings* pRenderSettings);
- bool UploadRenderingGPUResources(AMD::TressFXAsset& asset);
- //! Creation of the render Srg m_hairRenderSrg, followed by creation and binding of the
- //! GPU render resources: vertex thickness, vertex UV, hair albedo maps and two constant buffers.
- bool CreateRenderingGPUResources(
- Data::Instance<RPI::Shader> shader, AMD::TressFXAsset& asset, const char* assetName);
- bool Update();
- //! This method needs to be called in order to fill the bone matrices before the skinning
- void UpdateBoneMatrices(const AMD::float4x4* pBoneMatricesInWS, int numBoneMatrices);
- //! update of the skinning matrices per frame. The matrices are in model / local space
- //! which is why the entity world matrix is also passed.
- void UpdateBoneMatrices(const AZ::Matrix3x4& entityWorldMatrix, const AZStd::vector<AZ::Matrix3x4>& boneMatrices);
- void InitBoneMatricesPlaceHolder(int numBoneMatrices);
- void SetFrameDeltaTime(float deltaTime);
- //! Updating the bone matrices for the skinning in the simulation constant buffer.
- //! pBoneMatricesInWS constraints array of column major bone matrices in world space.
- void UpdateRenderingParameters(
- const AMD::TressFXRenderingSettings* parameters, const int nodePoolSize,
- float distance, bool shadowUpdate /*= false*/);
- AMD::TressFXRenderParams* GetHairRenderParams() { return m_renderCB.get(); };
- //! Update of simulation constant buffer.
- //! Notice that the bone matrices are set elsewhere and should be updated before GPU submit.
- void UpdateSimulationParameters(const AMD::TressFXSimulationSettings* settings, float timeStep);
- void SetWind(const Vector3& windDir, float windMag, int frame);
- void SetRenderIndex(uint32_t renderIndex) { m_RenderIndex = renderIndex; }
- void ResetPositions() { m_simCB->g_ResetPositions = 1.0f; }
- void IncreaseSimulationFrame()
- {
- m_simCB->g_ResetPositions = (m_SimulationFrame < 2) ? 1.0f : 0.0f;
- m_SimulationFrame++;
- }
- bool IsEnabled()
- {
- return m_enabled;
- }
- void SetEnabled(bool enable)
- {
- m_enabled = enable;
- }
- //!-----------------------------------------------------------------
- private:
- //----------------------- Private Methods --------------------------
- bool BindRenderSrgResources();
- void PrepareRenderSrgDescriptors();
- bool GetShaders();
- //------------------------------ Data ------------------------------
- static uint32_t s_objectCounter;
- //! The feature processor is the centralized class that gathers all render nodes and
- //! responsible for the various stages and passes' updates
- HairFeatureProcessor* m_featureProcessor = nullptr;
- //! Skinning compute shader used for creation of the compute Srgs and dispatch item
- Data::Instance<RPI::Shader> m_skinningShader = nullptr;
- //! Compute dispatch items map per the existing passes
- AZStd::unordered_map<RPI::Shader*, Data::Instance<HairDispatchItem>> m_dispatchItems;
- //! Geometry raster shader used for creation of the raster Srgs.
- //! Since the Srgs for geometry raster are the same across the shaders we keep
- //! only a single shader - if this to change in the future, several shaders and sets
- //! of dynamic Srgs should be created.
- Data::Instance<RPI::Shader> m_geometryRasterShader = nullptr;
- //! DrawPacket for the multi object geometry raster pass.
- AZStd::unordered_map<RPI::Shader*, RHI::ConstPtr<RHI::DrawPacket>> m_geometryDrawPackets;
- float m_frameDeltaTime = 0.02;
- //! The following are the configuration settings that might be required during the update.
- AMD::TressFXSimulationSettings* m_simSettings = nullptr;
- AMD::TressFXRenderingSettings* m_renderSettings = nullptr;
- //! Hair asset information
- uint32_t m_TotalIndices = 0;
- uint32_t m_NumTotalVertices = 0;
- uint32_t m_numGuideVertices = 0;
- uint32_t m_NumTotalStrands = 0;
- uint32_t m_NumVerticesPerStrand = 0;
- uint32_t m_CPULocalShapeIterations = 0;
- uint32_t m_NumFollowHairsPerGuideHair = 0;
- // LOD calculations factor
- float m_LODHairDensity = 1.0f;
- bool m_enabled = true;
- //! Controls reset / copy base hair state
- uint32_t m_SimulationFrame = 0;
- //! The index used as a look up into the material array during the resolve pass
- uint32_t m_RenderIndex = 0;
- //!-----------------------------------------------------------------
- //! The hair dynamic per instance buffers such as vertices, tangents, etc..
- //! The data of these buffers is read/write and will change between passes.
- DynamicHairData m_dynamicHairData;
- //!-----------------------------------------------------------------
- //! Static buffers & Srg: Initial position, bones transform skinning
- //! data, physical hair properties..
- //!-----------------------------------------------------------------
- AZStd::vector<Data::Instance<RPI::Buffer>> m_hairGenerationBuffers;
- AZStd::vector<SrgBufferDescriptor> m_hairGenerationDescriptors;
- //! The simulation parameters constant buffer.
- HairUniformBuffer<AMD::TressFXSimulationParams> m_simCB;
- Data::Instance<RPI::ShaderResourceGroup> m_hairGenerationSrg;
- //!-----------------------------------------------------------------
- //! TressFXRenderParams Srg buffers and declarations
- //! The rendering buffers and structures required for the render draw
- //! calls and are sent to the GPU using TressFXRenderParams Srg.
- //!-----------------------------------------------------------------
- //! Vertex and UV buffers.
- //! Naming was not changed to preserve correlation to TressFXHairObject.h
- Data::Instance<RPI::Buffer> m_hairVertexRenderParams;
- Data::Instance<RPI::Buffer> m_hairTexCoords;
-
- //! Base color of the hair root and per strand texture.
- Data::Instance<RPI::Image> m_baseAlbedo;
- Data::Instance<RPI::Image> m_strandAlbedo;
- HairUniformBuffer<AMD::TressFXRenderParams> m_renderCB;
- HairUniformBuffer<AMD::TressFXStrandParams> m_strandCB;
- AZStd::vector<SrgBufferDescriptor> m_hairRenderDescriptors;
- // Equivalent to m_pRenderLayoutBindSet in TressFX.
- Data::Instance<RPI::ShaderResourceGroup> m_hairRenderSrg;
-
- //! Index buffer for the render pass via draw calls - naming was kept
- Data::Instance<RHI::Buffer> m_indexBuffer;
- RHI::GeometryView m_geometryView;
- //-------------------------------------------------------------------
- AZStd::mutex m_mutex;
- };
- } // namespace Hair
- } // namespace Render
- } // namespace AZ
|