Increased maximum value of HeightFieldShape::mBitsPerSample to 16 to allow for better precision
Made tolerance that's used in the internal edge removal algorithm configurable in CollideShapeSettings and PhysicsSettings
This commit is contained in:
parent
220b0b2f74
commit
ff59dd6d5a
10 changed files with 348 additions and 32 deletions
|
|
@ -100,7 +100,7 @@ bool JoltPhysicsDirectSpaceState3D::_cast_motion_impl(const JPH::Shape &p_jolt_s
|
||||||
eier_settings.mActiveEdgeMode = JPH::EActiveEdgeMode::CollideWithAll;
|
eier_settings.mActiveEdgeMode = JPH::EActiveEdgeMode::CollideWithAll;
|
||||||
eier_settings.mCollectFacesMode = JPH::ECollectFacesMode::CollectFaces;
|
eier_settings.mCollectFacesMode = JPH::ECollectFacesMode::CollectFaces;
|
||||||
|
|
||||||
JPH::InternalEdgeRemovingCollector eier_collector(collector);
|
JPH::InternalEdgeRemovingCollector eier_collector(collector, JPH::cDefaultInternalEdgeRemovalVertexToleranceSq);
|
||||||
other_shape.CollideShape(&motion_shape, scale, transform_com, eier_settings, base_offset, eier_collector, p_shape_filter);
|
other_shape.CollideShape(&motion_shape, scale, transform_com, eier_settings, base_offset, eier_collector, p_shape_filter);
|
||||||
eier_collector.Flush();
|
eier_collector.Flush();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
1
thirdparty/README.md
vendored
1
thirdparty/README.md
vendored
|
|
@ -524,6 +524,7 @@ Patches:
|
||||||
- `0002-backport-upstream-commit-bc7f1fb8c.patch` (GH-115305)
|
- `0002-backport-upstream-commit-bc7f1fb8c.patch` (GH-115305)
|
||||||
- `0003-backport-upstream-commit-365a15367.patch` (GH-115305)
|
- `0003-backport-upstream-commit-365a15367.patch` (GH-115305)
|
||||||
- `0004-backport-upstream-commit-e0a6a9a16.patch` (GH-115327)
|
- `0004-backport-upstream-commit-e0a6a9a16.patch` (GH-115327)
|
||||||
|
- `0005-backport-upstream-commit-449b645.patch` (GH-117194)
|
||||||
|
|
||||||
|
|
||||||
## libbacktrace
|
## libbacktrace
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ public:
|
||||||
|
|
||||||
/// How backfacing triangles should be treated
|
/// How backfacing triangles should be treated
|
||||||
EBackFaceMode mBackFaceMode = EBackFaceMode::IgnoreBackFaces;
|
EBackFaceMode mBackFaceMode = EBackFaceMode::IgnoreBackFaces;
|
||||||
|
|
||||||
|
/// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared. (unit: meter^2)
|
||||||
|
float mInternalEdgeRemovalVertexToleranceSq = cDefaultInternalEdgeRemovalVertexToleranceSq;
|
||||||
};
|
};
|
||||||
|
|
||||||
JPH_NAMESPACE_END
|
JPH_NAMESPACE_END
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class InternalEdgeRemovingCollector : public CollideShapeCollector
|
||||||
{
|
{
|
||||||
for (const Voided &vf : mVoidedFeatures)
|
for (const Voided &vf : mVoidedFeatures)
|
||||||
if (vf.mSubShapeID == inSubShapeID
|
if (vf.mSubShapeID == inSubShapeID
|
||||||
&& inV.IsClose(Vec3::sLoadFloat3Unsafe(vf.mFeature), 1.0e-8f))
|
&& inV.IsClose(Vec3::sLoadFloat3Unsafe(vf.mFeature), mVertexToleranceSq))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -76,13 +76,15 @@ class InternalEdgeRemovingCollector : public CollideShapeCollector
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor, configures a collector to be called with all the results that do not hit internal edges
|
/// Constructor, configures a collector to be called with all the results that do not hit internal edges
|
||||||
explicit InternalEdgeRemovingCollector(CollideShapeCollector &inChainedCollector
|
explicit InternalEdgeRemovingCollector(CollideShapeCollector &inChainedCollector,
|
||||||
|
float inVertexToleranceSq
|
||||||
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
, RVec3Arg inBaseOffset
|
, RVec3Arg inBaseOffset
|
||||||
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
) :
|
) :
|
||||||
CollideShapeCollector(inChainedCollector),
|
CollideShapeCollector(inChainedCollector),
|
||||||
mChainedCollector(inChainedCollector)
|
mChainedCollector(inChainedCollector),
|
||||||
|
mVertexToleranceSq(inVertexToleranceSq)
|
||||||
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
, mBaseOffset(inBaseOffset)
|
, mBaseOffset(inBaseOffset)
|
||||||
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
|
@ -249,7 +251,7 @@ public:
|
||||||
JPH_ASSERT(inCollideShapeSettings.mActiveEdgeMode == EActiveEdgeMode::CollideWithAll); // Won't work without colliding with all edges
|
JPH_ASSERT(inCollideShapeSettings.mActiveEdgeMode == EActiveEdgeMode::CollideWithAll); // Won't work without colliding with all edges
|
||||||
JPH_ASSERT(inCollideShapeSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces); // Won't work without collecting faces
|
JPH_ASSERT(inCollideShapeSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces); // Won't work without collecting faces
|
||||||
|
|
||||||
InternalEdgeRemovingCollector wrapper(ioCollector
|
InternalEdgeRemovingCollector wrapper(ioCollector, inCollideShapeSettings.mInternalEdgeRemovalVertexToleranceSq
|
||||||
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
, inBaseOffset
|
, inBaseOffset
|
||||||
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
|
@ -271,6 +273,7 @@ private:
|
||||||
CollideShapeCollector & mChainedCollector;
|
CollideShapeCollector & mChainedCollector;
|
||||||
Array<Voided, STLLocalAllocator<Voided, cMaxLocalVoidedFeatures>> mVoidedFeatures;
|
Array<Voided, STLLocalAllocator<Voided, cMaxLocalVoidedFeatures>> mVoidedFeatures;
|
||||||
Array<CollideShapeResult, STLLocalAllocator<CollideShapeResult, cMaxLocalDelayedResults>> mDelayedResults;
|
Array<CollideShapeResult, STLLocalAllocator<CollideShapeResult, cMaxLocalDelayedResults>> mDelayedResults;
|
||||||
|
float mVertexToleranceSq; // Max squared distance to consider a vertex to be the same as another vertex, used to determine if a feature is voided
|
||||||
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
RVec3 mBaseOffset; // Base offset for the query, used to draw the results in the right place
|
RVec3 mBaseOffset; // Base offset for the query, used to draw the results in the right place
|
||||||
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ void NarrowPhaseQuery::CollideShapeWithInternalEdgeRemoval(const Shape *inShape,
|
||||||
settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
|
settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
|
||||||
settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
|
settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
|
||||||
|
|
||||||
InternalEdgeRemovingCollector wrapper(ioCollector
|
InternalEdgeRemovingCollector wrapper(ioCollector, settings.mInternalEdgeRemovalVertexToleranceSq
|
||||||
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
, inBaseOffset
|
, inBaseOffset
|
||||||
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
|
|
||||||
|
|
@ -185,9 +185,9 @@ uint32 HeightFieldShapeSettings::CalculateBitsPerSampleForError(float inMaxError
|
||||||
// Not accurate enough, increase bits per sample
|
// Not accurate enough, increase bits per sample
|
||||||
bits_per_sample++;
|
bits_per_sample++;
|
||||||
|
|
||||||
// Don't go above 8 bits per sample
|
// Don't go above cMaxBitsPerSample bits per sample
|
||||||
if (bits_per_sample == 8)
|
if (bits_per_sample == cMaxBitsPerSample)
|
||||||
return bits_per_sample;
|
return cMaxBitsPerSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +416,7 @@ void HeightFieldShape::StoreMaterialIndices(const HeightFieldShapeSettings &inSe
|
||||||
|
|
||||||
void HeightFieldShape::CacheValues()
|
void HeightFieldShape::CacheValues()
|
||||||
{
|
{
|
||||||
mSampleMask = uint8((uint32(1) << mBitsPerSample) - 1);
|
mSampleMask = uint16((uint32(1) << mBitsPerSample) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightFieldShape::AllocateBuffers()
|
void HeightFieldShape::AllocateBuffers()
|
||||||
|
|
@ -424,7 +424,7 @@ void HeightFieldShape::AllocateBuffers()
|
||||||
uint num_blocks = GetNumBlocks();
|
uint num_blocks = GetNumBlocks();
|
||||||
uint max_stride = (num_blocks + 1) >> 1;
|
uint max_stride = (num_blocks + 1) >> 1;
|
||||||
mRangeBlocksSize = sGridOffsets[sGetMaxLevel(num_blocks) - 1] + Square(max_stride);
|
mRangeBlocksSize = sGridOffsets[sGetMaxLevel(num_blocks) - 1] + Square(max_stride);
|
||||||
mHeightSamplesSize = (mSampleCount * mSampleCount * mBitsPerSample + 7) / 8 + 1;
|
mHeightSamplesSize = (mSampleCount * mSampleCount * mBitsPerSample + 7) / 8 + 2; // Since we read 3 bytes per sample, we need 2 extra bytes of padding
|
||||||
mActiveEdgesSize = (Square(mSampleCount - 1) * 3 + 7) / 8 + 1; // See explanation at HeightFieldShape::CalculateActiveEdges
|
mActiveEdgesSize = (Square(mSampleCount - 1) * 3 + 7) / 8 + 1; // See explanation at HeightFieldShape::CalculateActiveEdges
|
||||||
|
|
||||||
JPH_ASSERT(mRangeBlocks == nullptr && mHeightSamples == nullptr && mActiveEdges == nullptr);
|
JPH_ASSERT(mRangeBlocks == nullptr && mHeightSamples == nullptr && mActiveEdges == nullptr);
|
||||||
|
|
@ -457,9 +457,9 @@ HeightFieldShape::HeightFieldShape(const HeightFieldShapeSettings &inSettings, S
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check bits per sample
|
// Check bits per sample
|
||||||
if (inSettings.mBitsPerSample < 1 || inSettings.mBitsPerSample > 8)
|
if (inSettings.mBitsPerSample < 1 || inSettings.mBitsPerSample > HeightFieldShapeConstants::cMaxBitsPerSample)
|
||||||
{
|
{
|
||||||
outResult.SetError("HeightFieldShape: Bits per sample must be in the range [1, 8]!");
|
outResult.SetError("HeightFieldShape: Bits per sample must be in the range [1, 16]!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -727,9 +727,10 @@ HeightFieldShape::HeightFieldShape(const HeightFieldShapeSettings &inSettings, S
|
||||||
uint byte_pos = sample >> 3;
|
uint byte_pos = sample >> 3;
|
||||||
uint bit_pos = sample & 0b111;
|
uint bit_pos = sample & 0b111;
|
||||||
output_value <<= bit_pos;
|
output_value <<= bit_pos;
|
||||||
JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
mHeightSamples[byte_pos] |= uint8(output_value);
|
mHeightSamples[byte_pos] |= uint8(output_value);
|
||||||
mHeightSamples[byte_pos + 1] |= uint8(output_value >> 8);
|
mHeightSamples[byte_pos + 1] |= uint8(output_value >> 8);
|
||||||
|
mHeightSamples[byte_pos + 2] |= uint8(output_value >> 16);
|
||||||
sample += inSettings.mBitsPerSample;
|
sample += inSettings.mBitsPerSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -816,7 +817,7 @@ inline void HeightFieldShape::GetBlockOffsetAndScale(uint inBlockX, uint inBlock
|
||||||
outBlockScale = float(block.mMax[n] - block.mMin[n]) / float(mSampleMask);
|
outBlockScale = float(block.mMax[n] - block.mMin[n]) / float(mSampleMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
inline uint16 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
||||||
{
|
{
|
||||||
JPH_ASSERT(inX < mSampleCount);
|
JPH_ASSERT(inX < mSampleCount);
|
||||||
JPH_ASSERT(inY < mSampleCount);
|
JPH_ASSERT(inY < mSampleCount);
|
||||||
|
|
@ -827,16 +828,16 @@ inline uint8 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
||||||
uint bit_pos = sample & 0b111;
|
uint bit_pos = sample & 0b111;
|
||||||
|
|
||||||
// Fetch the height sample value
|
// Fetch the height sample value
|
||||||
JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
const uint8 *height_samples = mHeightSamples + byte_pos;
|
const uint8 *height_samples = mHeightSamples + byte_pos;
|
||||||
uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
|
uint32 height_sample = uint32(height_samples[0]) | (uint32(height_samples[1]) << 8) | (uint32(height_samples[2]) << 16);
|
||||||
return uint8(height_sample >> bit_pos) & mSampleMask;
|
return uint16(height_sample >> bit_pos) & mSampleMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vec3 HeightFieldShape::GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const
|
inline Vec3 HeightFieldShape::GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const
|
||||||
{
|
{
|
||||||
// Get quantized value
|
// Get quantized value
|
||||||
uint8 height_sample = GetHeightSample(inX, inY);
|
uint16 height_sample = GetHeightSample(inX, inY);
|
||||||
outNoCollision = height_sample == mSampleMask;
|
outNoCollision = height_sample == mSampleMask;
|
||||||
|
|
||||||
// Add 0.5 to the quantized value to minimize the error (see constructor)
|
// Add 0.5 to the quantized value to minimize the error (see constructor)
|
||||||
|
|
@ -980,7 +981,7 @@ void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
uint output_y = block_y * mBlockSize + sample_y;
|
uint output_y = block_y * mBlockSize + sample_y;
|
||||||
|
|
||||||
// Get quantized value
|
// Get quantized value
|
||||||
uint8 height_sample = GetHeightSample(inX + output_x, inY + output_y);
|
uint16 height_sample = GetHeightSample(inX + output_x, inY + output_y);
|
||||||
|
|
||||||
// Dequantize
|
// Dequantize
|
||||||
float h = height_sample != mSampleMask? offset + height_sample * scale : cNoCollisionValue;
|
float h = height_sample != mSampleMask? offset + height_sample * scale : cNoCollisionValue;
|
||||||
|
|
@ -1129,7 +1130,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
{
|
{
|
||||||
// Quantize height
|
// Quantize height
|
||||||
float h = heights[sample_y * heights_stride + sample_x];
|
float h = heights[sample_y * heights_stride + sample_x];
|
||||||
uint8 quantized_height = h != cNoCollisionValue? uint8(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
|
uint16 quantized_height = h != cNoCollisionValue? uint16(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
|
||||||
|
|
||||||
// Determine bit position of sample
|
// Determine bit position of sample
|
||||||
uint sample = ((affected_y + sample_y) * mSampleCount + affected_x + sample_x) * uint(mBitsPerSample);
|
uint sample = ((affected_y + sample_y) * mSampleCount + affected_x + sample_x) * uint(mBitsPerSample);
|
||||||
|
|
@ -1137,13 +1138,14 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
uint bit_pos = sample & 0b111;
|
uint bit_pos = sample & 0b111;
|
||||||
|
|
||||||
// Update the height value sample
|
// Update the height value sample
|
||||||
JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
uint8 *height_samples = mHeightSamples + byte_pos;
|
uint8 *height_samples = mHeightSamples + byte_pos;
|
||||||
uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
|
uint32 height_sample = uint32(height_samples[0]) | (uint32(height_samples[1]) << 8) | (uint32(height_samples[2]) << 16);
|
||||||
height_sample &= ~(uint16(mSampleMask) << bit_pos);
|
height_sample &= ~(uint32(mSampleMask) << bit_pos);
|
||||||
height_sample |= uint16(quantized_height) << bit_pos;
|
height_sample |= uint32(quantized_height) << bit_pos;
|
||||||
height_samples[0] = uint8(height_sample);
|
height_samples[0] = uint8(height_sample);
|
||||||
height_samples[1] = uint8(height_sample >> 8);
|
height_samples[1] = uint8(height_sample >> 8);
|
||||||
|
height_samples[2] = uint8(height_sample >> 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ namespace HeightFieldShapeConstants
|
||||||
/// When height samples are converted to 16 bit:
|
/// When height samples are converted to 16 bit:
|
||||||
constexpr uint16 cNoCollisionValue16 = 0xffff; ///< This is the magic value for 'no collision'
|
constexpr uint16 cNoCollisionValue16 = 0xffff; ///< This is the magic value for 'no collision'
|
||||||
constexpr uint16 cMaxHeightValue16 = 0xfffe; ///< This is the maximum allowed height value
|
constexpr uint16 cMaxHeightValue16 = 0xfffe; ///< This is the maximum allowed height value
|
||||||
|
|
||||||
|
/// Maximum value for HeightFieldShapeSettings::mBitsPerSample
|
||||||
|
constexpr uint32 cMaxBitsPerSample = 16;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Class that constructs a HeightFieldShape
|
/// Class that constructs a HeightFieldShape
|
||||||
|
|
@ -63,7 +66,7 @@ public:
|
||||||
|
|
||||||
/// Given mBlockSize, mSampleCount and mHeightSamples, calculate the amount of bits needed to stay below absolute error inMaxError
|
/// Given mBlockSize, mSampleCount and mHeightSamples, calculate the amount of bits needed to stay below absolute error inMaxError
|
||||||
/// @param inMaxError Maximum allowed error in mHeightSamples after compression (note that this does not take mScale.Y into account)
|
/// @param inMaxError Maximum allowed error in mHeightSamples after compression (note that this does not take mScale.Y into account)
|
||||||
/// @return Needed bits per sample in the range [1, 8].
|
/// @return Needed bits per sample in the range [1, 16].
|
||||||
uint32 CalculateBitsPerSampleForError(float inMaxError) const;
|
uint32 CalculateBitsPerSampleForError(float inMaxError) const;
|
||||||
|
|
||||||
/// The height field is a surface defined by: mOffset + mScale * (x, mHeightSamples[y * mSampleCount + x], y).
|
/// The height field is a surface defined by: mOffset + mScale * (x, mHeightSamples[y * mSampleCount + x], y).
|
||||||
|
|
@ -83,12 +86,12 @@ public:
|
||||||
uint32 mMaterialsCapacity = 0;
|
uint32 mMaterialsCapacity = 0;
|
||||||
|
|
||||||
/// The heightfield is divided in blocks of mBlockSize * mBlockSize * 2 triangles and the acceleration structure culls blocks only,
|
/// The heightfield is divided in blocks of mBlockSize * mBlockSize * 2 triangles and the acceleration structure culls blocks only,
|
||||||
/// bigger block sizes reduce memory consumption but also reduce query performance. Sensible values are [2, 8], does not need to be
|
/// bigger block sizes reduce memory consumption but also reduce query performance. Valid values are [2, 8], does not need to be
|
||||||
/// a power of 2. Note that at run-time we'll perform one more grid subdivision, so the effective block size is half of what is provided here.
|
/// a power of 2. Note that at run-time we'll perform one more grid subdivision, so the effective block size is half of what is provided here.
|
||||||
uint32 mBlockSize = 2;
|
uint32 mBlockSize = 2;
|
||||||
|
|
||||||
/// How many bits per sample to use to compress the height field. Can be in the range [1, 8].
|
/// How many bits per sample to use to compress the height field. Can be in the range [1, 16].
|
||||||
/// Note that each sample is compressed relative to the min/max value of its block of mBlockSize * mBlockSize pixels so the effective precision is higher.
|
/// Note that each sample is compressed relative to the min/max value of its block of mBlockSize * mBlockSize samples so the effective precision is higher.
|
||||||
/// Also note that increasing mBlockSize saves more memory than reducing the amount of bits per sample.
|
/// Also note that increasing mBlockSize saves more memory than reducing the amount of bits per sample.
|
||||||
uint32 mBitsPerSample = 8;
|
uint32 mBitsPerSample = 8;
|
||||||
|
|
||||||
|
|
@ -307,7 +310,7 @@ private:
|
||||||
inline void GetBlockOffsetAndScale(uint inBlockX, uint inBlockY, uint inRangeBlockOffset, uint inRangeBlockStride, float &outBlockOffset, float &outBlockScale) const;
|
inline void GetBlockOffsetAndScale(uint inBlockX, uint inBlockY, uint inRangeBlockOffset, uint inRangeBlockStride, float &outBlockOffset, float &outBlockScale) const;
|
||||||
|
|
||||||
/// Get the height sample at position (inX, inY)
|
/// Get the height sample at position (inX, inY)
|
||||||
inline uint8 GetHeightSample(uint inX, uint inY) const;
|
inline uint16 GetHeightSample(uint inX, uint inY) const;
|
||||||
|
|
||||||
/// Faster version of GetPosition when block offset and scale are already known
|
/// Faster version of GetPosition when block offset and scale are already known
|
||||||
inline Vec3 GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const;
|
inline Vec3 GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const;
|
||||||
|
|
@ -358,7 +361,7 @@ private:
|
||||||
uint32 mRangeBlocksSize = 0; ///< Size of mRangeBlocks in elements
|
uint32 mRangeBlocksSize = 0; ///< Size of mRangeBlocks in elements
|
||||||
uint32 mActiveEdgesSize = 0; ///< Size of mActiveEdges in bytes
|
uint32 mActiveEdgesSize = 0; ///< Size of mActiveEdges in bytes
|
||||||
uint8 mBitsPerSample = 8; ///< See HeightFieldShapeSettings::mBitsPerSample
|
uint8 mBitsPerSample = 8; ///< See HeightFieldShapeSettings::mBitsPerSample
|
||||||
uint8 mSampleMask = 0xff; ///< All bits set for a sample: (1 << mBitsPerSample) - 1, used to indicate that there's no collision
|
uint16 mSampleMask = 0xff; ///< All bits set for a sample: (1 << mBitsPerSample) - 1, used to indicate that there's no collision
|
||||||
uint16 mMinSample = HeightFieldShapeConstants::cNoCollisionValue16; ///< Min and max value in mHeightSamples quantized to 16 bit, for calculating bounding box
|
uint16 mMinSample = HeightFieldShapeConstants::cNoCollisionValue16; ///< Min and max value in mHeightSamples quantized to 16 bit, for calculating bounding box
|
||||||
uint16 mMaxSample = HeightFieldShapeConstants::cNoCollisionValue16;
|
uint16 mMaxSample = HeightFieldShapeConstants::cNoCollisionValue16;
|
||||||
RangeBlock * mRangeBlocks = nullptr; ///< Hierarchical grid of range data describing the height variations within 1 block. The grid for level <level> starts at offset sGridOffsets[<level>]
|
RangeBlock * mRangeBlocks = nullptr; ///< Hierarchical grid of range data describing the height variations within 1 block. The grid for level <level> starts at offset sGridOffsets[<level>]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,10 @@ constexpr float cDefaultPenetrationTolerance = 1.0e-4f; ///< Stop when there's l
|
||||||
constexpr float cDefaultConvexRadius = 0.05f;
|
constexpr float cDefaultConvexRadius = 0.05f;
|
||||||
|
|
||||||
/// Used by (Tapered)CapsuleShape to determine when supporting face is an edge rather than a point (unit: meter)
|
/// Used by (Tapered)CapsuleShape to determine when supporting face is an edge rather than a point (unit: meter)
|
||||||
static constexpr float cCapsuleProjectionSlop = 0.02f;
|
constexpr float cCapsuleProjectionSlop = 0.02f;
|
||||||
|
|
||||||
|
/// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared (unit: meter^2)
|
||||||
|
constexpr float cDefaultInternalEdgeRemovalVertexToleranceSq = 1.0e-8f;
|
||||||
|
|
||||||
/// Maximum amount of jobs to allow
|
/// Maximum amount of jobs to allow
|
||||||
constexpr int cMaxPhysicsJobs = 2048;
|
constexpr int cMaxPhysicsJobs = 2048;
|
||||||
|
|
@ -73,6 +76,9 @@ struct PhysicsSettings
|
||||||
/// Maximum allowed distance between old and new contact point to preserve contact forces for warm start (units: meter^2)
|
/// Maximum allowed distance between old and new contact point to preserve contact forces for warm start (units: meter^2)
|
||||||
float mContactPointPreserveLambdaMaxDistSq = Square(0.01f); ///< 1 cm
|
float mContactPointPreserveLambdaMaxDistSq = Square(0.01f); ///< 1 cm
|
||||||
|
|
||||||
|
/// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared. (unit: meter^2)
|
||||||
|
float mInternalEdgeRemovalVertexToleranceSq = cDefaultInternalEdgeRemovalVertexToleranceSq;
|
||||||
|
|
||||||
/// Number of solver velocity iterations to run
|
/// Number of solver velocity iterations to run
|
||||||
/// Note that this needs to be >= 2 in order for friction to work (friction is applied using the non-penetration impulse from the previous iteration)
|
/// Note that this needs to be >= 2 in order for friction to work (friction is applied using the non-penetration impulse from the previous iteration)
|
||||||
uint mNumVelocitySteps = 10;
|
uint mNumVelocitySteps = 10;
|
||||||
|
|
|
||||||
|
|
@ -1096,6 +1096,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
|
||||||
settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
|
settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
|
||||||
settings.mMaxSeparationDistance = body1->IsSensor() || body2->IsSensor()? 0.0f : mPhysicsSettings.mSpeculativeContactDistance;
|
settings.mMaxSeparationDistance = body1->IsSensor() || body2->IsSensor()? 0.0f : mPhysicsSettings.mSpeculativeContactDistance;
|
||||||
settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity();
|
settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity();
|
||||||
|
settings.mInternalEdgeRemovalVertexToleranceSq = mPhysicsSettings.mInternalEdgeRemovalVertexToleranceSq;
|
||||||
|
|
||||||
// Create shape filter
|
// Create shape filter
|
||||||
SimShapeFilterWrapper shape_filter(mSimShapeFilter, body1);
|
SimShapeFilterWrapper shape_filter(mSimShapeFilter, body1);
|
||||||
|
|
|
||||||
297
thirdparty/jolt_physics/patches/0005-backport-upstream-commit-449b645.patch
vendored
Normal file
297
thirdparty/jolt_physics/patches/0005-backport-upstream-commit-449b645.patch
vendored
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h b/thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h
|
||||||
|
index cfec8139..134f300d 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/Collision/CollideShape.h
|
||||||
|
@@ -101,6 +101,9 @@ public:
|
||||||
|
|
||||||
|
/// How backfacing triangles should be treated
|
||||||
|
EBackFaceMode mBackFaceMode = EBackFaceMode::IgnoreBackFaces;
|
||||||
|
+
|
||||||
|
+ /// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared. (unit: meter^2)
|
||||||
|
+ float mInternalEdgeRemovalVertexToleranceSq = cDefaultInternalEdgeRemovalVertexToleranceSq;
|
||||||
|
};
|
||||||
|
|
||||||
|
JPH_NAMESPACE_END
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h b/thirdparty/jolt_physics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h
|
||||||
|
index cec7d7be..eee55022 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/Collision/InternalEdgeRemovingCollector.h
|
||||||
|
@@ -31,7 +31,7 @@ class InternalEdgeRemovingCollector : public CollideShapeCollector
|
||||||
|
{
|
||||||
|
for (const Voided &vf : mVoidedFeatures)
|
||||||
|
if (vf.mSubShapeID == inSubShapeID
|
||||||
|
- && inV.IsClose(Vec3::sLoadFloat3Unsafe(vf.mFeature), 1.0e-8f))
|
||||||
|
+ && inV.IsClose(Vec3::sLoadFloat3Unsafe(vf.mFeature), mVertexToleranceSq))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -76,13 +76,15 @@ class InternalEdgeRemovingCollector : public CollideShapeCollector
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Constructor, configures a collector to be called with all the results that do not hit internal edges
|
||||||
|
- explicit InternalEdgeRemovingCollector(CollideShapeCollector &inChainedCollector
|
||||||
|
+ explicit InternalEdgeRemovingCollector(CollideShapeCollector &inChainedCollector,
|
||||||
|
+ float inVertexToleranceSq
|
||||||
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
, RVec3Arg inBaseOffset
|
||||||
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
) :
|
||||||
|
CollideShapeCollector(inChainedCollector),
|
||||||
|
- mChainedCollector(inChainedCollector)
|
||||||
|
+ mChainedCollector(inChainedCollector),
|
||||||
|
+ mVertexToleranceSq(inVertexToleranceSq)
|
||||||
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
, mBaseOffset(inBaseOffset)
|
||||||
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
@@ -249,7 +251,7 @@ public:
|
||||||
|
JPH_ASSERT(inCollideShapeSettings.mActiveEdgeMode == EActiveEdgeMode::CollideWithAll); // Won't work without colliding with all edges
|
||||||
|
JPH_ASSERT(inCollideShapeSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces); // Won't work without collecting faces
|
||||||
|
|
||||||
|
- InternalEdgeRemovingCollector wrapper(ioCollector
|
||||||
|
+ InternalEdgeRemovingCollector wrapper(ioCollector, inCollideShapeSettings.mInternalEdgeRemovalVertexToleranceSq
|
||||||
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
, inBaseOffset
|
||||||
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
@@ -271,6 +273,7 @@ private:
|
||||||
|
CollideShapeCollector & mChainedCollector;
|
||||||
|
Array<Voided, STLLocalAllocator<Voided, cMaxLocalVoidedFeatures>> mVoidedFeatures;
|
||||||
|
Array<CollideShapeResult, STLLocalAllocator<CollideShapeResult, cMaxLocalDelayedResults>> mDelayedResults;
|
||||||
|
+ float mVertexToleranceSq; // Max squared distance to consider a vertex to be the same as another vertex, used to determine if a feature is voided
|
||||||
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
RVec3 mBaseOffset; // Base offset for the query, used to draw the results in the right place
|
||||||
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp b/thirdparty/jolt_physics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp
|
||||||
|
index 670cee33..1a8c2c78 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp
|
||||||
|
@@ -301,7 +301,7 @@ void NarrowPhaseQuery::CollideShapeWithInternalEdgeRemoval(const Shape *inShape,
|
||||||
|
settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
|
||||||
|
settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
|
||||||
|
|
||||||
|
- InternalEdgeRemovingCollector wrapper(ioCollector
|
||||||
|
+ InternalEdgeRemovingCollector wrapper(ioCollector, settings.mInternalEdgeRemovalVertexToleranceSq
|
||||||
|
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
, inBaseOffset
|
||||||
|
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp b/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp
|
||||||
|
index ff55f4ba..d859b22e 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.cpp
|
||||||
|
@@ -185,9 +185,9 @@ uint32 HeightFieldShapeSettings::CalculateBitsPerSampleForError(float inMaxError
|
||||||
|
// Not accurate enough, increase bits per sample
|
||||||
|
bits_per_sample++;
|
||||||
|
|
||||||
|
- // Don't go above 8 bits per sample
|
||||||
|
- if (bits_per_sample == 8)
|
||||||
|
- return bits_per_sample;
|
||||||
|
+ // Don't go above cMaxBitsPerSample bits per sample
|
||||||
|
+ if (bits_per_sample == cMaxBitsPerSample)
|
||||||
|
+ return cMaxBitsPerSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -416,7 +416,7 @@ void HeightFieldShape::StoreMaterialIndices(const HeightFieldShapeSettings &inSe
|
||||||
|
|
||||||
|
void HeightFieldShape::CacheValues()
|
||||||
|
{
|
||||||
|
- mSampleMask = uint8((uint32(1) << mBitsPerSample) - 1);
|
||||||
|
+ mSampleMask = uint16((uint32(1) << mBitsPerSample) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightFieldShape::AllocateBuffers()
|
||||||
|
@@ -424,7 +424,7 @@ void HeightFieldShape::AllocateBuffers()
|
||||||
|
uint num_blocks = GetNumBlocks();
|
||||||
|
uint max_stride = (num_blocks + 1) >> 1;
|
||||||
|
mRangeBlocksSize = sGridOffsets[sGetMaxLevel(num_blocks) - 1] + Square(max_stride);
|
||||||
|
- mHeightSamplesSize = (mSampleCount * mSampleCount * mBitsPerSample + 7) / 8 + 1;
|
||||||
|
+ mHeightSamplesSize = (mSampleCount * mSampleCount * mBitsPerSample + 7) / 8 + 2; // Since we read 3 bytes per sample, we need 2 extra bytes of padding
|
||||||
|
mActiveEdgesSize = (Square(mSampleCount - 1) * 3 + 7) / 8 + 1; // See explanation at HeightFieldShape::CalculateActiveEdges
|
||||||
|
|
||||||
|
JPH_ASSERT(mRangeBlocks == nullptr && mHeightSamples == nullptr && mActiveEdges == nullptr);
|
||||||
|
@@ -457,9 +457,9 @@ HeightFieldShape::HeightFieldShape(const HeightFieldShapeSettings &inSettings, S
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check bits per sample
|
||||||
|
- if (inSettings.mBitsPerSample < 1 || inSettings.mBitsPerSample > 8)
|
||||||
|
+ if (inSettings.mBitsPerSample < 1 || inSettings.mBitsPerSample > HeightFieldShapeConstants::cMaxBitsPerSample)
|
||||||
|
{
|
||||||
|
- outResult.SetError("HeightFieldShape: Bits per sample must be in the range [1, 8]!");
|
||||||
|
+ outResult.SetError("HeightFieldShape: Bits per sample must be in the range [1, 16]!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -727,9 +727,10 @@ HeightFieldShape::HeightFieldShape(const HeightFieldShapeSettings &inSettings, S
|
||||||
|
uint byte_pos = sample >> 3;
|
||||||
|
uint bit_pos = sample & 0b111;
|
||||||
|
output_value <<= bit_pos;
|
||||||
|
- JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
||||||
|
+ JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
|
mHeightSamples[byte_pos] |= uint8(output_value);
|
||||||
|
mHeightSamples[byte_pos + 1] |= uint8(output_value >> 8);
|
||||||
|
+ mHeightSamples[byte_pos + 2] |= uint8(output_value >> 16);
|
||||||
|
sample += inSettings.mBitsPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -816,7 +817,7 @@ inline void HeightFieldShape::GetBlockOffsetAndScale(uint inBlockX, uint inBlock
|
||||||
|
outBlockScale = float(block.mMax[n] - block.mMin[n]) / float(mSampleMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
-inline uint8 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
||||||
|
+inline uint16 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
||||||
|
{
|
||||||
|
JPH_ASSERT(inX < mSampleCount);
|
||||||
|
JPH_ASSERT(inY < mSampleCount);
|
||||||
|
@@ -827,16 +828,16 @@ inline uint8 HeightFieldShape::GetHeightSample(uint inX, uint inY) const
|
||||||
|
uint bit_pos = sample & 0b111;
|
||||||
|
|
||||||
|
// Fetch the height sample value
|
||||||
|
- JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
||||||
|
+ JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
|
const uint8 *height_samples = mHeightSamples + byte_pos;
|
||||||
|
- uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
|
||||||
|
- return uint8(height_sample >> bit_pos) & mSampleMask;
|
||||||
|
+ uint32 height_sample = uint32(height_samples[0]) | (uint32(height_samples[1]) << 8) | (uint32(height_samples[2]) << 16);
|
||||||
|
+ return uint16(height_sample >> bit_pos) & mSampleMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 HeightFieldShape::GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const
|
||||||
|
{
|
||||||
|
// Get quantized value
|
||||||
|
- uint8 height_sample = GetHeightSample(inX, inY);
|
||||||
|
+ uint16 height_sample = GetHeightSample(inX, inY);
|
||||||
|
outNoCollision = height_sample == mSampleMask;
|
||||||
|
|
||||||
|
// Add 0.5 to the quantized value to minimize the error (see constructor)
|
||||||
|
@@ -980,7 +981,7 @@ void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
|
uint output_y = block_y * mBlockSize + sample_y;
|
||||||
|
|
||||||
|
// Get quantized value
|
||||||
|
- uint8 height_sample = GetHeightSample(inX + output_x, inY + output_y);
|
||||||
|
+ uint16 height_sample = GetHeightSample(inX + output_x, inY + output_y);
|
||||||
|
|
||||||
|
// Dequantize
|
||||||
|
float h = height_sample != mSampleMask? offset + height_sample * scale : cNoCollisionValue;
|
||||||
|
@@ -1129,7 +1130,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
|
{
|
||||||
|
// Quantize height
|
||||||
|
float h = heights[sample_y * heights_stride + sample_x];
|
||||||
|
- uint8 quantized_height = h != cNoCollisionValue? uint8(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
|
||||||
|
+ uint16 quantized_height = h != cNoCollisionValue? uint16(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
|
||||||
|
|
||||||
|
// Determine bit position of sample
|
||||||
|
uint sample = ((affected_y + sample_y) * mSampleCount + affected_x + sample_x) * uint(mBitsPerSample);
|
||||||
|
@@ -1137,13 +1138,14 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
|
||||||
|
uint bit_pos = sample & 0b111;
|
||||||
|
|
||||||
|
// Update the height value sample
|
||||||
|
- JPH_ASSERT(byte_pos + 1 < mHeightSamplesSize);
|
||||||
|
+ JPH_ASSERT(byte_pos + 2 < mHeightSamplesSize); // We read max 16 bits which could be spread out over 3 bytes
|
||||||
|
uint8 *height_samples = mHeightSamples + byte_pos;
|
||||||
|
- uint16 height_sample = uint16(height_samples[0]) | uint16(uint16(height_samples[1]) << 8);
|
||||||
|
- height_sample &= ~(uint16(mSampleMask) << bit_pos);
|
||||||
|
- height_sample |= uint16(quantized_height) << bit_pos;
|
||||||
|
+ uint32 height_sample = uint32(height_samples[0]) | (uint32(height_samples[1]) << 8) | (uint32(height_samples[2]) << 16);
|
||||||
|
+ height_sample &= ~(uint32(mSampleMask) << bit_pos);
|
||||||
|
+ height_sample |= uint32(quantized_height) << bit_pos;
|
||||||
|
height_samples[0] = uint8(height_sample);
|
||||||
|
height_samples[1] = uint8(height_sample >> 8);
|
||||||
|
+ height_samples[2] = uint8(height_sample >> 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.h b/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.h
|
||||||
|
index 5aa6de88..c9bdc605 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.h
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/HeightFieldShape.h
|
||||||
|
@@ -33,6 +33,9 @@ namespace HeightFieldShapeConstants
|
||||||
|
/// When height samples are converted to 16 bit:
|
||||||
|
constexpr uint16 cNoCollisionValue16 = 0xffff; ///< This is the magic value for 'no collision'
|
||||||
|
constexpr uint16 cMaxHeightValue16 = 0xfffe; ///< This is the maximum allowed height value
|
||||||
|
+
|
||||||
|
+ /// Maximum value for HeightFieldShapeSettings::mBitsPerSample
|
||||||
|
+ constexpr uint32 cMaxBitsPerSample = 16;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class that constructs a HeightFieldShape
|
||||||
|
@@ -63,7 +66,7 @@ public:
|
||||||
|
|
||||||
|
/// Given mBlockSize, mSampleCount and mHeightSamples, calculate the amount of bits needed to stay below absolute error inMaxError
|
||||||
|
/// @param inMaxError Maximum allowed error in mHeightSamples after compression (note that this does not take mScale.Y into account)
|
||||||
|
- /// @return Needed bits per sample in the range [1, 8].
|
||||||
|
+ /// @return Needed bits per sample in the range [1, 16].
|
||||||
|
uint32 CalculateBitsPerSampleForError(float inMaxError) const;
|
||||||
|
|
||||||
|
/// The height field is a surface defined by: mOffset + mScale * (x, mHeightSamples[y * mSampleCount + x], y).
|
||||||
|
@@ -83,12 +86,12 @@ public:
|
||||||
|
uint32 mMaterialsCapacity = 0;
|
||||||
|
|
||||||
|
/// The heightfield is divided in blocks of mBlockSize * mBlockSize * 2 triangles and the acceleration structure culls blocks only,
|
||||||
|
- /// bigger block sizes reduce memory consumption but also reduce query performance. Sensible values are [2, 8], does not need to be
|
||||||
|
+ /// bigger block sizes reduce memory consumption but also reduce query performance. Valid values are [2, 8], does not need to be
|
||||||
|
/// a power of 2. Note that at run-time we'll perform one more grid subdivision, so the effective block size is half of what is provided here.
|
||||||
|
uint32 mBlockSize = 2;
|
||||||
|
|
||||||
|
- /// How many bits per sample to use to compress the height field. Can be in the range [1, 8].
|
||||||
|
- /// Note that each sample is compressed relative to the min/max value of its block of mBlockSize * mBlockSize pixels so the effective precision is higher.
|
||||||
|
+ /// How many bits per sample to use to compress the height field. Can be in the range [1, 16].
|
||||||
|
+ /// Note that each sample is compressed relative to the min/max value of its block of mBlockSize * mBlockSize samples so the effective precision is higher.
|
||||||
|
/// Also note that increasing mBlockSize saves more memory than reducing the amount of bits per sample.
|
||||||
|
uint32 mBitsPerSample = 8;
|
||||||
|
|
||||||
|
@@ -307,7 +310,7 @@ private:
|
||||||
|
inline void GetBlockOffsetAndScale(uint inBlockX, uint inBlockY, uint inRangeBlockOffset, uint inRangeBlockStride, float &outBlockOffset, float &outBlockScale) const;
|
||||||
|
|
||||||
|
/// Get the height sample at position (inX, inY)
|
||||||
|
- inline uint8 GetHeightSample(uint inX, uint inY) const;
|
||||||
|
+ inline uint16 GetHeightSample(uint inX, uint inY) const;
|
||||||
|
|
||||||
|
/// Faster version of GetPosition when block offset and scale are already known
|
||||||
|
inline Vec3 GetPosition(uint inX, uint inY, float inBlockOffset, float inBlockScale, bool &outNoCollision) const;
|
||||||
|
@@ -358,7 +361,7 @@ private:
|
||||||
|
uint32 mRangeBlocksSize = 0; ///< Size of mRangeBlocks in elements
|
||||||
|
uint32 mActiveEdgesSize = 0; ///< Size of mActiveEdges in bytes
|
||||||
|
uint8 mBitsPerSample = 8; ///< See HeightFieldShapeSettings::mBitsPerSample
|
||||||
|
- uint8 mSampleMask = 0xff; ///< All bits set for a sample: (1 << mBitsPerSample) - 1, used to indicate that there's no collision
|
||||||
|
+ uint16 mSampleMask = 0xff; ///< All bits set for a sample: (1 << mBitsPerSample) - 1, used to indicate that there's no collision
|
||||||
|
uint16 mMinSample = HeightFieldShapeConstants::cNoCollisionValue16; ///< Min and max value in mHeightSamples quantized to 16 bit, for calculating bounding box
|
||||||
|
uint16 mMaxSample = HeightFieldShapeConstants::cNoCollisionValue16;
|
||||||
|
RangeBlock * mRangeBlocks = nullptr; ///< Hierarchical grid of range data describing the height variations within 1 block. The grid for level <level> starts at offset sGridOffsets[<level>]
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h b/thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h
|
||||||
|
index 1109e253..cbd88d1a 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/PhysicsSettings.h
|
||||||
|
@@ -16,7 +16,10 @@ constexpr float cDefaultPenetrationTolerance = 1.0e-4f; ///< Stop when there's l
|
||||||
|
constexpr float cDefaultConvexRadius = 0.05f;
|
||||||
|
|
||||||
|
/// Used by (Tapered)CapsuleShape to determine when supporting face is an edge rather than a point (unit: meter)
|
||||||
|
-static constexpr float cCapsuleProjectionSlop = 0.02f;
|
||||||
|
+constexpr float cCapsuleProjectionSlop = 0.02f;
|
||||||
|
+
|
||||||
|
+/// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared (unit: meter^2)
|
||||||
|
+constexpr float cDefaultInternalEdgeRemovalVertexToleranceSq = 1.0e-8f;
|
||||||
|
|
||||||
|
/// Maximum amount of jobs to allow
|
||||||
|
constexpr int cMaxPhysicsJobs = 2048;
|
||||||
|
@@ -73,6 +76,9 @@ struct PhysicsSettings
|
||||||
|
/// Maximum allowed distance between old and new contact point to preserve contact forces for warm start (units: meter^2)
|
||||||
|
float mContactPointPreserveLambdaMaxDistSq = Square(0.01f); ///< 1 cm
|
||||||
|
|
||||||
|
+ /// Max squared distance to consider a vertex to be the same as another vertex, used by the internal edge removal algorithm to determine if two edges are shared. (unit: meter^2)
|
||||||
|
+ float mInternalEdgeRemovalVertexToleranceSq = cDefaultInternalEdgeRemovalVertexToleranceSq;
|
||||||
|
+
|
||||||
|
/// Number of solver velocity iterations to run
|
||||||
|
/// Note that this needs to be >= 2 in order for friction to work (friction is applied using the non-penetration impulse from the previous iteration)
|
||||||
|
uint mNumVelocitySteps = 10;
|
||||||
|
diff --git a/thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp b/thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp
|
||||||
|
index 7b4babfc..c2ead513 100644
|
||||||
|
--- a/thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp
|
||||||
|
+++ b/thirdparty/jolt_physics/Jolt/Physics/PhysicsSystem.cpp
|
||||||
|
@@ -1096,6 +1096,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
|
||||||
|
settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
|
||||||
|
settings.mMaxSeparationDistance = body1->IsSensor() || body2->IsSensor()? 0.0f : mPhysicsSettings.mSpeculativeContactDistance;
|
||||||
|
settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity();
|
||||||
|
+ settings.mInternalEdgeRemovalVertexToleranceSq = mPhysicsSettings.mInternalEdgeRemovalVertexToleranceSq;
|
||||||
|
|
||||||
|
// Create shape filter
|
||||||
|
SimShapeFilterWrapper shape_filter(mSimShapeFilter, body1);
|
||||||
|
2.52.0.windows.1
|
||||||
Loading…
Add table
Add a link
Reference in a new issue