211 lines
7.2 KiB
C++
211 lines
7.2 KiB
C++
/**
|
|
* @file llphysicsshapebuilder.cpp
|
|
* @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "llphysicsshapebuilderutil.h"
|
|
|
|
/* static */
|
|
void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut )
|
|
{
|
|
const LLProfileParams& profile_params = volume_params.getProfileParams();
|
|
const LLPathParams& path_params = volume_params.getPathParams();
|
|
|
|
specOut.mScale = scale;
|
|
|
|
const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f;
|
|
|
|
// count the scale elements that are small
|
|
S32 min_size_counts = 0;
|
|
for (S32 i = 0; i < 3; ++i)
|
|
{
|
|
if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
|
{
|
|
++min_size_counts;
|
|
}
|
|
}
|
|
|
|
const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
|
|
( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
|
|
|
|
const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
|
|
( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
|
|
|
|
const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale )
|
|
&& ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
|
|
&& ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
|
|
&& ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() );
|
|
|
|
if (simple_params && profile_complete)
|
|
{
|
|
// Try to create an implicit shape or convexified
|
|
bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
|
|
&& ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale );
|
|
|
|
bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale )
|
|
&& ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale);
|
|
|
|
// Box
|
|
if(
|
|
( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE )
|
|
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
|
&& no_taper
|
|
&& no_twist
|
|
)
|
|
{
|
|
specOut.mType = PhysicsShapeSpecification::BOX;
|
|
if ( path_complete )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Side lengths
|
|
specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
|
specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
|
specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
|
|
|
specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Sphere
|
|
if( path_complete
|
|
&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF )
|
|
&& ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE )
|
|
&& ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
|
|
&& no_twist
|
|
)
|
|
{
|
|
if ( ( scale[VX] == scale[VZ] )
|
|
&& ( scale[VY] == scale[VZ] ) )
|
|
{
|
|
// perfect sphere
|
|
specOut.mType = PhysicsShapeSpecification::SPHERE;
|
|
specOut.mScale = scale;
|
|
return;
|
|
}
|
|
else if (min_size_counts > 1)
|
|
{
|
|
// small or narrow sphere -- we can boxify
|
|
for (S32 i=0; i<3; ++i)
|
|
{
|
|
if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
|
{
|
|
// reduce each small dimension size to split the approximation errors
|
|
specOut.mScale[i] *= 0.75f;
|
|
}
|
|
}
|
|
specOut.mType = PhysicsShapeSpecification::BOX;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Cylinder
|
|
if( (scale[VX] == scale[VY])
|
|
&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE )
|
|
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
|
&& ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale )
|
|
&& ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) )
|
|
&& no_taper
|
|
)
|
|
{
|
|
if (min_size_counts > 1)
|
|
{
|
|
// small or narrow sphere -- we can boxify
|
|
for (S32 i=0; i<3; ++i)
|
|
{
|
|
if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
|
{
|
|
// reduce each small dimension size to split the approximation errors
|
|
specOut.mScale[i] *= 0.75f;
|
|
}
|
|
}
|
|
|
|
specOut.mType = PhysicsShapeSpecification::BOX;
|
|
}
|
|
else
|
|
{
|
|
specOut.mType = PhysicsShapeSpecification::CYLINDER;
|
|
F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ];
|
|
|
|
specOut.mScale[VY] = specOut.mScale[VX];
|
|
specOut.mScale[VZ] = length;
|
|
// The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1.
|
|
specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] );
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( (min_size_counts == 3 )
|
|
// Possible dead code here--who wants to take it out?
|
|
|| (path_complete
|
|
&& profile_complete
|
|
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
|
&& (min_size_counts > 1 ) )
|
|
)
|
|
{
|
|
// it isn't simple but
|
|
// we might be able to convexify this shape if the path and profile are complete
|
|
// or the path is linear and both path and profile are complete --> we can boxify it
|
|
specOut.mType = PhysicsShapeSpecification::BOX;
|
|
specOut.mScale = scale;
|
|
return;
|
|
}
|
|
|
|
// Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE
|
|
if (min_size_counts == 1 // One dimension is small
|
|
&& avgScale > 3.f) // ... but others are fairly large
|
|
{
|
|
for (S32 i = 0; i < 3; ++i)
|
|
{
|
|
specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE );
|
|
}
|
|
}
|
|
|
|
if ( volume_params.shouldForceConvex() )
|
|
{
|
|
specOut.mType = PhysicsShapeSpecification::USER_CONVEX;
|
|
}
|
|
// Make a simpler convex shape if we can.
|
|
else if (volume_params.isConvex() // is convex
|
|
|| min_size_counts > 1 ) // two or more small dimensions
|
|
{
|
|
specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
|
|
}
|
|
else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy)
|
|
{
|
|
specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT;
|
|
}
|
|
else // Resort to mesh
|
|
{
|
|
specOut.mType = PhysicsShapeSpecification::PRIM_MESH;
|
|
}
|
|
}
|