// 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); } } };