Files
XCEngine/engine/third_party/physx/source/common/src/CmScaling.h

242 lines
7.7 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef CM_SCALING_H
#define CM_SCALING_H
#include "foundation/PxBounds3.h"
#include "foundation/PxMat33.h"
#include "foundation/PxMathUtils.h"
#include "foundation/PxMat34.h"
#include "foundation/PxSIMDHelpers.h"
#include "geometry/PxMeshScale.h"
#include "CmUtils.h"
namespace physx
{
namespace Cm
{
// PT: same as PxMeshScale::toMat33() but faster
PX_FORCE_INLINE PxMat33 toMat33(const PxMeshScale& meshScale)
{
const PxMat33Padded rot(meshScale.rotation);
PxMat33 trans = rot.getTranspose();
trans.column0 *= meshScale.scale[0];
trans.column1 *= meshScale.scale[1];
trans.column2 *= meshScale.scale[2];
return trans * rot;
}
// class that can perform scaling fast. Relatively large size, generated from PxMeshScale on demand.
// CS: I've removed most usages of this class, because most of the time only one-way transform is needed.
// If you only need a temporary FastVertex2ShapeScaling, setup your transform as PxMat34Legacy and use
// normal matrix multiplication or a transform() overload to convert points and bounds between spaces.
class FastVertex2ShapeScaling
{
public:
PX_INLINE FastVertex2ShapeScaling()
{
//no scaling by default:
vertex2ShapeSkew = PxMat33(PxIdentity);
shape2VertexSkew = PxMat33(PxIdentity);
mFlipNormal = false;
}
PX_INLINE explicit FastVertex2ShapeScaling(const PxMeshScale& scale)
{
init(scale);
}
PX_INLINE FastVertex2ShapeScaling(const PxVec3& scale, const PxQuat& rotation)
{
init(scale, rotation);
}
PX_INLINE void init(const PxMeshScale& scale)
{
init(scale.scale, scale.rotation);
}
PX_INLINE void setIdentity()
{
vertex2ShapeSkew = PxMat33(PxIdentity);
shape2VertexSkew = PxMat33(PxIdentity);
mFlipNormal = false;
}
PX_INLINE void init(const PxVec3& scale, const PxQuat& rotation)
{
// TODO: may want to optimize this for cases where we have uniform or axis aligned scaling!
// That would introduce branches and it's unclear to me whether that's faster than just doing the math.
// Lazy computation would be another option, at the cost of introducing even more branches.
const PxMat33Padded R(rotation);
vertex2ShapeSkew = R.getTranspose();
const PxMat33 diagonal = PxMat33::createDiagonal(scale);
vertex2ShapeSkew = vertex2ShapeSkew * diagonal;
vertex2ShapeSkew = vertex2ShapeSkew * R;
/*
The inverse, is, explicitly:
shape2VertexSkew.setTransposed(R);
shape2VertexSkew.multiplyDiagonal(PxVec3(1.0f/scale.x, 1.0f/scale.y, 1.0f/scale.z));
shape2VertexSkew *= R;
It may be competitive to compute the inverse -- though this has a branch in it:
*/
shape2VertexSkew = vertex2ShapeSkew.getInverse();
mFlipNormal = ((scale.x * scale.y * scale.z) < 0.0f);
}
PX_FORCE_INLINE void flipNormal(PxVec3& v1, PxVec3& v2) const
{
if (mFlipNormal)
{
PxVec3 tmp = v1; v1 = v2; v2 = tmp;
}
}
PX_FORCE_INLINE PxVec3 operator* (const PxVec3& src) const
{
return vertex2ShapeSkew * src;
}
PX_FORCE_INLINE PxVec3 operator% (const PxVec3& src) const
{
return shape2VertexSkew * src;
}
PX_FORCE_INLINE const PxMat33& getVertex2ShapeSkew() const
{
return vertex2ShapeSkew;
}
PX_FORCE_INLINE const PxMat33& getShape2VertexSkew() const
{
return shape2VertexSkew;
}
PX_INLINE PxMat34 getVertex2WorldSkew(const PxMat34& shape2world) const
{
const PxMat34 vertex2worldSkew = shape2world * getVertex2ShapeSkew();
//vertex2worldSkew = shape2world * [vertex2shapeSkew, 0]
//[aR at] * [bR bt] = [aR * bR aR * bt + at] NOTE: order of operations important so it works when this ?= left ?= right.
return vertex2worldSkew;
}
PX_INLINE PxMat34 getWorld2VertexSkew(const PxMat34& shape2world) const
{
//world2vertexSkew = shape2vertex * invPQ(shape2world)
//[aR 0] * [bR' -bR'*bt] = [aR * bR' -aR * bR' * bt + 0]
const PxMat33 rotate( shape2world[0], shape2world[1], shape2world[2] );
const PxMat33 M = getShape2VertexSkew() * rotate.getTranspose();
return PxMat34(M[0], M[1], M[2], -M * shape2world[3]);
}
//! Transforms a shape space OBB to a vertex space OBB. All 3 params are in and out.
void transformQueryBounds(PxVec3& center, PxVec3& extents, PxMat33& basis) const
{
basis.column0 = shape2VertexSkew * (basis.column0 * extents.x);
basis.column1 = shape2VertexSkew * (basis.column1 * extents.y);
basis.column2 = shape2VertexSkew * (basis.column2 * extents.z);
center = shape2VertexSkew * center;
extents = PxOptimizeBoundingBox(basis);
}
void transformPlaneToShapeSpace(const PxVec3& nIn, const PxReal dIn, PxVec3& nOut, PxReal& dOut) const
{
const PxVec3 tmp = shape2VertexSkew.transformTranspose(nIn);
const PxReal denom = 1.0f / tmp.magnitude();
nOut = tmp * denom;
dOut = dIn * denom;
}
PX_FORCE_INLINE bool flipsNormal() const { return mFlipNormal; }
private:
PxMat33 vertex2ShapeSkew;
PxMat33 shape2VertexSkew;
bool mFlipNormal;
};
PX_FORCE_INLINE void getScaledVertices(PxVec3* v, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, bool idtMeshScale, const Cm::FastVertex2ShapeScaling& scaling)
{
if(idtMeshScale)
{
v[0] = v0;
v[1] = v1;
v[2] = v2;
}
else
{
const PxI32 winding = scaling.flipsNormal() ? 1 : 0;
v[0] = scaling * v0;
v[1+winding] = scaling * v1;
v[2-winding] = scaling * v2;
}
}
} // namespace Cm
PX_INLINE PxMat34 operator*(const PxTransform& transform, const PxMeshScale& scale)
{
const PxMat33Padded tmp(transform.q);
return PxMat34(tmp * Cm::toMat33(scale), transform.p);
}
PX_INLINE PxMat34 operator*(const PxMeshScale& scale, const PxTransform& transform)
{
const PxMat33 scaleMat = Cm::toMat33(scale);
const PxMat33Padded t(transform.q);
const PxMat33 r = scaleMat * t;
const PxVec3 p = scaleMat * transform.p;
return PxMat34(r, p);
}
PX_INLINE PxMat34 operator*(const PxMat34& transform, const PxMeshScale& scale)
{
return PxMat34(transform.m * Cm::toMat33(scale), transform.p);
}
PX_INLINE PxMat34 operator*(const PxMeshScale& scale, const PxMat34& transform)
{
const PxMat33 scaleMat = Cm::toMat33(scale);
return PxMat34(scaleMat * transform.m, scaleMat * transform.p);
}
}
#endif