From 723a882824940b829cb1d78d4421b5e0b67401b8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 23 Dec 2024 23:28:01 +0100 Subject: [PATCH] Merge more code together for meshes --- Source/Engine/Content/Assets/Model.cpp | 10 +- Source/Engine/Content/Assets/Model.h | 162 ++++++++++++++++-- Source/Engine/Content/Assets/ModelBase.cpp | 6 +- Source/Engine/Content/Assets/ModelBase.h | 2 + Source/Engine/Content/Assets/SkinnedModel.cpp | 7 +- Source/Engine/Content/Assets/SkinnedModel.h | 130 +++++++++++++- Source/Engine/Graphics/Models/ModelLOD.h | 159 ----------------- .../Engine/Graphics/Models/SkinnedModelLOD.h | 139 --------------- 8 files changed, 299 insertions(+), 316 deletions(-) delete mode 100644 Source/Engine/Graphics/Models/ModelLOD.h delete mode 100644 Source/Engine/Graphics/Models/SkinnedModelLOD.h diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp index 52f633e1b..bf58c8782 100644 --- a/Source/Engine/Content/Assets/Model.cpp +++ b/Source/Engine/Content/Assets/Model.cpp @@ -79,9 +79,9 @@ Model::Model(const SpawnParams& params, const AssetInfo* info) } } -Model::~Model() +bool Model::HasAnyLODInitialized() const { - ASSERT(_streamingTask == nullptr); + return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized(); } bool Model::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh, int32 lodIndex) @@ -890,6 +890,12 @@ AssetChunksFlag Model::getChunksToPreload() const return GET_CHUNK_FLAG(0) | GET_CHUNK_FLAG(15); } +bool ModelLOD::HasAnyMeshInitialized() const +{ + // Note: we initialize all meshes at once so the last one can be used to check it. + return Meshes.HasItems() && Meshes.Last().IsInitialized(); +} + bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh) { bool result = false; diff --git a/Source/Engine/Content/Assets/Model.h b/Source/Engine/Content/Assets/Model.h index 3f78f973d..de17f37e1 100644 --- a/Source/Engine/Content/Assets/Model.h +++ b/Source/Engine/Content/Assets/Model.h @@ -3,9 +3,156 @@ #pragma once #include "ModelBase.h" -#include "Engine/Graphics/Models/ModelLOD.h" +#include "Engine/Graphics/Models/Mesh.h" -class Mesh; +/// +/// Represents single Level Of Detail for the model. Contains a collection of the meshes. +/// +API_CLASS(NoSpawn) class FLAXENGINE_API ModelLOD : public ScriptingObject +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(ModelLOD, ScriptingObject); + friend Model; + friend Mesh; + +private: + Model* _model = nullptr; + int32 _lodIndex = 0; + uint32 _verticesCount = 0; + + void Link(Model* model, int32 lodIndex) + { + _model = model; + _lodIndex = lodIndex; + _verticesCount = 0; + } + +public: + /// + /// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD. + /// + API_FIELD() float ScreenSize = 1.0f; + + /// + /// The meshes array. + /// + API_FIELD(ReadOnly) Array Meshes; + + /// + /// Determines whether any mesh has been initialized. + /// + /// True if any mesh has been initialized, otherwise false. + bool HasAnyMeshInitialized() const; + + /// + /// Gets the model LOD index. + /// + API_PROPERTY() FORCE_INLINE int32 GetLODIndex() const + { + return _lodIndex; + } + + /// + /// Gets the vertex count for this model LOD level. + /// + API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const + { + return _verticesCount; + } + +public: + /// + /// Determines if there is an intersection between the Model and a Ray in given world using given instance + /// + /// The ray to test + /// World to test + /// When the method completes, contains the distance of the intersection (if any valid). + /// When the method completes, contains the intersection surface normal vector (if any valid). + /// Mesh, or null + /// True whether the two objects intersected + bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh); + + /// + /// Determines if there is an intersection between the Model and a Ray in given world using given instance + /// + /// The ray to test + /// The instance transformation. + /// When the method completes, contains the distance of the intersection (if any valid). + /// When the method completes, contains the intersection surface normal vector (if any valid). + /// Mesh, or null + /// True whether the two objects intersected + bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh); + + /// + /// Get model bounding box in transformed world matrix. + /// + /// World matrix + /// Bounding box + BoundingBox GetBox(const Matrix& world) const; + + /// + /// Get model bounding box in transformed world. + /// + /// The instance transformation. + /// The meshes deformation container (optional). + /// Bounding box + BoundingBox GetBox(const Transform& transform, const MeshDeformation* deformation = nullptr) const; + + /// + /// Gets the bounding box combined for all meshes in this model LOD. + /// + API_PROPERTY() BoundingBox GetBox() const; + + /// + /// Draws the meshes. Binds vertex and index buffers and invokes the draw calls. + /// + /// The GPU context to draw with. + FORCE_INLINE void Render(GPUContext* context) + { + for (int32 i = 0; i < Meshes.Count(); i++) + Meshes.Get()[i].Render(context); + } + + /// + /// Draws the meshes from the model LOD. + /// + /// The rendering context. + /// The material to use for rendering. + /// The world transformation of the model. + /// The object static flags. + /// True if rendered geometry can receive decals, otherwise false. + /// The draw passes to use for rendering this object. + /// The random per-instance value (normalized to range 0-1). + /// Object sorting key. + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int8 sortOrder = 0) const + { + for (int32 i = 0; i < Meshes.Count(); i++) + Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom, sortOrder); + } + + /// + /// Draws all the meshes from the model LOD. + /// + /// The rendering context. + /// The packed drawing info data. + /// The LOD transition dither factor. + FORCE_INLINE void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info, float lodDitherFactor) const + { + for (int32 i = 0; i < Meshes.Count(); i++) + Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor); + } + + /// + /// Draws all the meshes from the model LOD. + /// + /// The rendering context batch. + /// The packed drawing info data. + /// The LOD transition dither factor. + FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info, float lodDitherFactor) const + { + for (int32 i = 0; i < Meshes.Count(); i++) + Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor); + } +}; /// /// Model asset that contains model object made of meshes which can rendered on the GPU. @@ -26,20 +173,11 @@ public: /// API_FIELD(ReadOnly) SDFData SDF; -public: - /// - /// Finalizes an instance of the class. - /// - ~Model(); - public: /// /// Determines whether any LOD has been initialized. /// - FORCE_INLINE bool HasAnyLODInitialized() const - { - return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized(); - } + bool HasAnyLODInitialized() const; public: /// diff --git a/Source/Engine/Content/Assets/ModelBase.cpp b/Source/Engine/Content/Assets/ModelBase.cpp index 6e7fc3457..220c1b4f7 100644 --- a/Source/Engine/Content/Assets/ModelBase.cpp +++ b/Source/Engine/Content/Assets/ModelBase.cpp @@ -163,12 +163,16 @@ public: } }; +ModelBase::~ModelBase() +{ + ASSERT(_streamingTask == nullptr); +} + void ModelBase::SetupMaterialSlots(int32 slotsCount) { CHECK(slotsCount >= 0 && slotsCount < 4096); if (!IsVirtual() && WaitForLoaded()) return; - ScopeLock lock(Locker); const int32 prevCount = MaterialSlots.Count(); diff --git a/Source/Engine/Content/Assets/ModelBase.h b/Source/Engine/Content/Assets/ModelBase.h index ab683c116..34d7ee23b 100644 --- a/Source/Engine/Content/Assets/ModelBase.h +++ b/Source/Engine/Content/Assets/ModelBase.h @@ -97,6 +97,8 @@ protected: } public: + ~ModelBase(); + /// /// The minimum screen size to draw this model (the bottom limit). Used to cull small models. Set to 0 to disable this feature. /// diff --git a/Source/Engine/Content/Assets/SkinnedModel.cpp b/Source/Engine/Content/Assets/SkinnedModel.cpp index 933643f63..9450ddf64 100644 --- a/Source/Engine/Content/Assets/SkinnedModel.cpp +++ b/Source/Engine/Content/Assets/SkinnedModel.cpp @@ -32,7 +32,6 @@ SkinnedModel::SkinnedModel(const SpawnParams& params, const AssetInfo* info) SkinnedModel::~SkinnedModel() { - ASSERT(_streamingTask == nullptr); ASSERT(_skeletonMappingCache.Count() == 0); } @@ -1053,6 +1052,12 @@ AssetChunksFlag SkinnedModel::getChunksToPreload() const return GET_CHUNK_FLAG(0); } +bool SkinnedModelLOD::HasAnyMeshInitialized() const +{ + // Note: we initialize all meshes at once so the last one can be used to check it. + return Meshes.HasItems() && Meshes.Last().IsInitialized(); +} + bool SkinnedModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh) { // Check all meshes diff --git a/Source/Engine/Content/Assets/SkinnedModel.h b/Source/Engine/Content/Assets/SkinnedModel.h index fc64e9339..78350285c 100644 --- a/Source/Engine/Content/Assets/SkinnedModel.h +++ b/Source/Engine/Content/Assets/SkinnedModel.h @@ -4,9 +4,135 @@ #include "ModelBase.h" #include "Engine/Core/Collections/Dictionary.h" -#include "Engine/Graphics/Models/Config.h" +#include "Engine/Graphics/Models/SkinnedMesh.h" #include "Engine/Graphics/Models/SkeletonData.h" -#include "Engine/Graphics/Models/SkinnedModelLOD.h" + +/// +/// Represents single Level Of Detail for the skinned model. Contains a collection of the meshes. +/// +API_CLASS(NoSpawn) class FLAXENGINE_API SkinnedModelLOD : public ScriptingObject +{ + DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(SkinnedModelLOD, ScriptingObject); + friend SkinnedModel; +private: + SkinnedModel* _model = nullptr; + int32 _lodIndex = 0; + +public: + /// + /// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD. + /// + API_FIELD() float ScreenSize = 1.0f; + + /// + /// The meshes array. + /// + API_FIELD(ReadOnly) Array Meshes; + + /// + /// Gets the model LOD index. + /// + API_PROPERTY() FORCE_INLINE int32 GetLODIndex() const + { + return _lodIndex; + } + + /// + /// Determines whether any mesh has been initialized. + /// + bool HasAnyMeshInitialized() const; + +public: + /// + /// Determines if there is an intersection between the Model and a Ray in given world using given instance + /// + /// The ray to test + /// World to test + /// When the method completes, contains the distance of the intersection (if any valid). + /// When the method completes, contains the intersection surface normal vector (if any valid). + /// Mesh, or null + /// True whether the two objects intersected + bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh); + + /// + /// Determines if there is an intersection between the Model and a Ray in given world using given instance + /// + /// The ray to test + /// Instance transformation + /// When the method completes, contains the distance of the intersection (if any valid). + /// When the method completes, contains the intersection surface normal vector (if any valid). + /// Mesh, or null + /// True whether the two objects intersected + bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, SkinnedMesh** mesh); + + /// + /// Get model bounding box in transformed world for given instance buffer + /// + /// World matrix + /// Bounding box + BoundingBox GetBox(const Matrix& world) const; + + /// + /// Get model bounding box in transformed world. + /// + /// The instance transformation. + /// The meshes deformation container (optional). + /// Bounding box + BoundingBox GetBox(const Transform& transform, const MeshDeformation* deformation = nullptr) const; + + /// + /// Get model bounding box in transformed world for given instance buffer for only one mesh + /// + /// World matrix + /// esh index + /// Bounding box + BoundingBox GetBox(const Matrix& world, int32 meshIndex) const; + + /// + /// Gets the bounding box combined for all meshes in this model LOD. + /// + API_PROPERTY() BoundingBox GetBox() const; + + /// + /// Draws the meshes. Binds vertex and index buffers and invokes the draw calls. + /// + /// The GPU context to draw with. + FORCE_INLINE void Render(GPUContext* context) + { + for (int32 i = 0; i < Meshes.Count(); i++) + { + Meshes.Get()[i].Render(context); + } + } + + /// + /// Draws all the meshes from the model LOD. + /// + /// The rendering context. + /// The packed drawing info data. + /// The LOD transition dither factor. + FORCE_INLINE void Draw(const RenderContext& renderContext, const SkinnedMesh::DrawInfo& info, float lodDitherFactor) const + { + for (int32 i = 0; i < Meshes.Count(); i++) + { + Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor); + } + } + + /// + /// Draws all the meshes from the model LOD. + /// + /// The rendering context batch. + /// The packed drawing info data. + /// The LOD transition dither factor. + FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const SkinnedMesh::DrawInfo& info, float lodDitherFactor) const + { + for (int32 i = 0; i < Meshes.Count(); i++) + { + Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor); + } + } +}; /// /// Skinned model asset that contains model object made of meshes that can be rendered on the GPU using skeleton bones skinning. diff --git a/Source/Engine/Graphics/Models/ModelLOD.h b/Source/Engine/Graphics/Models/ModelLOD.h deleted file mode 100644 index 4934e6cc2..000000000 --- a/Source/Engine/Graphics/Models/ModelLOD.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. - -#pragma once - -#include "Mesh.h" - -class MemoryReadStream; - -/// -/// Represents single Level Of Detail for the model. Contains a collection of the meshes. -/// -API_CLASS(NoSpawn) class FLAXENGINE_API ModelLOD : public ScriptingObject -{ - DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(ModelLOD, ScriptingObject); - friend Model; - friend Mesh; -private: - Model* _model = nullptr; - int32 _lodIndex = 0; - uint32 _verticesCount = 0; - - void Link(Model* model, int32 lodIndex) - { - _model = model; - _lodIndex = lodIndex; - _verticesCount = 0; - } - -public: - /// - /// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD. - /// - API_FIELD() float ScreenSize = 1.0f; - - /// - /// The meshes array. - /// - API_FIELD(ReadOnly) Array Meshes; - - /// - /// Determines whether any mesh has been initialized. - /// - /// True if any mesh has been initialized, otherwise false. - FORCE_INLINE bool HasAnyMeshInitialized() const - { - // Note: we initialize all meshes at once so the last one can be used to check it. - return Meshes.HasItems() && Meshes.Last().IsInitialized(); - } - - /// - /// Gets the model LOD index. - /// - API_PROPERTY() FORCE_INLINE int32 GetLODIndex() const - { - return _lodIndex; - } - - /// - /// Gets the vertex count for this model LOD level. - /// - API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const - { - return _verticesCount; - } - -public: - /// - /// Determines if there is an intersection between the Model and a Ray in given world using given instance - /// - /// The ray to test - /// World to test - /// When the method completes, contains the distance of the intersection (if any valid). - /// When the method completes, contains the intersection surface normal vector (if any valid). - /// Mesh, or null - /// True whether the two objects intersected - bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh); - - /// - /// Determines if there is an intersection between the Model and a Ray in given world using given instance - /// - /// The ray to test - /// The instance transformation. - /// When the method completes, contains the distance of the intersection (if any valid). - /// When the method completes, contains the intersection surface normal vector (if any valid). - /// Mesh, or null - /// True whether the two objects intersected - bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh); - - /// - /// Get model bounding box in transformed world matrix. - /// - /// World matrix - /// Bounding box - BoundingBox GetBox(const Matrix& world) const; - - /// - /// Get model bounding box in transformed world. - /// - /// The instance transformation. - /// The meshes deformation container (optional). - /// Bounding box - BoundingBox GetBox(const Transform& transform, const MeshDeformation* deformation = nullptr) const; - - /// - /// Gets the bounding box combined for all meshes in this model LOD. - /// - API_PROPERTY() BoundingBox GetBox() const; - - /// - /// Draws the meshes. Binds vertex and index buffers and invokes the draw calls. - /// - /// The GPU context to draw with. - FORCE_INLINE void Render(GPUContext* context) - { - for (int32 i = 0; i < Meshes.Count(); i++) - Meshes.Get()[i].Render(context); - } - - /// - /// Draws the meshes from the model LOD. - /// - /// The rendering context. - /// The material to use for rendering. - /// The world transformation of the model. - /// The object static flags. - /// True if rendered geometry can receive decals, otherwise false. - /// The draw passes to use for rendering this object. - /// The random per-instance value (normalized to range 0-1). - /// Object sorting key. - API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int8 sortOrder = 0) const - { - for (int32 i = 0; i < Meshes.Count(); i++) - Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom, sortOrder); - } - - /// - /// Draws all the meshes from the model LOD. - /// - /// The rendering context. - /// The packed drawing info data. - /// The LOD transition dither factor. - FORCE_INLINE void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info, float lodDitherFactor) const - { - for (int32 i = 0; i < Meshes.Count(); i++) - Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor); - } - - /// - /// Draws all the meshes from the model LOD. - /// - /// The rendering context batch. - /// The packed drawing info data. - /// The LOD transition dither factor. - FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info, float lodDitherFactor) const - { - for (int32 i = 0; i < Meshes.Count(); i++) - Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor); - } -}; diff --git a/Source/Engine/Graphics/Models/SkinnedModelLOD.h b/Source/Engine/Graphics/Models/SkinnedModelLOD.h deleted file mode 100644 index f7c78f3d1..000000000 --- a/Source/Engine/Graphics/Models/SkinnedModelLOD.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. - -#pragma once - -#include "SkinnedMesh.h" - -class MemoryReadStream; - -/// -/// Represents single Level Of Detail for the skinned model. Contains a collection of the meshes. -/// -API_CLASS(NoSpawn) class FLAXENGINE_API SkinnedModelLOD : public ScriptingObject -{ - DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(SkinnedModelLOD, ScriptingObject); - friend SkinnedModel; -private: - SkinnedModel* _model = nullptr; - int32 _lodIndex = 0; - -public: - /// - /// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD. - /// - API_FIELD() float ScreenSize = 1.0f; - - /// - /// The meshes array. - /// - API_FIELD(ReadOnly) Array Meshes; - - /// - /// Gets the model LOD index. - /// - API_PROPERTY() FORCE_INLINE int32 GetLODIndex() const - { - return _lodIndex; - } - - /// - /// Determines whether any mesh has been initialized. - /// - bool HasAnyMeshInitialized() const - { - // Note: we initialize all meshes at once so the last one can be used to check it. - return Meshes.HasItems() && Meshes.Last().IsInitialized(); - } - - -public: - /// - /// Determines if there is an intersection between the Model and a Ray in given world using given instance - /// - /// The ray to test - /// World to test - /// When the method completes, contains the distance of the intersection (if any valid). - /// When the method completes, contains the intersection surface normal vector (if any valid). - /// Mesh, or null - /// True whether the two objects intersected - bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh); - - /// - /// Determines if there is an intersection between the Model and a Ray in given world using given instance - /// - /// The ray to test - /// Instance transformation - /// When the method completes, contains the distance of the intersection (if any valid). - /// When the method completes, contains the intersection surface normal vector (if any valid). - /// Mesh, or null - /// True whether the two objects intersected - bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, SkinnedMesh** mesh); - - /// - /// Get model bounding box in transformed world for given instance buffer - /// - /// World matrix - /// Bounding box - BoundingBox GetBox(const Matrix& world) const; - - /// - /// Get model bounding box in transformed world. - /// - /// The instance transformation. - /// The meshes deformation container (optional). - /// Bounding box - BoundingBox GetBox(const Transform& transform, const MeshDeformation* deformation = nullptr) const; - - /// - /// Get model bounding box in transformed world for given instance buffer for only one mesh - /// - /// World matrix - /// esh index - /// Bounding box - BoundingBox GetBox(const Matrix& world, int32 meshIndex) const; - - /// - /// Gets the bounding box combined for all meshes in this model LOD. - /// - API_PROPERTY() BoundingBox GetBox() const; - - /// - /// Draws the meshes. Binds vertex and index buffers and invokes the draw calls. - /// - /// The GPU context to draw with. - FORCE_INLINE void Render(GPUContext* context) - { - for (int32 i = 0; i < Meshes.Count(); i++) - { - Meshes.Get()[i].Render(context); - } - } - - /// - /// Draws all the meshes from the model LOD. - /// - /// The rendering context. - /// The packed drawing info data. - /// The LOD transition dither factor. - FORCE_INLINE void Draw(const RenderContext& renderContext, const SkinnedMesh::DrawInfo& info, float lodDitherFactor) const - { - for (int32 i = 0; i < Meshes.Count(); i++) - { - Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor); - } - } - - /// - /// Draws all the meshes from the model LOD. - /// - /// The rendering context batch. - /// The packed drawing info data. - /// The LOD transition dither factor. - FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const SkinnedMesh::DrawInfo& info, float lodDitherFactor) const - { - for (int32 i = 0; i < Meshes.Count(); i++) - { - Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor); - } - } -};