@@ -9,7 +9,7 @@
|
||||
#include "Skin_Common.azsli"
|
||||
|
||||
// SRGs
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/Skin/SkinObjectSrg.azsli>
|
||||
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
|
||||
|
||||
// Pass Output
|
||||
|
||||
@@ -973,15 +973,15 @@
|
||||
"tag": "ForwardPass"
|
||||
},
|
||||
{
|
||||
"file": "Shaders/Shadow/Shadowmap.shader",
|
||||
"file": "Shaders/Shadow/ShadowmapSkin.shader",
|
||||
"tag": "Shadowmap"
|
||||
},
|
||||
{
|
||||
"file": "Shaders/Depth/DepthPass.shader",
|
||||
"file": "Shaders/Depth/DepthPassSkin.shader",
|
||||
"tag": "DepthPass"
|
||||
},
|
||||
{
|
||||
"file": "Shaders/MotionVector/MeshMotionVector.shader",
|
||||
"file": "Shaders/MotionVector/MeshMotionVectorSkin.shader",
|
||||
"tag": "MeshMotionVector"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -27,16 +27,6 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId);
|
||||
}
|
||||
|
||||
//[GFX TODO][ATOM-15280] Move wrinkle mask data from the default object srg into something specific to the Skin shader
|
||||
uint m_wrinkle_mask_count;
|
||||
float4 m_wrinkle_mask_weights[4];
|
||||
Texture2D m_wrinkle_masks[16];
|
||||
|
||||
float GetWrinkleMaskWeight(uint index)
|
||||
{
|
||||
return m_wrinkle_mask_weights[index / 4][index % 4];
|
||||
}
|
||||
|
||||
//! Reflection Probe (smallest probe volume that overlaps the object position)
|
||||
struct ReflectionProbeData
|
||||
{
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
|
||||
ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
{
|
||||
uint m_objectId;
|
||||
|
||||
//! Returns the matrix for transforming points from Object Space to World Space.
|
||||
float4x4 GetWorldMatrix()
|
||||
{
|
||||
return SceneSrg::GetObjectToWorldMatrix(m_objectId);
|
||||
}
|
||||
|
||||
//! Returns the inverse-transpose of the world matrix.
|
||||
//! Commonly used to transform normals while supporting non-uniform scale.
|
||||
float3x3 GetWorldMatrixInverseTranspose()
|
||||
{
|
||||
return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId);
|
||||
}
|
||||
|
||||
uint m_wrinkle_mask_count;
|
||||
float4 m_wrinkle_mask_weights[4];
|
||||
Texture2D m_wrinkle_masks[16];
|
||||
|
||||
float GetWrinkleMaskWeight(uint index)
|
||||
{
|
||||
return m_wrinkle_mask_weights[index / 4][index % 4];
|
||||
}
|
||||
|
||||
//! Reflection Probe (smallest probe volume that overlaps the object position)
|
||||
struct ReflectionProbeData
|
||||
{
|
||||
row_major float3x4 m_modelToWorld;
|
||||
row_major float3x4 m_modelToWorldInverse; // does not include extents
|
||||
float3 m_outerObbHalfLengths;
|
||||
float3 m_innerObbHalfLengths;
|
||||
float m_padding;
|
||||
bool m_useReflectionProbe;
|
||||
bool m_useParallaxCorrection;
|
||||
};
|
||||
|
||||
ReflectionProbeData m_reflectionProbeData;
|
||||
TextureCube m_reflectionProbeCubeMap;
|
||||
|
||||
float4x4 GetReflectionProbeWorldMatrix()
|
||||
{
|
||||
float4x4 modelToWorld = float4x4(
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(0, 0, 0, 1));
|
||||
|
||||
modelToWorld[0] = m_reflectionProbeData.m_modelToWorld[0];
|
||||
modelToWorld[1] = m_reflectionProbeData.m_modelToWorld[1];
|
||||
modelToWorld[2] = m_reflectionProbeData.m_modelToWorld[2];
|
||||
return modelToWorld;
|
||||
}
|
||||
|
||||
float4x4 GetReflectionProbeWorldMatrixInverse()
|
||||
{
|
||||
float4x4 modelToWorldInverse = float4x4(
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(0, 0, 0, 1));
|
||||
|
||||
modelToWorldInverse[0] = m_reflectionProbeData.m_modelToWorldInverse[0];
|
||||
modelToWorldInverse[1] = m_reflectionProbeData.m_modelToWorldInverse[1];
|
||||
modelToWorldInverse[2] = m_reflectionProbeData.m_modelToWorldInverse[2];
|
||||
return modelToWorldInverse;
|
||||
}
|
||||
}
|
||||
@@ -6,30 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <DepthPassCommon.azsli>
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
};
|
||||
|
||||
struct VSDepthOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
};
|
||||
|
||||
VSDepthOutput DepthPassVS(VSInput IN)
|
||||
{
|
||||
VSDepthOutput OUT;
|
||||
|
||||
float4x4 objectToWorld = ObjectSrg::GetWorldMatrix();
|
||||
float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0));
|
||||
OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Use the depth pass shader with the default object srg
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <viewsrg.srgi>
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
};
|
||||
|
||||
struct VSDepthOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
};
|
||||
|
||||
VSDepthOutput DepthPassVS(VSInput IN)
|
||||
{
|
||||
VSDepthOutput OUT;
|
||||
|
||||
float4x4 objectToWorld = ObjectSrg::GetWorldMatrix();
|
||||
float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0));
|
||||
OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/Skin/SkinObjectSrg.azsli>
|
||||
#include <DepthPassCommon.azsli>
|
||||
|
||||
// Use the depth pass shader with the skin object srg
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"Source" : "DepthPassSkin",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
|
||||
},
|
||||
|
||||
"CompilerHints" : {
|
||||
"DisableOptimizations" : false
|
||||
},
|
||||
|
||||
"ProgramSettings" :
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "DepthPassVS",
|
||||
"type" : "Vertex"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"DrawList" : "depth"
|
||||
}
|
||||
@@ -6,77 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include <viewsrg.srgi>
|
||||
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
#include <MeshMotionVectorCommon.azsli>
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
|
||||
// This gets set automatically by the system at runtime only if it's available.
|
||||
// There is a soft naming convention that associates this with o_prevPosition_isBound, which will be set to true whenever m_optional_prevPosition is available.
|
||||
// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention).
|
||||
// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream.
|
||||
// Vertex position of last frame to capture small scale motion due to vertex animation
|
||||
float3 m_optional_prevPosition : POSITIONT;
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
float3 m_worldPos : TEXCOORD0;
|
||||
float3 m_worldPosPrev: TEXCOORD1;
|
||||
};
|
||||
|
||||
struct PSOutput
|
||||
{
|
||||
float2 m_motion : SV_Target0;
|
||||
};
|
||||
|
||||
// Indicates whether the vertex input struct's "m_optional_prevPosition" is bound. If false, it is not safe to read from m_optional_prevPosition.
|
||||
// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_prevPosition.
|
||||
// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention).
|
||||
// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream.
|
||||
option bool o_prevPosition_isBound;
|
||||
|
||||
VSOutput MainVS(VSInput IN)
|
||||
{
|
||||
VSOutput OUT;
|
||||
|
||||
OUT.m_worldPos = mul(SceneSrg::GetObjectToWorldMatrix(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz;
|
||||
OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPos, 1.0));
|
||||
|
||||
if (o_prevPosition_isBound)
|
||||
{
|
||||
OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_optional_prevPosition, 1.0)).xyz;
|
||||
}
|
||||
else
|
||||
{
|
||||
OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz;
|
||||
}
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
PSOutput OUT;
|
||||
|
||||
// Current clip position
|
||||
float4 clipPos = mul(ViewSrg::m_viewProjectionMatrix, float4(IN.m_worldPos, 1.0));
|
||||
|
||||
// Reprojected last frame's clip position, for skinned mesh it also implies last key frame
|
||||
float4 clipPosPrev = mul(ViewSrg::m_viewProjectionPrevMatrix, float4(IN.m_worldPosPrev, 1.0));
|
||||
|
||||
float2 motion = (clipPos.xy / clipPos.w - clipPosPrev.xy / clipPosPrev.w) * 0.5;
|
||||
|
||||
OUT.m_motion = motion;
|
||||
|
||||
// Flip y to line up with uv coordinates
|
||||
OUT.m_motion.y = -OUT.m_motion.y;
|
||||
|
||||
return OUT;
|
||||
}
|
||||
// Use the mesh motion vector with the default object srg
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include <viewsrg.srgi>
|
||||
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
|
||||
// This gets set automatically by the system at runtime only if it's available.
|
||||
// There is a soft naming convention that associates this with o_prevPosition_isBound, which will be set to true whenever m_optional_prevPosition is available.
|
||||
// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention).
|
||||
// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream.
|
||||
// Vertex position of last frame to capture small scale motion due to vertex animation
|
||||
float3 m_optional_prevPosition : POSITIONT;
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
float3 m_worldPos : TEXCOORD0;
|
||||
float3 m_worldPosPrev: TEXCOORD1;
|
||||
};
|
||||
|
||||
struct PSOutput
|
||||
{
|
||||
float2 m_motion : SV_Target0;
|
||||
};
|
||||
|
||||
// Indicates whether the vertex input struct's "m_optional_prevPosition" is bound. If false, it is not safe to read from m_optional_prevPosition.
|
||||
// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_prevPosition.
|
||||
// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention).
|
||||
// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream.
|
||||
option bool o_prevPosition_isBound;
|
||||
|
||||
VSOutput MainVS(VSInput IN)
|
||||
{
|
||||
VSOutput OUT;
|
||||
|
||||
OUT.m_worldPos = mul(SceneSrg::GetObjectToWorldMatrix(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz;
|
||||
OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPos, 1.0));
|
||||
|
||||
if (o_prevPosition_isBound)
|
||||
{
|
||||
OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_optional_prevPosition, 1.0)).xyz;
|
||||
}
|
||||
else
|
||||
{
|
||||
OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz;
|
||||
}
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
PSOutput OUT;
|
||||
|
||||
// Current clip position
|
||||
float4 clipPos = mul(ViewSrg::m_viewProjectionMatrix, float4(IN.m_worldPos, 1.0));
|
||||
|
||||
// Reprojected last frame's clip position, for skinned mesh it also implies last key frame
|
||||
float4 clipPosPrev = mul(ViewSrg::m_viewProjectionPrevMatrix, float4(IN.m_worldPosPrev, 1.0));
|
||||
|
||||
float2 motion = (clipPos.xy / clipPos.w - clipPosPrev.xy / clipPosPrev.w) * 0.5;
|
||||
|
||||
OUT.m_motion = motion;
|
||||
|
||||
// Flip y to line up with uv coordinates
|
||||
OUT.m_motion.y = -OUT.m_motion.y;
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/Skin/SkinObjectSrg.azsli>
|
||||
#include <MeshMotionVectorCommon.azsli>
|
||||
|
||||
// Use the mesh motion vector with the skin object srg
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"Source" : "MeshMotionVectorSkin",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
|
||||
},
|
||||
|
||||
"DrawList" : "motion",
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "MainVS",
|
||||
"type": "Vertex"
|
||||
},
|
||||
{
|
||||
"name": "MainPS",
|
||||
"type": "Fragment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -6,27 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include <viewsrg.srgi>
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <ShadowmapCommon.azsli>
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
};
|
||||
|
||||
struct VertexOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
};
|
||||
|
||||
VertexOutput MainVS(VertexInput input)
|
||||
{
|
||||
const float4x4 worldMatrix = ObjectSrg::GetWorldMatrix();
|
||||
VertexOutput output;
|
||||
|
||||
const float3 worldPosition = mul(worldMatrix, float4(input.m_position, 1.0)).xyz;
|
||||
output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0));
|
||||
|
||||
return output;
|
||||
}
|
||||
// Use the shadowmap shader with the default object srg
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <scenesrg.srgi>
|
||||
#include <viewsrg.srgi>
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
};
|
||||
|
||||
struct VertexOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
};
|
||||
|
||||
VertexOutput MainVS(VertexInput input)
|
||||
{
|
||||
const float4x4 worldMatrix = ObjectSrg::GetWorldMatrix();
|
||||
VertexOutput output;
|
||||
|
||||
const float3 worldPosition = mul(worldMatrix, float4(input.m_position, 1.0)).xyz;
|
||||
output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0));
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/Skin/SkinObjectSrg.azsli>
|
||||
#include <ShadowmapCommon.azsli>
|
||||
|
||||
// Use the shadowmap shader with the skin object srg
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"Source" : "ShadowmapSkin",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"Depth" : { "Enable" : true, "CompareFunc" : "LessEqual" }
|
||||
},
|
||||
|
||||
"DrawList" : "shadow",
|
||||
|
||||
"RasterState" :
|
||||
{
|
||||
"depthBias" : "10",
|
||||
"depthBiasSlopeScale" : "4"
|
||||
},
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "MainVS",
|
||||
"type": "Vertex"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
-1
@@ -10,6 +10,5 @@ ly_add_external_target(
|
||||
NAME renderdoc
|
||||
3RDPARTY_ROOT_DIRECTORY "${LY_RENDERDOC_PATH}"
|
||||
VERSION
|
||||
INCLUDE_DIRECTORIES .
|
||||
COMPILE_DEFINITIONS USE_RENDERDOC
|
||||
)
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
#
|
||||
#
|
||||
|
||||
set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/librenderdoc.so")
|
||||
set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/lib/librenderdoc.so")
|
||||
set(RENDERDOC_INCLUDE_DIRECTORIES "include")
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
#
|
||||
|
||||
set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/renderdoc.dll")
|
||||
set(RENDERDOC_INCLUDE_DIRECTORIES ".")
|
||||
|
||||
@@ -344,9 +344,9 @@ namespace Blast
|
||||
|
||||
void UpdateMassProperties(
|
||||
[[maybe_unused]] AzPhysics::MassComputeFlags flags,
|
||||
[[maybe_unused]] const AZ::Vector3* centerOfMassOffsetOverride,
|
||||
[[maybe_unused]] const AZ::Matrix3x3* inertiaTensorOverride,
|
||||
[[maybe_unused]] const float* massOverride) override
|
||||
[[maybe_unused]] const AZ::Vector3& centerOfMassOffsetOverride,
|
||||
[[maybe_unused]] const AZ::Matrix3x3& inertiaTensorOverride,
|
||||
[[maybe_unused]] const float massOverride) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace LmbrCentral
|
||||
return intersection;
|
||||
}
|
||||
|
||||
const bool intersection = AZ::Intersect::IntersectRayObb(src, dir, m_intersectionDataCache.m_obb, distance) > 0;
|
||||
const bool intersection = AZ::Intersect::IntersectRayObb(src, dir, m_intersectionDataCache.m_obb, distance);
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace LmbrCentral
|
||||
m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_diskShapeConfig);
|
||||
|
||||
return AZ::Intersect::IntersectRayDisk(
|
||||
src, dir, m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius, m_intersectionDataCache.m_normal, distance) > 0;
|
||||
src, dir, m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius, m_intersectionDataCache.m_normal, distance);
|
||||
}
|
||||
|
||||
void DiskShape::DiskIntersectionDataCache::UpdateIntersectionParamsImpl(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
#include <AzFramework/Physics/Utils.h>
|
||||
#include <AzFramework/Physics/Configuration/RigidBodyConfiguration.h>
|
||||
#include <PhysX/NativeTypeIdentifiers.h>
|
||||
@@ -23,6 +24,28 @@
|
||||
|
||||
namespace PhysX
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const AZ::Vector3 DefaultCenterOfMass = AZ::Vector3::CreateZero();
|
||||
const float DefaultMass = 1.0f;
|
||||
const AZ::Matrix3x3 DefaultInertiaTensor = AZ::Matrix3x3::CreateIdentity();
|
||||
|
||||
bool IsSimulationShape(const physx::PxShape& pxShape)
|
||||
{
|
||||
return (pxShape.getFlags() & physx::PxShapeFlag::eSIMULATION_SHAPE);
|
||||
}
|
||||
|
||||
bool CanShapeComputeMassProperties(const physx::PxShape& pxShape)
|
||||
{
|
||||
// Note: List based on computeMassAndInertia function in ExtRigidBodyExt.cpp file in PhysX.
|
||||
const physx::PxGeometryType::Enum geometryType = pxShape.getGeometryType();
|
||||
return geometryType == physx::PxGeometryType::eSPHERE
|
||||
|| geometryType == physx::PxGeometryType::eBOX
|
||||
|| geometryType == physx::PxGeometryType::eCAPSULE
|
||||
|| geometryType == physx::PxGeometryType::eCONVEXMESH;
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
@@ -152,104 +175,120 @@ namespace PhysX
|
||||
m_shapes.erase(found);
|
||||
}
|
||||
|
||||
void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3* centerOfMassOffsetOverride, const AZ::Matrix3x3* inertiaTensorOverride, const float* massOverride)
|
||||
void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3& centerOfMassOffsetOverride, const AZ::Matrix3x3& inertiaTensorOverride, const float massOverride)
|
||||
{
|
||||
// Input validation
|
||||
bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM);
|
||||
AZ_Assert(computeCenterOfMass || centerOfMassOffsetOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_COM is not set but COM offset is not specified");
|
||||
computeCenterOfMass = computeCenterOfMass || !centerOfMassOffsetOverride;
|
||||
const bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM);
|
||||
const bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA);
|
||||
const bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS);
|
||||
const bool needsCompute = computeCenterOfMass || computeInertiaTensor || computeMass;
|
||||
const bool includeAllShapesInMassCalculation = AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES);
|
||||
|
||||
bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA);
|
||||
AZ_Assert(computeInertiaTensor || inertiaTensorOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_INERTIA is not set but inertia tensor is not specified");
|
||||
computeInertiaTensor = computeInertiaTensor || !inertiaTensorOverride;
|
||||
|
||||
bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS);
|
||||
AZ_Assert(computeMass || massOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_MASS is not set but mass is not specified");
|
||||
computeMass = computeMass || !massOverride;
|
||||
|
||||
AZ::u32 shapesCount = GetShapeCount();
|
||||
|
||||
// Basic cases when we don't need to compute anything
|
||||
if (shapesCount == 0 || flags == AzPhysics::MassComputeFlags::NONE)
|
||||
// Basic case where all properties are set directly.
|
||||
if (!needsCompute)
|
||||
{
|
||||
if (massOverride)
|
||||
{
|
||||
SetMass(*massOverride);
|
||||
}
|
||||
|
||||
if (inertiaTensorOverride)
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
}
|
||||
|
||||
if (centerOfMassOffsetOverride)
|
||||
{
|
||||
SetCenterOfMassOffset(*centerOfMassOffsetOverride);
|
||||
}
|
||||
SetCenterOfMassOffset(centerOfMassOffsetOverride);
|
||||
SetMass(massOverride);
|
||||
SetInertia(inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup center of mass offset pointer for PxRigidBodyExt::updateMassAndInertia function
|
||||
AZStd::optional<physx::PxVec3> optionalComOverride;
|
||||
if (!computeCenterOfMass && centerOfMassOffsetOverride)
|
||||
// If there are no shapes then set the properties directly without computing anything.
|
||||
if (m_shapes.empty())
|
||||
{
|
||||
optionalComOverride = PxMathConvert(*centerOfMassOffsetOverride);
|
||||
}
|
||||
|
||||
const physx::PxVec3* massLocalPose = optionalComOverride.has_value() ? &optionalComOverride.value() : nullptr;
|
||||
|
||||
bool includeAllShapesInMassCalculation =
|
||||
AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES);
|
||||
|
||||
// Handle the case when we don't compute mass
|
||||
if (!computeMass)
|
||||
{
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, *massOverride, massLocalPose,
|
||||
includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
if (!computeInertiaTensor)
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
}
|
||||
|
||||
SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride);
|
||||
SetMass(computeMass ? DefaultMass : massOverride);
|
||||
SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the cases when mass should be computed from density
|
||||
if (shapesCount == 1)
|
||||
auto cannotComputeMassProperties = [this, includeAllShapesInMassCalculation]
|
||||
{
|
||||
AZStd::shared_ptr<Physics::Shape> shape = GetShape(0);
|
||||
float density = shape->GetMaterial()->GetDensity();
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
return AZStd::any_of(m_shapes.cbegin(), m_shapes.cend(),
|
||||
[includeAllShapesInMassCalculation](const AZStd::shared_ptr<PhysX::Shape>& shape)
|
||||
{
|
||||
const physx::PxShape& pxShape = *shape->GetPxShape();
|
||||
const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape);
|
||||
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, density, massLocalPose,
|
||||
includeAllShapesInMassCalculation);
|
||||
return includeShape && !CanShapeComputeMassProperties(pxShape);
|
||||
});
|
||||
};
|
||||
|
||||
// If contains shapes that cannot compute mass properties (triangle mesh,
|
||||
// plane or heightfield) then default values will be used.
|
||||
if (cannotComputeMassProperties())
|
||||
{
|
||||
AZ_Warning("RigidBody", !computeCenterOfMass,
|
||||
"Rigid body '%s' cannot compute COM because it contains triangle mesh, plane or heightfield shapes, it will default to %s.",
|
||||
GetName().c_str(), AZ::ToString(DefaultCenterOfMass).c_str());
|
||||
AZ_Warning("RigidBody", !computeMass,
|
||||
"Rigid body '%s' cannot compute Mass because it contains triangle mesh, plane or heightfield shapes, it will default to %0.1f.",
|
||||
GetName().c_str(), DefaultMass);
|
||||
AZ_Warning("RigidBody", !computeInertiaTensor,
|
||||
"Rigid body '%s' cannot compute Inertia because it contains triangle mesh, plane or heightfield shapes, it will default to %s.",
|
||||
GetName().c_str(), AZ::ToString(DefaultInertiaTensor.RetrieveScale()).c_str());
|
||||
|
||||
SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride);
|
||||
SetMass(computeMass ? DefaultMass : massOverride);
|
||||
SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Center of mass needs to be considered first since
|
||||
// it's needed when computing mass and inertia.
|
||||
if (computeCenterOfMass)
|
||||
{
|
||||
// Compute Center of Mass
|
||||
UpdateCenterOfMass(includeAllShapesInMassCalculation);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::vector<float> densities(shapesCount);
|
||||
for (AZ::u32 i = 0; i < shapesCount; ++i)
|
||||
SetCenterOfMassOffset(centerOfMassOffsetOverride);
|
||||
}
|
||||
const physx::PxVec3 pxCenterOfMass = PxMathConvert(GetCenterOfMassLocal());
|
||||
|
||||
if (computeMass)
|
||||
{
|
||||
// Gather material densities from all shapes,
|
||||
// mass computation is based on them.
|
||||
AZStd::vector<float> densities;
|
||||
densities.reserve(m_shapes.size());
|
||||
for (const auto& shape : m_shapes)
|
||||
{
|
||||
densities[i] = GetShape(i)->GetMaterial()->GetDensity();
|
||||
densities.emplace_back(shape->GetMaterial()->GetDensity());
|
||||
}
|
||||
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, densities.data(),
|
||||
shapesCount, massLocalPose, includeAllShapesInMassCalculation);
|
||||
}
|
||||
// Compute Mass + Inertia
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor,
|
||||
densities.data(), static_cast<AZ::u32>(densities.size()),
|
||||
&pxCenterOfMass, includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
// Set the overrides if provided.
|
||||
// Note: We don't set the center of mass here because it was already provided
|
||||
// to PxRigidBodyExt::updateMassAndInertia above
|
||||
if (!computeInertiaTensor)
|
||||
// There is no physx function to only compute the mass without
|
||||
// computing the inertia. So now that both have been computed
|
||||
// we can override the inertia if it's suppose to use a
|
||||
// specific value set by the user.
|
||||
if (!computeInertiaTensor)
|
||||
{
|
||||
SetInertia(inertiaTensorOverride);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
if (computeInertiaTensor)
|
||||
{
|
||||
// Set Mass + Compute Inertia
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, massOverride,
|
||||
&pxCenterOfMass, includeAllShapesInMassCalculation);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMass(massOverride);
|
||||
SetInertia(inertiaTensorOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,52 +383,49 @@ namespace PhysX
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::UpdateComputedCenterOfMass()
|
||||
void RigidBody::UpdateCenterOfMass(bool includeAllShapesInMassCalculation)
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
if (m_shapes.empty())
|
||||
{
|
||||
physx::PxU32 shapeCount = 0;
|
||||
SetCenterOfMassOffset(DefaultCenterOfMass);
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<const physx::PxShape*> pxShapes;
|
||||
pxShapes.reserve(m_shapes.size());
|
||||
{
|
||||
// Filter shapes in the same way that updateMassAndInertia function does.
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
for (const auto& shape : m_shapes)
|
||||
{
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
shapeCount = m_pxRigidActor->getNbShapes();
|
||||
}
|
||||
if (shapeCount > 0)
|
||||
{
|
||||
AZStd::vector<physx::PxShape*> shapes;
|
||||
shapes.resize(shapeCount);
|
||||
const physx::PxShape& pxShape = *shape->GetPxShape();
|
||||
const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape);
|
||||
|
||||
if (includeShape && CanShapeComputeMassProperties(pxShape))
|
||||
{
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->getShapes(&shapes[0], shapeCount);
|
||||
pxShapes.emplace_back(&pxShape);
|
||||
}
|
||||
|
||||
shapes.erase(AZStd::remove_if(shapes.begin()
|
||||
, shapes.end()
|
||||
, [](const physx::PxShape* shape)
|
||||
{
|
||||
return shape->getFlags() & physx::PxShapeFlag::eTRIGGER_SHAPE;
|
||||
})
|
||||
, shapes.end());
|
||||
shapeCount = static_cast<physx::PxU32>(shapes.size());
|
||||
|
||||
if (shapeCount == 0)
|
||||
{
|
||||
SetZeroCenterOfMass();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto properties = physx::PxRigidBodyExt::computeMassPropertiesFromShapes(&shapes[0], shapeCount);
|
||||
const physx::PxTransform computedCenterOfMass(properties.centerOfMass);
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->setCMassLocalPose(computedCenterOfMass);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetZeroCenterOfMass();
|
||||
}
|
||||
}
|
||||
|
||||
if (pxShapes.empty())
|
||||
{
|
||||
SetCenterOfMassOffset(DefaultCenterOfMass);
|
||||
return;
|
||||
}
|
||||
|
||||
const physx::PxMassProperties pxMassProperties = [this, &pxShapes]
|
||||
{
|
||||
// Note: PhysX computeMassPropertiesFromShapes function does not use densities
|
||||
// to compute the shape's masses, which are needed to calculate the center of mass.
|
||||
// This differs from updateMassAndInertia function, which uses material density values.
|
||||
// So the masses used during center of mass calculation do not match the masses
|
||||
// used during mass/inertia calculation. This is an inconsistency in PhysX.
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
return physx::PxRigidBodyExt::computeMassPropertiesFromShapes(pxShapes.data(), static_cast<physx::PxU32>(pxShapes.size()));
|
||||
}();
|
||||
|
||||
SetCenterOfMassOffset(PxMathConvert(pxMassProperties.centerOfMass));
|
||||
}
|
||||
|
||||
void RigidBody::SetInertia(const AZ::Matrix3x3& inertia)
|
||||
@@ -401,16 +437,6 @@ namespace PhysX
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::ComputeInertia()
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
auto localPose = m_pxRigidActor->getCMassLocalPose().p;
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, m_pxRigidActor->getMass(), &localPose);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Vector3 RigidBody::GetLinearVelocity() const
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
@@ -783,13 +809,4 @@ namespace PhysX
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void RigidBody::SetZeroCenterOfMass()
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->setCMassLocalPose(physx::PxTransform(PxMathConvert(AZ::Vector3::CreateZero())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,17 +109,15 @@ namespace PhysX
|
||||
void RemoveShape(AZStd::shared_ptr<Physics::Shape> shape) override;
|
||||
|
||||
void UpdateMassProperties(AzPhysics::MassComputeFlags flags = AzPhysics::MassComputeFlags::DEFAULT,
|
||||
const AZ::Vector3* centerOfMassOffsetOverride = nullptr,
|
||||
const AZ::Matrix3x3* inertiaTensorOverride = nullptr,
|
||||
const float* massOverride = nullptr) override;
|
||||
const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(),
|
||||
const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(),
|
||||
const float massOverride = 1.0f) override;
|
||||
|
||||
private:
|
||||
void CreatePhysXActor(const AzPhysics::RigidBodyConfiguration& configuration);
|
||||
|
||||
void UpdateComputedCenterOfMass();
|
||||
void ComputeInertia();
|
||||
void UpdateCenterOfMass(bool includeAllShapesInMassCalculation);
|
||||
void SetInertia(const AZ::Matrix3x3& inertia);
|
||||
void SetZeroCenterOfMass();
|
||||
|
||||
AZStd::shared_ptr<physx::PxRigidDynamic> m_pxRigidActor;
|
||||
AZStd::vector<AZStd::shared_ptr<PhysX::Shape>> m_shapes;
|
||||
|
||||
@@ -198,8 +198,8 @@ namespace PhysX
|
||||
AZ_Warning("PhysXScene", shapeAdded, "No Collider or Shape information found when creating Rigid body [%s]", configuration->m_debugName.c_str());
|
||||
}
|
||||
const AzPhysics::MassComputeFlags& flags = configuration->GetMassComputeFlags();
|
||||
newBody->UpdateMassProperties(flags, &configuration->m_centerOfMassOffset,
|
||||
&configuration->m_inertiaTensor, &configuration->m_mass);
|
||||
newBody->UpdateMassProperties(flags, configuration->m_centerOfMassOffset,
|
||||
configuration->m_inertiaTensor, configuration->m_mass);
|
||||
|
||||
crc = AZ::Crc32(newBody, sizeof(*newBody));
|
||||
return newBody;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/Physics/SystemBus.h>
|
||||
#include <AzFramework/Physics/Collision/CollisionGroups.h>
|
||||
@@ -1283,11 +1285,13 @@ namespace PhysX
|
||||
EXPECT_TRUE(AZ::IsClose(expectedMass, mass, 0.001f));
|
||||
}
|
||||
|
||||
// Valid material density values: [0.01f, 1e5f]
|
||||
INSTANTIATE_TEST_CASE_P(PhysX, MultiShapesDensityTestFixture,
|
||||
::testing::Values(
|
||||
AZStd::make_pair(std::numeric_limits<float>::min(), std::numeric_limits<float>::max()),
|
||||
AZStd::make_pair(-std::numeric_limits<float>::max(), 0.0f),
|
||||
AZStd::make_pair(1.0f, 1e9f)
|
||||
AZStd::make_pair(0.01f, 0.01f),
|
||||
AZStd::make_pair(1e5f, 1e5f),
|
||||
AZStd::make_pair(0.01f, 1e5f),
|
||||
AZStd::make_pair(2364.0f, 10.0f)
|
||||
));
|
||||
|
||||
// Fixture for testing extreme density values
|
||||
@@ -1311,6 +1315,7 @@ namespace PhysX
|
||||
&& resultingDensity <= Physics::MaterialConfiguration::MaxDensityLimit);
|
||||
}
|
||||
|
||||
// Valid material density values: [0.01f, 1e5f]
|
||||
INSTANTIATE_TEST_CASE_P(PhysX, DensityBoundariesTestFixture,
|
||||
::testing::Values(
|
||||
std::numeric_limits<float>::min(),
|
||||
@@ -1318,7 +1323,9 @@ namespace PhysX
|
||||
-std::numeric_limits<float>::max(),
|
||||
0.0f,
|
||||
1.0f,
|
||||
1e9f
|
||||
1e9f,
|
||||
0.01f,
|
||||
1e5f
|
||||
));
|
||||
|
||||
enum class SimulatedShapesMode
|
||||
@@ -1329,7 +1336,7 @@ namespace PhysX
|
||||
};
|
||||
|
||||
class MassComputeFixture
|
||||
: public ::testing::TestWithParam<::testing::tuple<SimulatedShapesMode, AzPhysics::MassComputeFlags, bool>>
|
||||
: public ::testing::TestWithParam<::testing::tuple<Physics::ShapeType, SimulatedShapesMode, AzPhysics::MassComputeFlags, bool, bool>>
|
||||
{
|
||||
public:
|
||||
void SetUp() override final
|
||||
@@ -1349,6 +1356,8 @@ namespace PhysX
|
||||
AzPhysics::SimulatedBodyHandle simBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &m_rigidBodyConfig);
|
||||
m_rigidBody = azdynamic_cast<AzPhysics::RigidBody*>(sceneInterface->GetSimulatedBodyFromHandle(m_testSceneHandle, simBodyHandle));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(m_rigidBody != nullptr);
|
||||
}
|
||||
|
||||
void TearDown() override final
|
||||
@@ -1363,130 +1372,242 @@ namespace PhysX
|
||||
m_rigidBody = nullptr;
|
||||
}
|
||||
|
||||
SimulatedShapesMode GetShapesMode() const
|
||||
Physics::ShapeType GetShapeType() const
|
||||
{
|
||||
return ::testing::get<0>(GetParam());
|
||||
}
|
||||
|
||||
AzPhysics::MassComputeFlags GetMassComputeFlags() const
|
||||
SimulatedShapesMode GetShapesMode() const
|
||||
{
|
||||
return ::testing::get<1>(GetParam());
|
||||
}
|
||||
|
||||
AzPhysics::MassComputeFlags GetMassComputeFlags() const
|
||||
{
|
||||
const AzPhysics::MassComputeFlags massComputeFlags = ::testing::get<2>(GetParam());
|
||||
if (IncludeAllShapes())
|
||||
{
|
||||
return massComputeFlags | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return massComputeFlags;
|
||||
}
|
||||
}
|
||||
|
||||
bool IncludeAllShapes() const
|
||||
{
|
||||
return ::testing::get<3>(GetParam());
|
||||
}
|
||||
|
||||
bool IsMultiShapeTest() const
|
||||
{
|
||||
return ::testing::get<2>(GetParam());
|
||||
return ::testing::get<4>(GetParam());
|
||||
}
|
||||
|
||||
bool IsMassExpectedToChange() const
|
||||
{
|
||||
return m_rigidBodyConfig.m_computeMass &&
|
||||
(!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
(GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
bool IsComExpectedToChange() const
|
||||
{
|
||||
return m_rigidBodyConfig.m_computeCenterOfMass &&
|
||||
(!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
(GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
bool IsInertiaExpectedToChange() const
|
||||
{
|
||||
return m_rigidBodyConfig.m_computeInertiaTensor &&
|
||||
(!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
(GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<Physics::Shape> CreateShape(const Physics::ColliderConfiguration& colliderConfiguration, Physics::ShapeType shapeType)
|
||||
{
|
||||
AZStd::shared_ptr<Physics::Shape> shape;
|
||||
Physics::System* physics = AZ::Interface<Physics::System>::Get();
|
||||
switch (shapeType)
|
||||
{
|
||||
case Physics::ShapeType::Sphere:
|
||||
shape = physics->CreateShape(colliderConfiguration, Physics::SphereShapeConfiguration());
|
||||
break;
|
||||
case Physics::ShapeType::Box:
|
||||
shape = physics->CreateShape(colliderConfiguration, Physics::BoxShapeConfiguration());
|
||||
break;
|
||||
case Physics::ShapeType::Capsule:
|
||||
shape = physics->CreateShape(colliderConfiguration, Physics::CapsuleShapeConfiguration());
|
||||
break;
|
||||
}
|
||||
return shape;
|
||||
};
|
||||
|
||||
AzPhysics::RigidBodyConfiguration m_rigidBodyConfig;
|
||||
AzPhysics::RigidBody* m_rigidBody;
|
||||
AzPhysics::RigidBody* m_rigidBody = nullptr;
|
||||
AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle;
|
||||
};
|
||||
|
||||
TEST_P(MassComputeFixture, RigidBody_ComputeMassFlagsCombinationsTwoShapes_MassPropertiesCalculatedAccordingly)
|
||||
{
|
||||
SimulatedShapesMode shapeMode = GetShapesMode();
|
||||
AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags();
|
||||
bool multiShapeTest = IsMultiShapeTest();
|
||||
Physics::System* physics = AZ::Interface<Physics::System>::Get();
|
||||
const Physics::ShapeType shapeType = GetShapeType();
|
||||
const SimulatedShapesMode shapeMode = GetShapesMode();
|
||||
const AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags();
|
||||
const bool multiShapeTest = IsMultiShapeTest();
|
||||
|
||||
// Save initial values
|
||||
AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld();
|
||||
AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld();
|
||||
float massBefore = m_rigidBody->GetMass();
|
||||
const AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld();
|
||||
const AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld();
|
||||
const float massBefore = m_rigidBody->GetMass();
|
||||
|
||||
// Box shape will be simulated for ALL and MIXED shape modes
|
||||
Physics::ColliderConfiguration boxColliderConfig;
|
||||
boxColliderConfig.m_isSimulated =
|
||||
// Shape will be simulated for ALL and MIXED shape modes
|
||||
Physics::ColliderConfiguration colliderConfig;
|
||||
colliderConfig.m_isSimulated =
|
||||
(shapeMode == SimulatedShapesMode::ALL || shapeMode == SimulatedShapesMode::MIXED);
|
||||
boxColliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f);
|
||||
colliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
AZStd::shared_ptr<Physics::Shape> boxShape =
|
||||
physics->CreateShape(boxColliderConfig, Physics::BoxShapeConfiguration());
|
||||
m_rigidBody->AddShape(boxShape);
|
||||
AZStd::shared_ptr<Physics::Shape> shape = CreateShape(colliderConfig, shapeType);
|
||||
m_rigidBody->AddShape(shape);
|
||||
|
||||
if (multiShapeTest)
|
||||
{
|
||||
// Sphere shape will be simulated only for the ALL shape mode
|
||||
Physics::ColliderConfiguration sphereColliderConfig;
|
||||
sphereColliderConfig.m_isSimulated = (shapeMode == SimulatedShapesMode::ALL);
|
||||
sphereColliderConfig.m_position = AZ::Vector3(-1.0f, 0.0f, 0.0f);
|
||||
AZStd::shared_ptr<Physics::Shape> sphereShape =
|
||||
physics->CreateShape(sphereColliderConfig, Physics::SphereShapeConfiguration());
|
||||
sphereColliderConfig.m_position = AZ::Vector3(-2.0f, 0.0f, 0.0f);
|
||||
AZStd::shared_ptr<Physics::Shape> sphereShape = CreateShape(sphereColliderConfig, Physics::ShapeType::Sphere);
|
||||
m_rigidBody->AddShape(sphereShape);
|
||||
}
|
||||
|
||||
// Verify swapping materials results in changes in the mass.
|
||||
m_rigidBody->UpdateMassProperties(massComputeFlags, &m_rigidBodyConfig.m_centerOfMassOffset,
|
||||
&m_rigidBodyConfig.m_inertiaTensor, &m_rigidBodyConfig.m_mass);
|
||||
m_rigidBody->UpdateMassProperties(massComputeFlags, m_rigidBodyConfig.m_centerOfMassOffset,
|
||||
m_rigidBodyConfig.m_inertiaTensor, m_rigidBodyConfig.m_mass);
|
||||
|
||||
float massAfter = m_rigidBody->GetMass();
|
||||
AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld();
|
||||
AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld();
|
||||
const float massAfter = m_rigidBody->GetMass();
|
||||
const AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld();
|
||||
const AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld();
|
||||
|
||||
using ::testing::Not;
|
||||
using ::testing::FloatNear;
|
||||
using ::UnitTest::IsClose;
|
||||
if (IsMassExpectedToChange())
|
||||
{
|
||||
EXPECT_FALSE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON));
|
||||
EXPECT_THAT(massBefore, Not(FloatNear(massAfter, FLT_EPSILON)));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_TRUE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON));
|
||||
EXPECT_THAT(massBefore, FloatNear(massAfter, FLT_EPSILON));
|
||||
}
|
||||
|
||||
if (IsComExpectedToChange())
|
||||
{
|
||||
EXPECT_FALSE(comBefore.IsClose(comAfter));
|
||||
EXPECT_THAT(comBefore, Not(IsClose(comAfter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_TRUE(comBefore.IsClose(comAfter));
|
||||
EXPECT_THAT(comBefore, IsClose(comAfter));
|
||||
}
|
||||
|
||||
if (IsInertiaExpectedToChange())
|
||||
{
|
||||
EXPECT_FALSE(inertiaBefore.IsClose(inertiaAfter));
|
||||
EXPECT_THAT(inertiaBefore, Not(IsClose(inertiaAfter)));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_TRUE(inertiaBefore.IsClose(inertiaAfter));
|
||||
EXPECT_THAT(inertiaBefore, IsClose(inertiaAfter));
|
||||
}
|
||||
}
|
||||
|
||||
AzPhysics::MassComputeFlags possibleMassComputeFlags[] = {
|
||||
AzPhysics::MassComputeFlags::NONE, AzPhysics::MassComputeFlags::DEFAULT, AzPhysics::MassComputeFlags::COMPUTE_MASS,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA,
|
||||
AzPhysics::MassComputeFlags::DEFAULT | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA, AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES,
|
||||
static const AzPhysics::MassComputeFlags PossibleMassComputeFlags[] =
|
||||
{
|
||||
// No compute
|
||||
AzPhysics::MassComputeFlags::NONE,
|
||||
|
||||
// Compute Mass only
|
||||
AzPhysics::MassComputeFlags::COMPUTE_MASS,
|
||||
|
||||
// Compute Inertia only
|
||||
AzPhysics::MassComputeFlags::COMPUTE_INERTIA,
|
||||
|
||||
// Compute COM only
|
||||
AzPhysics::MassComputeFlags::COMPUTE_COM,
|
||||
|
||||
// Compute combinations of 2
|
||||
AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA,
|
||||
AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES
|
||||
|
||||
// Compute all
|
||||
AzPhysics::MassComputeFlags::DEFAULT, // COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PhysX, MassComputeFixture, ::testing::Combine(
|
||||
::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }),
|
||||
::testing::ValuesIn(possibleMassComputeFlags),
|
||||
::testing::Bool()));
|
||||
::testing::ValuesIn({ Physics::ShapeType::Sphere, Physics::ShapeType::Box, Physics::ShapeType::Capsule }), // Values for GetShapeType()
|
||||
::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }), // Values for GetShapesMode()
|
||||
::testing::ValuesIn(PossibleMassComputeFlags), // Values for GetMassComputeFlags()
|
||||
::testing::Bool(), // Values for IncludeAllShapes()
|
||||
::testing::Bool())); // Values for IsMultiShapeTest()
|
||||
|
||||
class MassPropertiesWithTriangleMesh
|
||||
: public ::testing::TestWithParam<AzPhysics::MassComputeFlags>
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get())
|
||||
{
|
||||
AzPhysics::SceneConfiguration sceneConfiguration = physicsSystem->GetDefaultSceneConfiguration();
|
||||
sceneConfiguration.m_sceneName = AzPhysics::DefaultPhysicsSceneName;
|
||||
m_testSceneHandle = physicsSystem->AddScene(sceneConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// Clean up the Test scene
|
||||
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get())
|
||||
{
|
||||
physicsSystem->RemoveScene(m_testSceneHandle);
|
||||
}
|
||||
m_testSceneHandle = AzPhysics::InvalidSceneHandle;
|
||||
}
|
||||
|
||||
AzPhysics::MassComputeFlags GetMassComputeFlags() const
|
||||
{
|
||||
return GetParam();
|
||||
}
|
||||
|
||||
AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle;
|
||||
};
|
||||
|
||||
TEST_P(MassPropertiesWithTriangleMesh, KinematicRigidBody_ComputeMassProperties_TriggersWarnings)
|
||||
{
|
||||
const AzPhysics::MassComputeFlags flags = GetMassComputeFlags();
|
||||
|
||||
const bool doesComputeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM);
|
||||
const bool doesComputeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS);
|
||||
const bool doesComputeInertia = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA);
|
||||
|
||||
UnitTest::ErrorHandler computeCenterOfMassWarningHandler(
|
||||
"cannot compute COM");
|
||||
UnitTest::ErrorHandler computeMassWarningHandler(
|
||||
"cannot compute Mass");
|
||||
UnitTest::ErrorHandler computeIneriaWarningHandler(
|
||||
"cannot compute Inertia");
|
||||
|
||||
AzPhysics::SimulatedBodyHandle rigidBodyhandle = TestUtils::AddKinematicTriangleMeshCubeToScene(m_testSceneHandle, 3.0f, flags);
|
||||
|
||||
EXPECT_TRUE(rigidBodyhandle != AzPhysics::InvalidSimulatedBodyHandle);
|
||||
EXPECT_EQ(computeCenterOfMassWarningHandler.GetExpectedWarningCount(), doesComputeCenterOfMass ? 1 : 0);
|
||||
EXPECT_EQ(computeMassWarningHandler.GetExpectedWarningCount(), doesComputeMass ? 1 : 0);
|
||||
EXPECT_EQ(computeIneriaWarningHandler.GetExpectedWarningCount(), doesComputeInertia ? 1 : 0);
|
||||
|
||||
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
|
||||
{
|
||||
sceneInterface->RemoveSimulatedBody(m_testSceneHandle, rigidBodyhandle);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PhysX, MassPropertiesWithTriangleMesh,
|
||||
::testing::ValuesIn(PossibleMassComputeFlags)); // Values for GetMassComputeFlags()
|
||||
} // namespace PhysX
|
||||
|
||||
|
||||
@@ -253,6 +253,36 @@ namespace PhysX
|
||||
return AzPhysics::InvalidSimulatedBodyHandle;
|
||||
}
|
||||
|
||||
AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags)
|
||||
{
|
||||
// Generate input data
|
||||
VertexIndexData cubeMeshData = GenerateCubeMeshData(halfExtent);
|
||||
AZStd::vector<AZ::u8> cookedData;
|
||||
bool cookingResult = false;
|
||||
Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory,
|
||||
cubeMeshData.first.data(), static_cast<AZ::u32>(cubeMeshData.first.size()),
|
||||
cubeMeshData.second.data(), static_cast<AZ::u32>(cubeMeshData.second.size()),
|
||||
cookedData);
|
||||
AZ_Assert(cookingResult, "Failed to cook the cube mesh.");
|
||||
|
||||
// Setup shape & collider configurations
|
||||
auto shapeConfig = AZStd::make_shared<Physics::CookedMeshShapeConfiguration>();
|
||||
shapeConfig->SetCookedMeshData(cookedData.data(), cookedData.size(),
|
||||
Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh);
|
||||
|
||||
AzPhysics::RigidBodyConfiguration rigidBodyConfiguration;
|
||||
rigidBodyConfiguration.m_kinematic = true;
|
||||
rigidBodyConfiguration.SetMassComputeFlags(massComputeFlags);
|
||||
rigidBodyConfiguration.m_colliderAndShapeData = AzPhysics::ShapeColliderPair(
|
||||
AZStd::make_shared<Physics::ColliderConfiguration>(), shapeConfig);
|
||||
|
||||
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
|
||||
{
|
||||
return sceneInterface->AddSimulatedBody(scene, &rigidBodyConfiguration);
|
||||
}
|
||||
return AzPhysics::InvalidSimulatedBodyHandle;
|
||||
}
|
||||
|
||||
void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag)
|
||||
{
|
||||
Physics::CollisionFilteringRequestBus::Event(entity->GetId(), &Physics::CollisionFilteringRequests::SetCollisionLayer, layerName, AZ::Crc32(colliderTag.c_str()));
|
||||
|
||||
@@ -89,6 +89,7 @@ namespace PhysX
|
||||
const AzPhysics::CollisionLayer& layer = AzPhysics::CollisionLayer::Default);
|
||||
|
||||
AzPhysics::SimulatedBodyHandle AddStaticTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent);
|
||||
AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags);
|
||||
|
||||
// Collision Filtering
|
||||
void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag = "");
|
||||
|
||||
@@ -567,13 +567,15 @@ namespace Terrain
|
||||
ShaderMacroMaterialData& shaderData = macroMaterialData.at(i);
|
||||
const AZ::Aabb& materialBounds = materialData.m_bounds;
|
||||
|
||||
// Use reverse coordinates (1 - y) for the y direction so that the lower left corner of the macro material images
|
||||
// map to the lower left corner in world space. This will match up with the height uv coordinate mapping.
|
||||
shaderData.m_uvMin = {
|
||||
(xPatch - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(),
|
||||
(yPatch - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent()
|
||||
1.0f - ((yPatch - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent())
|
||||
};
|
||||
shaderData.m_uvMax = {
|
||||
((xPatch + GridMeters) - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(),
|
||||
((yPatch + GridMeters) - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent()
|
||||
1.0f - (((yPatch + GridMeters) - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent())
|
||||
};
|
||||
shaderData.m_normalFactor = materialData.m_normalFactor;
|
||||
shaderData.m_flipNormalX = materialData.m_normalFlipX;
|
||||
|
||||
@@ -91,6 +91,11 @@ namespace WhiteBox
|
||||
bodyConfiguration.m_position = worldTransform.GetTranslation();
|
||||
bodyConfiguration.m_kinematic = true; // note: this field is ignored in the WhiteBoxBodyType::Static case
|
||||
bodyConfiguration.m_colliderAndShapeData = shape;
|
||||
// Since the shape used is a triangle mesh the COM, Mass and Inertia
|
||||
// cannot be computed. Disable them to use default values.
|
||||
bodyConfiguration.m_computeCenterOfMass = false;
|
||||
bodyConfiguration.m_computeMass = false;
|
||||
bodyConfiguration.m_computeInertiaTensor = false;
|
||||
m_simulatedBodyHandle = sceneInterface->AddSimulatedBody(defaultScene, &bodyConfiguration);
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user