mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 19:55:07 +02:00
Merge pull request #11048 from 1P-Cusack/21389
WL21389 PR1: Representation of collision shapes need updating (details below).
This commit is contained in:
commit
e465186511
7 changed files with 163 additions and 10 deletions
|
@ -82,6 +82,80 @@ bool RenderableShapeEntityItem::isTransparent() {
|
|||
}
|
||||
}
|
||||
|
||||
void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
|
||||
// This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc)
|
||||
// is set.
|
||||
|
||||
const glm::vec3 entityDimensions = getDimensions();
|
||||
|
||||
switch (_shape){
|
||||
case entity::Shape::Quad:
|
||||
case entity::Shape::Cube: {
|
||||
_collisionShapeType = SHAPE_TYPE_BOX;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Sphere: {
|
||||
|
||||
float diameter = entityDimensions.x;
|
||||
const float MIN_DIAMETER = 0.001f;
|
||||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (diameter > MIN_DIAMETER
|
||||
&& fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
|
||||
_collisionShapeType = SHAPE_TYPE_SPHERE;
|
||||
}
|
||||
else {
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Cylinder: {
|
||||
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
|
||||
// TODO WL21389: determine if rotation is axis-aligned
|
||||
//const Transform::Quat & rot = _transform.getRotation();
|
||||
|
||||
// TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
|
||||
// hull ( or dimensions, need circular cross section)
|
||||
// Should allow for minor variance along axes?
|
||||
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Triangle:
|
||||
case entity::Shape::Hexagon:
|
||||
case entity::Shape::Octagon:
|
||||
case entity::Shape::Circle:
|
||||
case entity::Shape::Tetrahedron:
|
||||
case entity::Shape::Octahedron:
|
||||
case entity::Shape::Dodecahedron:
|
||||
case entity::Shape::Icosahedron:
|
||||
case entity::Shape::Cone: {
|
||||
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later)
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
case entity::Shape::Torus:
|
||||
{
|
||||
// Not in GeometryCache::buildShapes, unsupported.
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
EntityItem::computeShapeInfo(info);
|
||||
}
|
||||
|
||||
// This value specifes how the shape should be treated by physics calculations.
|
||||
ShapeType RenderableShapeEntityItem::getShapeType() const {
|
||||
return _collisionShapeType;
|
||||
}
|
||||
|
||||
void RenderableShapeEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||
//Q_ASSERT(getType() == EntityTypes::Shape);
|
||||
|
|
|
@ -28,9 +28,18 @@ public:
|
|||
|
||||
bool isTransparent() override;
|
||||
|
||||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
ShapeType getShapeType() const override;
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr<Procedural> _procedural { nullptr };
|
||||
|
||||
//! This is SHAPE_TYPE_ELLIPSOID rather than SHAPE_TYPE_NONE to maintain
|
||||
//! prior functionality where new or unsupported shapes are treated as
|
||||
//! ellipsoids.
|
||||
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
};
|
||||
|
||||
|
|
|
@ -160,12 +160,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
|
||||
}
|
||||
|
||||
// This value specifes how the shape should be treated by physics calculations.
|
||||
// For now, all polys will act as spheres
|
||||
ShapeType ShapeEntityItem::getShapeType() const {
|
||||
return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
|
||||
void ShapeEntityItem::setColor(const rgbColor& value) {
|
||||
memcpy(_color, value, sizeof(rgbColor));
|
||||
}
|
||||
|
@ -223,10 +217,12 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
void ShapeEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " shape:" << stringFromShape(_shape);
|
||||
qCDebug(entities) << " name:" << _name;
|
||||
qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )";
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,6 @@ public:
|
|||
QColor getQColor() const;
|
||||
void setColor(const QColor& value);
|
||||
|
||||
ShapeType getShapeType() const override;
|
||||
bool shouldBePhysical() const override { return !isDead(); }
|
||||
|
||||
bool supportsDetailedRayIntersection() const override;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "BulletUtil.h"
|
||||
|
||||
// These are the same normalized directions used by the btShapeHull class.
|
||||
// 12 points for the face centers of a duodecohedron plus another 30 points
|
||||
// 12 points for the face centers of a dodecahedron plus another 30 points
|
||||
// for the midpoints the edges, for a total of 42.
|
||||
const uint32_t NUM_UNIT_SPHERE_DIRECTIONS = 42;
|
||||
static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
|
||||
|
@ -288,6 +288,38 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_X: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.y;
|
||||
float height = 2.0f * halfExtents.x;
|
||||
shape = new btCapsuleShapeX(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_Z: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.x;
|
||||
float height = 2.0f * halfExtents.z;
|
||||
shape = new btCapsuleShapeZ(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER_X: {
|
||||
const glm::vec3 halfExtents = info.getHalfExtents();
|
||||
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
shape = new btCylinderShapeX(btHalfExtents);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER_Z: {
|
||||
const glm::vec3 halfExtents = info.getHalfExtents();
|
||||
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
shape = new btCylinderShapeZ(btHalfExtents);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER_Y: {
|
||||
const glm::vec3 halfExtents = info.getHalfExtents();
|
||||
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
shape = new btCylinderShape(btHalfExtents);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_HULL: {
|
||||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
|
|
|
@ -29,6 +29,7 @@ void ShapeInfo::clear() {
|
|||
}
|
||||
|
||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
|
||||
//TODO WL21389: Does this need additional cases and handling added?
|
||||
_url = "";
|
||||
_type = type;
|
||||
setHalfExtents(halfExtents);
|
||||
|
@ -55,6 +56,9 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
//TODO WL21389: Should this pointlist clearance added in case
|
||||
// this is a re-purposed instance?
|
||||
// See https://github.com/highfidelity/hifi/pull/11024#discussion_r128885491
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
setHalfExtents(halfExtents);
|
||||
|
@ -62,6 +66,7 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
|||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
//TODO WL21389: See comment in setBox regarding clearance
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_SPHERE;
|
||||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
|
@ -70,12 +75,14 @@ void ShapeInfo::setSphere(float radius) {
|
|||
}
|
||||
|
||||
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
|
||||
//TODO WL21389: May need to skip resetting type here.
|
||||
_pointCollection = pointCollection;
|
||||
_type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
||||
//TODO WL21389: See comment in setBox regarding clearance
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_CAPSULE_Y;
|
||||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
|
@ -117,6 +124,7 @@ int ShapeInfo::getLargestSubshapePointCount() const {
|
|||
}
|
||||
|
||||
float ShapeInfo::computeVolume() const {
|
||||
//TODO WL21389: Add support for other ShapeTypes( CYLINDER_X, CYLINDER_Y, etc).
|
||||
const float DEFAULT_VOLUME = 1.0f;
|
||||
float volume = DEFAULT_VOLUME;
|
||||
switch(_type) {
|
||||
|
@ -136,7 +144,10 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f);
|
||||
// Need to offset halfExtents.y by x to account for the system treating
|
||||
// the y extent of the capsule as the cylindrical height + spherical radius.
|
||||
float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
|
||||
volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -147,6 +158,7 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
|
||||
bool ShapeInfo::contains(const glm::vec3& point) const {
|
||||
//TODO WL21389: Add support for other ShapeTypes like Ellipsoid/Compound.
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
return glm::length(point) <= _halfExtents.x;
|
||||
|
@ -191,6 +203,7 @@ bool ShapeInfo::contains(const glm::vec3& point) const {
|
|||
}
|
||||
|
||||
const DoubleHashKey& ShapeInfo::getHash() const {
|
||||
//TODO WL21389: Need to include the pointlist for SIMPLE_HULL in hash
|
||||
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET;
|
||||
|
|
30
scripts/developer/tests/basicEntityTest/shapeSpawner.js
Normal file
30
scripts/developer/tests/basicEntityTest/shapeSpawner.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// compute a position to create the object relative to avatar
|
||||
var forwardOffset = Vec3.multiply(2.0, Quat.getFront(MyAvatar.orientation));
|
||||
var objectPosition = Vec3.sum(MyAvatar.position, forwardOffset);
|
||||
|
||||
var LIFETIME = 1800; //seconds
|
||||
var DIM_HEIGHT = 1, DIM_WIDTH = 1, DIM_DEPTH = 1;
|
||||
var COLOR_R = 100, COLOR_G = 10, COLOR_B = 200;
|
||||
|
||||
var properties = {
|
||||
name: "ShapeSpawnTest",
|
||||
type: "Shape",
|
||||
shape: "Cylinder",
|
||||
dimensions: {x: DIM_WIDTH, y: DIM_HEIGHT, z: DIM_DEPTH},
|
||||
color: {red: COLOR_R, green: COLOR_G, blue: COLOR_B},
|
||||
position: objectPosition,
|
||||
lifetime: LIFETIME,
|
||||
};
|
||||
|
||||
// create the object
|
||||
var entityId = Entities.addEntity(properties);
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(entityId);
|
||||
}
|
||||
|
||||
// delete the object when this script is stopped
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue