| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
📝 Walkthrough
WalkthroughAdds an Object::Utils mesh simplifier/deduper and a SoftBodyChassis subsystem: new soft-body component types and internals, builder hooks, plugin/system registration, Jolt soft-body creation/synchronization, and mesh processing flows (dedupe, simplify, vertex mapping). Changes
Sequence Diagram(s)sequenceDiagram
participant Builder as VehicleBuilder
participant Plugin as PhysicsPlugin
participant System as SoftBodyChassisSystem
participant ObjectUtils as Object::Utils
participant Jolt as JoltPhysics
participant Mesh as EntityMesh
rect rgba(100,150,255,0.5)
Builder->>Builder: EnableSoftBodyChassis()
Builder->>Plugin: Build() with SoftBodyChassis component
Plugin->>System: InitSoftBodyChassisSystem()
System->>System: Register lifecycle hooks
end
rect rgba(100,200,100,0.5)
Mesh->>System: Component attached (mesh + transform)
System->>ObjectUtils: DeduplicateVertices(mesh)
System->>ObjectUtils: SimplifyMesh(mesh, settings) [optional]
System->>Jolt: Create skeleton RigidBody
System->>Jolt: Create SoftBody with constraints
System->>System: Store SoftBodyChassisInternal (vertexMap, IDs, state)
end
rect rgba(200,150,100,0.5)
loop per-frame
System->>Jolt: Read skeleton transforms
System->>System: Skin vertices / update joint matrices
System->>Jolt: Read SoftBody vertex positions
System->>Mesh: Update vertex positions & recalc normals
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem🚥 Pre-merge checks | ✅ 2 | ❌ 1 ❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ ShareComment @coderabbitai help to get the list of available commands and usage tips. |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agentsIn `@src/plugin/object/src/utils/MeshSimplifier.cpp`: - Around line 421-425: The multiplication cellsX * cellsY * cellsZ can overflow uint32_t; change the intermediate computation to use uint64_t (e.g., compute uint64_t maxCells64 = static_cast<uint64_t>(cellsX) * cellsY * cellsZ), then clamp or validate the result before assigning to uint32_t maxCells (use std::numeric_limits<uint32_t>::max() or fail/resize if maxCells64 exceeds that) and update any uses of maxCells accordingly to avoid silent wraparound in MeshSimplifier.cpp (references: cellsX, cellsY, cellsZ, maxCells).
src/plugin/object/src/utils/MeshSimplifier.cpp (2)319-324: Missing vertexMap initialization when vertices is empty.
When vertices.empty() is true, result.vertexMap is not initialized, leaving it empty. While this is technically correct (no vertices to map), it's inconsistent with SimplifyMesh which always initializes vertexMap. Consider adding an explicit initialization for consistency.
♻️ Suggested improvementif (vertices.empty()) { result.mesh = mesh; result.simplifiedVertexCount = 0; result.wasSimplified = false; + // vertexMap intentionally left empty for empty input return result; }
243-247: Texture coordinate averaging may produce incorrect results at UV seams.
When merging vertices at UV seams (where the same position has different texture coordinates), averaging the texture coordinates can produce incorrect results. This is a known limitation of vertex clustering algorithms.
Consider documenting this limitation or, for critical use cases, providing an option to preserve UV seam vertices.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)src/plugin/physics/src/system/SoftBodySystem.cpp (1)123-203: ⚠️ Potential issue | 🟠 Major
Remap softBody.edges through the dedup vertex map.
After deduplication, edge indices must be remapped to the deduped vertex indices or they can reference invalid/wrong vertices when no faces are present.
🛠️ Suggested fix- else if (!softBody.edges.empty()) + else if (!softBody.edges.empty()) { // For rope/chain without faces, use edge constraints from SoftBody settings->mEdgeConstraints.reserve(softBody.edges.size()); for (const auto &[vertexA, vertexB] : softBody.edges) { - settings->mEdgeConstraints.emplace_back( - JPH::SoftBodySharedSettings::Edge(vertexA, vertexB, softBody.settings.edgeCompliance)); + if (vertexA >= result.vertexMap.size() || vertexB >= result.vertexMap.size()) + { + Log::Warn(fmt::format("SoftBody: Skipping edge with out-of-bounds indices ({}, {})", vertexA, vertexB)); + continue; + } + uint32_t a = result.vertexMap[vertexA]; + uint32_t b = result.vertexMap[vertexB]; + if (a == b) + continue; + settings->mEdgeConstraints.emplace_back( + JPH::SoftBodySharedSettings::Edge(a, b, softBody.settings.edgeCompliance)); } }
In `@src/plugin/object/src/utils/MeshSimplifier.cpp`: - Around line 19-20: The SpatialHash constructor currently sets _invCellSize = 1.0f / cellSize which yields Inf for zero/negative inputs; update SpatialHash(float cellSize) to validate or clamp cellSize (e.g., if cellSize <= 0.0f then set cellSize = max(cellSize, std::numeric_limits<float>::epsilon()) or a small positive fallback) before assigning _cellSize and computing _invCellSize, or alternatively assert/throw on invalid input; ensure GetKey and any other methods relying on _invCellSize then operate on the validated/clamped value. In `@src/plugin/physics/src/system/SoftBodyChassisSystem.cpp`: - Around line 452-469: The computation of invScale = 1.0f / internal.initialScale can divide by zero if any component of initialScale is zero; change it to clamp each component against a small epsilon (use the same epsilon used in SoftBodySystem) before inversion (e.g., compute safeScale = glm::max(internal.initialScale, glm::vec3(epsilon)) then invScale = 1.0f / safeScale) so invScale contains no inf/NaN and the subsequent mesh.SetVertexAt updates remain valid. - Around line 223-303: The internal.vertexMap must map original mesh vertex indices to the final Jolt vertex indices (deduped simplified mesh) — currently when wasSimplified is true you assign only simplificationMap, losing the dedup mapping from CreateChassisSharedSettings (vertexMap) and causing incorrect/out-of-range indices during sync. Fix by composing the maps when wasSimplified: take simplificationMap (orig->simplifiedIndex) and the dedup vertexMap returned by CreateChassisSharedSettings (simplifiedIndex->joltIndex) and build a combined map orig->joltIndex, then assign that combined map to Component::SoftBodyChassisInternal::vertexMap (instead of assigning only simplificationMap); keep the existing move semantics (use std::move where appropriate) and ensure the code references simplificationMap, vertexMap (the one returned by CreateChassisSharedSettings), internal.vertexMap and wasSimplified.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agentsIn `@src/plugin/object/src/utils/MeshSimplifier.cpp`: - Around line 281-368: The function SimplifyMesh currently unconditionally sets result.wasSimplified = true at the end of the simplification path; change this to reflect actual change by comparing counts: set result.wasSimplified = (result.simplifiedVertexCount != result.originalVertexCount) || (newIndices.size() != indices.size()). Update the assignment for result.wasSimplified (after computing result.simplifiedVertexCount and newIndices) instead of the unconditional true so the flag accurately reflects whether vertices or indices changed. In `@src/plugin/physics/src/system/SoftBodyChassisSystem.cpp`: - Around line 135-169: The static function CreateSkeletonBody is unused and should be removed or explicitly documented; either delete the entire CreateSkeletonBody function (including its references to JPH::BoxShapeSettings, bodySettings, and physicsManager/GetBodyInterface/CreateBody) to eliminate dead code, or keep it but add a clear comment above CreateSkeletonBody stating its intended future use (e.g., purpose for VehicleConstraint skeleton bodies), why it’s static/unused, and when/where it will be invoked so reviewers know it’s intentionally retained.
src/plugin/physics/src/system/SoftBodyChassisSystem.cpp (1)42-51: Remove unused DeduplicatedMesh struct and orphaned doc comment.
The DeduplicatedMesh struct is defined but never used anywhere in this file. Additionally, the doc comment at line 49-51 appears to describe a function that was removed, leaving an orphaned comment block.
🧹 Suggested cleanup-/** - * `@brief` Structure holding deduplicated mesh data - */ -struct DeduplicatedMesh { - std::vector<glm::vec3> vertices; - std::vector<uint32_t> indices; - std::vector<uint32_t> vertexMap; -}; - -/** - * `@brief` Convert mesh to deduplicated indexed mesh - */ - /** * `@brief` Create Jolt SoftBodySharedSettings with skinned constraints for chassis
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agentsIn `@src/plugin/physics/src/system/SoftBodyChassisSystem.cpp`: - Around line 224-257: When autoSimplify is enabled but simplification didn't reduce to settings.maxVertices and settings.fallbackToRigidBody is false, explicitly handle that case instead of silently continuing with an over-budget mesh: inside the branch where result.wasSimplified is false and settings.fallbackToRigidBody is false, add a Log::Warn message describing that simplification was insufficient and fallback is disabled, then if result.mesh is available use it as the working mesh (assign workingMesh = std::move(result.mesh); simplificationMap = std::move(result.vertexMap); set wasSimplified accordingly) so we at least use the best-effort simplified mesh, otherwise keep the original mesh but make the warning explicit and consider setting a flag or metric to show the chassis remains over-budget; reference symbols: meshVertices, settings.autoSimplify, settings.fallbackToRigidBody, result, workingMesh, simplificationMap, wasSimplified, chassisComp.isActive.
src/plugin/physics/src/system/SoftBodyChassisSystem.cpp (1)42-51: Remove unused struct and orphan docstring.
The DeduplicatedMesh struct is defined but never used—the code uses Object::Utils::DeduplicateVertices which returns its own result type. The docstring at lines 49-51 has no associated function.
🧹 Suggested cleanup-/** - * `@brief` Structure holding deduplicated mesh data - */ -struct DeduplicatedMesh { - std::vector<glm::vec3> vertices; - std::vector<uint32_t> indices; - std::vector<uint32_t> vertexMap; -}; - -/** - * `@brief` Convert mesh to deduplicated indexed mesh - */ - /** * `@brief` Create Jolt SoftBodySharedSettings with skinned constraints for chassis
Sorry, something went wrong.
| if (meshVertices.size() > settings.maxVertices) | ||
| { | ||
| if (settings.autoSimplify) | ||
| { | ||
| Log::Info(fmt::format("SoftBodyChassis: Simplifying mesh from {} to max {} vertices", | ||
| meshVertices.size(), settings.maxVertices)); | ||
|
|
||
| auto simplifySettings = Object::Utils::SimplificationSettings::ForVehicleChassis(); | ||
| simplifySettings.targetVertexCount = settings.maxVertices; | ||
|
|
||
| auto result = Object::Utils::SimplifyMesh(*mesh, simplifySettings); | ||
|
|
||
| if (result.wasSimplified && result.simplifiedVertexCount <= settings.maxVertices) | ||
| { | ||
| workingMesh = std::move(result.mesh); | ||
| simplificationMap = std::move(result.vertexMap); | ||
| wasSimplified = true; | ||
| Log::Info(fmt::format("SoftBodyChassis: Simplified to {} vertices", result.simplifiedVertexCount)); | ||
| } | ||
| else if (settings.fallbackToRigidBody) | ||
| { | ||
| Log::Warn("SoftBodyChassis: Simplification insufficient, falling back to RigidBody"); | ||
| chassisComp.isActive = false; | ||
| return; | ||
| } | ||
| } | ||
| else if (settings.fallbackToRigidBody) | ||
| { | ||
| Log::Warn(fmt::format("SoftBodyChassis: Mesh too complex ({} vertices), falling back to RigidBody", | ||
| meshVertices.size())); | ||
| chassisComp.isActive = false; | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟡 Minor
Simplification fallback logic allows over-budget mesh to proceed.
When autoSimplify is enabled, simplification fails to meet maxVertices, and fallbackToRigidBody is false, the code continues with the original over-budget mesh. This could cause performance degradation or unexpected behavior with Jolt.
Consider either logging a warning or providing explicit handling for this case:
💡 Suggested fix if (result.wasSimplified && result.simplifiedVertexCount <= settings.maxVertices)
{
workingMesh = std::move(result.mesh);
simplificationMap = std::move(result.vertexMap);
wasSimplified = true;
Log::Info(fmt::format("SoftBodyChassis: Simplified to {} vertices", result.simplifiedVertexCount));
}
else if (settings.fallbackToRigidBody)
{
Log::Warn("SoftBodyChassis: Simplification insufficient, falling back to RigidBody");
chassisComp.isActive = false;
return;
}
+ else
+ {
+ Log::Warn(fmt::format(
+ "SoftBodyChassis: Simplification insufficient ({} > {} vertices), proceeding with over-budget mesh",
+ result.simplifiedVertexCount, settings.maxVertices));
+ }In `@src/plugin/physics/src/system/SoftBodyChassisSystem.cpp` around lines 224 - 257, When autoSimplify is enabled but simplification didn't reduce to settings.maxVertices and settings.fallbackToRigidBody is false, explicitly handle that case instead of silently continuing with an over-budget mesh: inside the branch where result.wasSimplified is false and settings.fallbackToRigidBody is false, add a Log::Warn message describing that simplification was insufficient and fallback is disabled, then if result.mesh is available use it as the working mesh (assign workingMesh = std::move(result.mesh); simplificationMap = std::move(result.vertexMap); set wasSimplified accordingly) so we at least use the best-effort simplified mesh, otherwise keep the original mesh but make the warning explicit and consider setting a flag or metric to show the chassis remains over-budget; reference symbols: meshVertices, settings.autoSimplify, settings.fallbackToRigidBody, result, workingMesh, simplificationMap, wasSimplified, chassisComp.isActive.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agentsIn `@src/plugin/object/src/utils/MeshSimplifier.cpp`: - Around line 263-270: The loop in MeshSimplifier.cpp that writes res.normals from normalSums (inside the for over i) must guard against zero-length normalSums before calling glm::normalize to avoid NaNs; update the block that currently does res.normals[i] = glm::normalize(normalSums[i]) to compute the squared length (or length) of normalSums[i], compare against a small epsilon, and only normalize when above the threshold, otherwise set a safe fallback normal (e.g., a unit up vector or the vertex-normal computed from surrounding geometry) so res.normals[i] never becomes NaN; locate this change around the variables normalSums, res.normals, clusterCounts and clusterSums in the same loop. - Around line 475-477: Clamp the computed cellSize to a small positive minimum before using it to compute cellsX/cellsY to avoid division by zero when settings.mergeDistance is zero or negative; specifically, replace the direct use of settings.mergeDistance * 2.0f for cellSize with a clamped value (e.g., max(settings.mergeDistance * 2.0f, some small epsilon like 1e-6f)) and then use that clamped cellSize when computing cellsX and cellsY so the ceil(extent.x / cellSize) and ceil(extent.y / cellSize) calls cannot divide by zero.
Sorry, something went wrong.
| for (uint32_t i = 0; i < res.vertices.size(); ++i) | ||
| { | ||
| float invCount = 1.0f / static_cast<float>(clusterCounts[i]); | ||
| res.vertices[i] = clusterSums[i] * invCount; | ||
| if (!normals.empty()) | ||
| { | ||
| res.normals[i] = glm::normalize(normalSums[i]); | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟡 Minor
Guard against zero-length normal sums before normalize.
If clustered normals cancel out, normalizing a near-zero vector can produce NaNs and leak into rendering. Add a length check/fallback.
- if (!normals.empty())
- {
- res.normals[i] = glm::normalize(normalSums[i]);
- }
+ if (!normals.empty())
+ {
+ float len = glm::length(normalSums[i]);
+ res.normals[i] = (len > 1e-8f) ? (normalSums[i] / len) : glm::vec3(0.0f);
+ }‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (uint32_t i = 0; i < res.vertices.size(); ++i) | |
| { | |
| float invCount = 1.0f / static_cast<float>(clusterCounts[i]); | |
| res.vertices[i] = clusterSums[i] * invCount; | |
| if (!normals.empty()) | |
| { | |
| res.normals[i] = glm::normalize(normalSums[i]); | |
| } | |
| for (uint32_t i = 0; i < res.vertices.size(); ++i) | |
| { | |
| float invCount = 1.0f / static_cast<float>(clusterCounts[i]); | |
| res.vertices[i] = clusterSums[i] * invCount; | |
| if (!normals.empty()) | |
| { | |
| float len = glm::length(normalSums[i]); | |
| res.normals[i] = (len > 1e-8f) ? (normalSums[i] / len) : glm::vec3(0.0f); | |
| } |
In `@src/plugin/object/src/utils/MeshSimplifier.cpp` around lines 263 - 270, The loop in MeshSimplifier.cpp that writes res.normals from normalSums (inside the for over i) must guard against zero-length normalSums before calling glm::normalize to avoid NaNs; update the block that currently does res.normals[i] = glm::normalize(normalSums[i]) to compute the squared length (or length) of normalSums[i], compare against a small epsilon, and only normalize when above the threshold, otherwise set a safe fallback normal (e.g., a unit up vector or the vertex-normal computed from surrounding geometry) so res.normals[i] never becomes NaN; locate this change around the variables normalSums, res.normals, clusterCounts and clusterSums in the same loop.
Sorry, something went wrong.
| float cellSize = settings.mergeDistance * 2.0f; | ||
| uint32_t cellsX = static_cast<uint32_t>(std::ceil(extent.x / cellSize)) + 1; | ||
| uint32_t cellsY = static_cast<uint32_t>(std::ceil(extent.y / cellSize)) + 1; |
There was a problem hiding this comment.
⚠️ Potential issue | 🟠 Major
🧩 Analysis chain🏁 Script executed:
# First, let's examine the file to see if it exists and check the content around lines 475-477
ls -la src/plugin/object/src/utils/MeshSimplifier.cpp 2>/dev/null || echo "File not found at exact path, searching..."
fd "MeshSimplifier.cpp" --type fRepository: EngineSquared/EngineSquared
Length of output: 214
🏁 Script executed:
# Read the specific lines mentioned in the review
sed -n '470,485p' src/plugin/object/src/utils/MeshSimplifier.cppRepository: EngineSquared/EngineSquared
Length of output: 858
🏁 Script executed:
# Check more context to understand how cellSize is used
sed -n '470,550p' src/plugin/object/src/utils/MeshSimplifier.cppRepository: EngineSquared/EngineSquared
Length of output: 928
🏁 Script executed:
# Search for mergeDistance in the file to understand constraints and how it's set
rg "mergeDistance" src/plugin/object/src/utils/MeshSimplifier.cpp -B 2 -A 2Repository: EngineSquared/EngineSquared
Length of output: 1284
🏁 Script executed:
# Search for the settings structure definition
rg "struct.*settings|class.*settings" -i src/plugin/object/src/utils/MeshSimplifier.cpp -B 2 -A 10Repository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Search for where settings is initialized or validated
rg "mergeDistance\s*=" src/plugin/object/src/utils/MeshSimplifier.cpp -B 3 -A 1Repository: EngineSquared/EngineSquared
Length of output: 223
🏁 Script executed:
# Look for the settings struct definition more broadly
fd "\.h$" --path "*plugin/object*" --type f | head -20 | xargs rg "mergeDistance" 2>/dev/null | head -20Repository: EngineSquared/EngineSquared
Length of output: 1336
🏁 Script executed:
# Check the function signature that uses these settings
sed -n '450,480p' src/plugin/object/src/utils/MeshSimplifier.cppRepository: EngineSquared/EngineSquared
Length of output: 1141
🏁 Script executed:
# Look at the settings structure definition in the header file
cat src/plugin/object/src/utils/MeshSimplifier.hppRepository: EngineSquared/EngineSquared
Length of output: 6270
🏁 Script executed:
# Check if there's any validation of mergeDistance anywhere
rg "mergeDistance" src/plugin/object/src/utils/ -B 5 -A 5Repository: EngineSquared/EngineSquared
Length of output: 7271
🏁 Script executed:
# Quick check for any callers or usage of EstimateSimplifiedVertexCount
rg "EstimateSimplifiedVertexCount" --type cpp --type hppRepository: EngineSquared/EngineSquared
Length of output: 98
🏁 Script executed:
# Search for EstimateSimplifiedVertexCount usage
rg "EstimateSimplifiedVertexCount"Repository: EngineSquared/EngineSquared
Length of output: 354
Clamp cellSize to prevent division by zero or undefined behavior if settings.mergeDistance is zero or negative.
The divisions extent / cellSize on lines 476-478 will produce undefined behavior if cellSize ≤ 0, which can occur if settings.mergeDistance is zero or negative. While the default value is safe (0.01f), the struct lacks validation to prevent unsafe values from being set by callers.
Suggested fix- float cellSize = settings.mergeDistance * 2.0f;
+ float cellSize = std::max(settings.mergeDistance * 2.0f, 1e-6f);‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| float cellSize = settings.mergeDistance * 2.0f; | |
| uint32_t cellsX = static_cast<uint32_t>(std::ceil(extent.x / cellSize)) + 1; | |
| uint32_t cellsY = static_cast<uint32_t>(std::ceil(extent.y / cellSize)) + 1; | |
| float cellSize = std::max(settings.mergeDistance * 2.0f, 1e-6f); | |
| uint32_t cellsX = static_cast<uint32_t>(std::ceil(extent.x / cellSize)) + 1; | |
| uint32_t cellsY = static_cast<uint32_t>(std::ceil(extent.y / cellSize)) + 1; |
In `@src/plugin/object/src/utils/MeshSimplifier.cpp` around lines 475 - 477, Clamp the computed cellSize to a small positive minimum before using it to compute cellsX/cellsY to avoid division by zero when settings.mergeDistance is zero or negative; specifically, replace the direct use of settings.mergeDistance * 2.0f for cellSize with a clamped value (e.g., max(settings.mergeDistance * 2.0f, some small epsilon like 1e-6f)) and then use that clamped cellSize when computing cellsX and cellsY so the ceil(extent.x / cellSize) and ceil(extent.y / cellSize) calls cannot divide by zero.
Sorry, something went wrong.
…icle bodies - Added SoftBodyChassis component to enable vehicle chassis deformation on collision. - Introduced SoftBodyChassisInternal for managing Jolt references and skinning data. - Created SoftBodyChassisSystem to handle creation, destruction, and synchronization of soft body chassis. - Integrated mesh simplification for chassis to ensure performance and manage vertex count. - Updated VehicleBuilder to support soft body chassis configuration. - Enhanced SoftBody settings to include position update control during simulation. - Added necessary includes and system registrations in PhysicsPlugin.
…n notes for mesh simplification
…ctors, unused numJoints member from constructors; clean up deduplication logic and improve mesh handling, streamline mesh deduplication and improve logging
…Body chassis management, catch specific SoftBodyChassisError for improved error logging during chassis construction, enhance spatial hashing and cluster collapsing logic for better performance and readability
…initialization and enhance vertex mapping logic for better clarity
…ine bounding box computation, and improve merge distance logic for clarity and performance
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agentsIn `@src/plugin/physics/src/component/SoftBodyChassisInternal.hpp`: - Around line 58-64: The field skeletonBodyID in SoftBodyChassisInternal is left uninitialized causing HasValidSkeleton() to be unreliable; fix it by initializing skeletonBodyID to a known invalid value (e.g., JPH::BodyID() or JPH::BodyID::sInvalid) in SoftBodyChassisInternal's constructor OR ensure the code that creates a SoftBodyChassisInternal instance in SoftBodyChassisSystem assigns the actual created rigid body ID to skeletonBodyID after creation; update either the SoftBodyChassisInternal constructor or the instantiation site so skeletonBodyID is deterministically set before any call to HasValidSkeleton().
src/plugin/object/src/utils/MeshSimplifier.hpp (1)src/plugin/physics/src/builder/VehicleBuilder.hpp (1)150-153: Consider using uint32_t for consistency.
The function compares mesh.GetVertices().size() (which returns size_t) against uint32_t maxVertices. This works but may trigger compiler warnings on some platforms due to signed/unsigned comparison.
🔧 Optional: Explicit cast for clarity[[nodiscard]] inline bool NeedsSimplification(const Component::Mesh &mesh, uint32_t maxVertices) { - return mesh.GetVertices().size() > maxVertices; + return static_cast<uint32_t>(mesh.GetVertices().size()) > maxVertices; }src/plugin/physics/src/system/SoftBodyChassisSystem.cpp (1)22-22: Remove unused <optional> include.
The <optional> header is included but not used. _softBodyChassisSettings is stored by value, not as std::optional.
🧹 Remove unused include-#include <optional>42-46: Remove unused DeduplicatedMesh struct.
This struct is defined but never used. The code at line 66 uses Object::Utils::DeduplicateVertices which returns a SimplificationResult, not this struct.
🧹 Remove dead code-/** - * `@brief` Structure holding deduplicated mesh data - */ -struct DeduplicatedMesh { - std::vector<glm::vec3> vertices; - std::vector<uint32_t> indices; - std::vector<uint32_t> vertexMap; -}; - -/** - * `@brief` Convert mesh to deduplicated indexed mesh - */
Sorry, something went wrong.
…ization, streamline chassis shared settings creation, and improve soft body synchronization logic
|
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agentsIn `@src/plugin/physics/src/component/SoftBodyChassisInternal.hpp`: - Around line 149-161: The IsValid() check always fails because skeletonBodyID is never set; update the code to remove the unused skeleton requirement by deleting HasValidSkeleton() and skeletonBodyID usages and change IsValid() (in SoftBodyChassisInternal) to return HasValidSoftBody() && isInitialized; then update any call sites (e.g., SyncSoftBodyChassisWithSkeleton loop in SoftBodyChassisSystem.cpp) that reference HasValidSkeleton or skeletonBodyID to rely on the new IsValid() semantics and ensure anchorsInitialized and softBodyID usage remain intact so processing continues when the soft body is present and initialized.
src/plugin/physics/src/system/SoftBodyChassisSystem.cpp (2)42-46: Remove unused DeduplicatedMesh struct.
This struct is defined but never used. The actual deduplication at line 85 uses Object::Utils::DeduplicateVertices() which returns a SimplificationResult type, not this struct.
♻️ Suggested removal-/** - * `@brief` Structure holding deduplicated mesh data - */ -struct DeduplicatedMesh { - std::vector<glm::vec3> vertices; - std::vector<uint32_t> indices; - std::vector<uint32_t> vertexMap; -}; - -/** - * `@brief` Convert mesh to deduplicated indexed mesh - */
413-424: Redundant if/else branches with identical logic.
Both branches execute the same SetPositionAndRotationInternal call. The only difference is setting hardSkinNextFrame = false. This can be simplified:
♻️ Suggested simplification// On first frame or reset, teleport the entire soft body to match chassis - if (internal.hardSkinNextFrame) - { - // Set the body position and rotation to match chassis - body.SetPositionAndRotationInternal(Utils::ToJoltRVec3(position), Utils::ToJoltQuat(rotation)); - internal.hardSkinNextFrame = false; - } - else - { - // Normal frame: Update position/rotation - body.SetPositionAndRotationInternal(Utils::ToJoltRVec3(position), Utils::ToJoltQuat(rotation)); - } + // Update soft body position and rotation to match chassis + body.SetPositionAndRotationInternal(Utils::ToJoltRVec3(position), Utils::ToJoltQuat(rotation)); + internal.hardSkinNextFrame = false;If the hardSkinNextFrame case was intended to have different behavior (e.g., also teleporting vertices directly), that logic should be added.
Sorry, something went wrong.
| [[nodiscard]] bool HasValidSkeleton() const { return !skeletonBodyID.IsInvalid(); } | ||
|
|
||
| /** | ||
| * @brief Check if soft body ID is valid | ||
| * @return true if soft body ID is valid | ||
| */ | ||
| [[nodiscard]] bool HasValidSoftBody() const { return !softBodyID.IsInvalid(); } | ||
|
|
||
| /** | ||
| * @brief Check if both bodies are valid and system is ready | ||
| * @return true if fully initialized | ||
| */ | ||
| [[nodiscard]] bool IsValid() const { return HasValidSkeleton() && HasValidSoftBody() && isInitialized; } |
There was a problem hiding this comment.
⚠️ Potential issue | 🔴 Critical
IsValid() will always return false, breaking skeleton sync.
IsValid() requires HasValidSkeleton() to be true, but skeletonBodyID is never assigned a valid value in SoftBodyChassisSystem.cpp (only softBodyID is set at line 276). This causes SyncSoftBodyChassisWithSkeleton at line 395 to always skip processing:
if (!chassis.isActive || !internal.IsValid() || !internal.anchorsInitialized)
continue;Either:
- [[nodiscard]] bool IsValid() const { return HasValidSkeleton() && HasValidSoftBody() && isInitialized; }
+ [[nodiscard]] bool IsValid() const { return HasValidSoftBody() && isInitialized; }In `@src/plugin/physics/src/component/SoftBodyChassisInternal.hpp` around lines 149 - 161, The IsValid() check always fails because skeletonBodyID is never set; update the code to remove the unused skeleton requirement by deleting HasValidSkeleton() and skeletonBodyID usages and change IsValid() (in SoftBodyChassisInternal) to return HasValidSoftBody() && isInitialized; then update any call sites (e.g., SyncSoftBodyChassisWithSkeleton loop in SoftBodyChassisSystem.cpp) that reference HasValidSkeleton or skeletonBodyID to rely on the new IsValid() semantics and ensure anchorsInitialized and softBodyID usage remain intact so processing continues when the soft body is present and initialized.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Not related to any issues
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.