mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 17:03:58 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into yellow
This commit is contained in:
commit
97b18fcd52
8 changed files with 197 additions and 84 deletions
|
@ -18,6 +18,7 @@
|
|||
|
||||
var entityProps, currentPosition, currentVelocity, currentRotation, distanceToTarget, velocityTowardTarget, desiredVelocity;
|
||||
var addedVelocity, newVelocity, angularVelocity, dT, cameraEntityDistance;
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
var LASER_WIDTH = 3;
|
||||
var LASER_COLOR = {
|
||||
|
@ -50,7 +51,7 @@ var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/s
|
|||
var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
|
||||
|
||||
function getRayIntersection(pickRay) {
|
||||
var intersection = Entities.findRayIntersection(pickRay);
|
||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
@ -194,7 +195,7 @@ function controller(side) {
|
|||
origin: this.palmPosition,
|
||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition))
|
||||
};
|
||||
var intersection = getRayIntersection(pickRay);
|
||||
var intersection = getRayIntersection(pickRay, true);
|
||||
if (intersection.intersects && intersection.properties.collisionsWillMove) {
|
||||
this.laserWasHovered = true;
|
||||
if (this.triggerHeld && !this.grabbing) {
|
||||
|
@ -286,10 +287,12 @@ function controller(side) {
|
|||
|
||||
function update(deltaTime) {
|
||||
rightController.update(deltaTime);
|
||||
leftController.update(deltaTime);
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
}
|
||||
|
||||
function vectorIsZero(v) {
|
||||
|
@ -297,6 +300,7 @@ function vectorIsZero(v) {
|
|||
}
|
||||
|
||||
var rightController = new controller(RIGHT);
|
||||
var leftController = new controller(LEFT);
|
||||
|
||||
|
||||
Script.update.connect(update);
|
||||
|
|
|
@ -19,20 +19,20 @@ var EDGE_THICKESS = 0.10;
|
|||
var EDGE_HEIGHT = 0.10;
|
||||
var DROP_HEIGHT = 0.3;
|
||||
var PUCK_SIZE = 0.15;
|
||||
var PUCK_THICKNESS = 0.03;
|
||||
var PADDLE_SIZE = 0.12;
|
||||
var PADDLE_THICKNESS = 0.03;
|
||||
var PUCK_THICKNESS = 0.05;
|
||||
var PADDLE_SIZE = 0.15;
|
||||
var PADDLE_THICKNESS = 0.05;
|
||||
|
||||
var GOAL_WIDTH = 0.35;
|
||||
|
||||
var GRAVITY = -9.8;
|
||||
var LIFETIME = 6000;
|
||||
var PUCK_DAMPING = 0.03;
|
||||
var PUCK_DAMPING = 0.02;
|
||||
var PADDLE_DAMPING = 0.35;
|
||||
var ANGULAR_DAMPING = 0.10;
|
||||
var PADDLE_ANGULAR_DAMPING = 0.35;
|
||||
var ANGULAR_DAMPING = 0.4;
|
||||
var PADDLE_ANGULAR_DAMPING = 0.75;
|
||||
var MODEL_SCALE = 1.52;
|
||||
var MODEL_OFFSET = { x: 0, y: -0.18, z: 0 };
|
||||
var MODEL_OFFSET = { x: 0, y: -0.19, z: 0 };
|
||||
|
||||
var scoreSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_score.wav");
|
||||
|
||||
|
@ -41,9 +41,16 @@ var normalTable = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTabl
|
|||
var hitSound1 = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav"
|
||||
var hitSound2 = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit2.wav"
|
||||
var hitSideSound = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit3.wav"
|
||||
var puckModel = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyPuck.fbx"
|
||||
var puckCollisionModel = "http://headache.hungry.com/~seth/hifi/airHockeyPuck-hull.obj"
|
||||
var paddleModel = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyPaddle.obj"
|
||||
var paddleCollisionModel = "http://headache.hungry.com/~seth/hifi/paddle-hull.obj"
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var edgeRestitution = 0.9;
|
||||
var floorFriction = 0.01;
|
||||
|
||||
var floor = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Vec3.subtract(center, { x: 0, y: 0, z: 0 }),
|
||||
|
@ -52,6 +59,7 @@ var floor = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
locked: true,
|
||||
friction: floorFriction,
|
||||
visible: debugVisible,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -64,6 +72,7 @@ var edge1 = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -76,6 +85,7 @@ var edge2 = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -88,6 +98,7 @@ var edge3a = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -100,6 +111,7 @@ var edge3b = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -112,6 +124,7 @@ var edge4a = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -124,6 +137,7 @@ var edge4b = Entities.addEntity(
|
|||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
visible: debugVisible,
|
||||
restitution: edgeRestitution,
|
||||
locked: true,
|
||||
lifetime: LIFETIME });
|
||||
|
||||
|
@ -146,8 +160,8 @@ function makeNewProp(which) {
|
|||
if (which == "puck") {
|
||||
return Entities.addEntity(
|
||||
{ type: "Model",
|
||||
modelURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
modelURL: puckModel,
|
||||
compoundShapeURL: puckCollisionModel,
|
||||
collisionSoundURL: hitSound1,
|
||||
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT, z: 0 }),
|
||||
dimensions: { x: PUCK_SIZE, y: PUCK_THICKNESS, z: PUCK_SIZE },
|
||||
|
@ -162,13 +176,13 @@ function makeNewProp(which) {
|
|||
else if (which == "paddle1") {
|
||||
return Entities.addEntity(
|
||||
{ type: "Model",
|
||||
modelURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
modelURL: paddleModel,
|
||||
compoundShapeURL: paddleCollisionModel,
|
||||
collisionSoundURL: hitSound2,
|
||||
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT, z: FIELD_LENGTH * 0.35 }),
|
||||
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: FIELD_LENGTH * 0.35 }),
|
||||
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
velocity: { x: 0, y: 0.05, z: 0 },
|
||||
velocity: { x: 0, y: 0.07, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: PADDLE_DAMPING,
|
||||
angularDamping: PADDLE_ANGULAR_DAMPING,
|
||||
|
@ -178,13 +192,13 @@ function makeNewProp(which) {
|
|||
else if (which == "paddle2") {
|
||||
return Entities.addEntity(
|
||||
{ type: "Model",
|
||||
modelURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/puck.obj",
|
||||
modelURL: paddleModel,
|
||||
compoundShapeURL: paddleCollisionModel,
|
||||
collisionSoundURL: hitSound2,
|
||||
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT, z: -FIELD_LENGTH * 0.35 }),
|
||||
position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: -FIELD_LENGTH * 0.35 }),
|
||||
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE },
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
velocity: { x: 0, y: 0.05, z: 0 },
|
||||
velocity: { x: 0, y: 0.07, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: PADDLE_DAMPING,
|
||||
angularDamping: PADDLE_ANGULAR_DAMPING,
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
var addedVelocity, newVelocity, angularVelocity, dT, cameraEntityDistance;
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
var LASER_WIDTH = 3;
|
||||
var LASER_COLOR = {
|
||||
|
@ -50,10 +50,11 @@ var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/s
|
|||
var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
|
||||
|
||||
function getRayIntersection(pickRay) {
|
||||
var intersection = Entities.findRayIntersection(pickRay);
|
||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
||||
function controller(side) {
|
||||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
|
@ -190,7 +191,7 @@ function controller(side) {
|
|||
origin: this.palmPosition,
|
||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition))
|
||||
};
|
||||
var intersection = getRayIntersection(pickRay);
|
||||
var intersection = getRayIntersection(pickRay, true);
|
||||
if (intersection.intersects && intersection.properties.collisionsWillMove) {
|
||||
this.laserWasHovered = true;
|
||||
if (this.triggerHeld && !this.grabbing) {
|
||||
|
@ -282,10 +283,12 @@ function controller(side) {
|
|||
|
||||
function update(deltaTime) {
|
||||
rightController.update(deltaTime);
|
||||
leftController.update(deltaTime);
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
}
|
||||
|
||||
function vectorIsZero(v) {
|
||||
|
@ -293,6 +296,7 @@ function vectorIsZero(v) {
|
|||
}
|
||||
|
||||
var rightController = new controller(RIGHT);
|
||||
var leftController = new controller(LEFT);
|
||||
|
||||
|
||||
Script.update.connect(update);
|
||||
|
|
76
examples/pointer.js
Normal file
76
examples/pointer.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
|
||||
var lineEntityID = null;
|
||||
var lineIsRezzed = false;
|
||||
|
||||
|
||||
function nearLinePoint(targetPosition) {
|
||||
var handPosition = MyAvatar.getRightPalmPosition();
|
||||
var along = Vec3.subtract(targetPosition, handPosition);
|
||||
along = Vec3.normalize(along);
|
||||
along = Vec3.multiply(along, 0.4);
|
||||
return Vec3.sum(handPosition, along);
|
||||
}
|
||||
|
||||
|
||||
function removeLine() {
|
||||
if (lineIsRezzed) {
|
||||
Entities.deleteEntity(lineEntityID);
|
||||
lineEntityID = null;
|
||||
lineIsRezzed = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createOrUpdateLine(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||
|
||||
if (lineIsRezzed) {
|
||||
Entities.editEntity(lineEntityID, {
|
||||
position: nearLinePoint(intersection.intersection),
|
||||
dimensions: Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection)),
|
||||
lifetime: 30 // renew lifetime
|
||||
});
|
||||
|
||||
} else {
|
||||
lineIsRezzed = true;
|
||||
lineEntityID = Entities.addEntity({
|
||||
type: "Line",
|
||||
position: nearLinePoint(intersection.intersection),
|
||||
dimensions: Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection)),
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
lifetime: 30 // if someone crashes while pointing, don't leave the line there forever.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function mousePressEvent(event) {
|
||||
if (!event.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
if (lineIsRezzed) {
|
||||
return;
|
||||
}
|
||||
createOrUpdateLine(event);
|
||||
if (lineIsRezzed) {
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
createOrUpdateLine(event);
|
||||
}
|
||||
|
||||
|
||||
function mouseReleaseEvent() {
|
||||
if (lineIsRezzed) {
|
||||
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
|
||||
}
|
||||
removeLine();
|
||||
}
|
||||
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
@ -1111,6 +1111,9 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const
|
|||
|
||||
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
|
||||
EntityItem* entity = entityTree->findEntityByEntityItemID(id);
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
QUuid simulatorID = entity->getSimulatorID();
|
||||
if (simulatorID.isNull() || (simulatorID != myNodeID)) {
|
||||
return; // Only one injector per simulation, please.
|
||||
|
@ -1119,27 +1122,31 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
if (collisionSoundURL.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
SharedSoundPointer sound = DependencyManager::get<SoundCache>().data()->getSound(QUrl(collisionSoundURL));
|
||||
if (!sound->isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float mass = entity->computeMass();
|
||||
const float COLLISION_PENTRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
|
||||
const float linearVelocity = glm::length(collision.penetration) * COLLISION_PENTRATION_TO_VELOCITY;
|
||||
const float energy = mass * linearVelocity * linearVelocity / 2.0f;
|
||||
const glm::vec3 position = collision.contactPoint;
|
||||
const float COLLISION_ENERGY_AT_FULL_VOLUME = 10.0f;
|
||||
const float COLLISION_MINIMUM_VOLUME = 0.01f;
|
||||
const float energyPercentOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
|
||||
//qCDebug(entitiesrenderer) << energyPercentOfFull << energy << " " << " " << linearVelocity << " " << mass;
|
||||
if (energyPercentOfFull < COLLISION_MINIMUM_VOLUME) {
|
||||
const float COLLISION_ENERGY_AT_FULL_VOLUME = 0.5f;
|
||||
const float COLLISION_MINIMUM_VOLUME = 0.001f;
|
||||
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
|
||||
if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) {
|
||||
return;
|
||||
}
|
||||
// This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range 0.5-1.0, if we play it all.
|
||||
const float COLLISION_SOUND_COMPRESSION = 0.5f;
|
||||
const float volume = (energyPercentOfFull * COLLISION_SOUND_COMPRESSION) + (1.0f - COLLISION_SOUND_COMPRESSION);
|
||||
//qCDebug(entitiesrenderer) << collisionSoundURL << " " << volume << " " << position << " " << sound->isStereo();
|
||||
|
||||
auto soundCache = DependencyManager::get<SoundCache>();
|
||||
if (soundCache.isNull()) {
|
||||
return;
|
||||
}
|
||||
SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL));
|
||||
if (sound.isNull() || !sound->isReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all.
|
||||
const float COLLISION_SOUND_COMPRESSION_RANGE = 0.7f;
|
||||
float volume = energyFactorOfFull;
|
||||
volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
|
||||
|
||||
// This is quite similar to AudioScriptingInterface::playSound() and should probably be refactored.
|
||||
AudioInjectorOptions options;
|
||||
|
@ -1148,6 +1155,7 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
options.volume = volume;
|
||||
AudioInjector* injector = new AudioInjector(sound.data(), options);
|
||||
injector->setLocalAudioInterface(_localAudioInterface);
|
||||
injector->triggerDeleteAfterFinish();
|
||||
QThread* injectorThread = new QThread();
|
||||
injectorThread->setObjectName("Audio Injector Thread");
|
||||
injector->moveToThread(injectorThread);
|
||||
|
@ -1166,13 +1174,19 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
|||
if (!_tree || _shuttingDown) {
|
||||
return;
|
||||
}
|
||||
// Don't respond to small continuous contacts. It causes deadlocks when locking the entityTree.
|
||||
// Note that any entity script is likely to Entities.getEntityProperties(), which locks the tree.
|
||||
const float COLLISION_MINUMUM_PENETRATION = 0.005;
|
||||
if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// See if we should play sounds
|
||||
EntityTree* entityTree = static_cast<EntityTree*>(_tree);
|
||||
if (!entityTree->tryLockForRead()) {
|
||||
// I don't know why this can happen, but if it does,
|
||||
// the consequences are a deadlock, so bail.
|
||||
qCDebug(entitiesrenderer) << "NOTICE: skipping collision.";
|
||||
qCDebug(entitiesrenderer) << "NOTICE: skipping collision type " << collision.type << " penetration " << glm::length(collision.penetration);
|
||||
return;
|
||||
}
|
||||
const QUuid& myNodeID = DependencyManager::get<NodeList>()->getSessionUUID();
|
||||
|
|
|
@ -15,36 +15,48 @@
|
|||
#include "BulletUtil.h"
|
||||
|
||||
|
||||
// find the average point on a convex shape
|
||||
glm::vec3 findCenter(const QVector<glm::vec3>& points) {
|
||||
glm::vec3 result = glm::vec3(0);
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
result += points[i];
|
||||
|
||||
btConvexHullShape* ShapeInfoUtil::createConvexHull(const QVector<glm::vec3>& points) {
|
||||
assert(points.size() > 0);
|
||||
|
||||
btConvexHullShape* hull = new btConvexHullShape();
|
||||
glm::vec3 center = points[0];
|
||||
glm::vec3 maxCorner = center;
|
||||
glm::vec3 minCorner = center;
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
center += points[i];
|
||||
maxCorner = glm::max(maxCorner, points[i]);
|
||||
minCorner = glm::min(minCorner, points[i]);
|
||||
}
|
||||
return result * (1.0f / points.size());
|
||||
}
|
||||
center /= (float)(points.size());
|
||||
|
||||
float margin = hull->getMargin();
|
||||
|
||||
// bullet puts "margins" around all the collision shapes. This can cause shapes will hulls
|
||||
// to float a bit above what they are sitting on, etc. One option is to call:
|
||||
//
|
||||
// compound->setMargin(0.01);
|
||||
//
|
||||
// to reduce the size of the margin, but this has some consequences for the
|
||||
// performance and stability of the simulation. Instead, we clench in all the points of
|
||||
// the hull by the margin. These clenched points + bullets margin will but the actual
|
||||
// collision hull fairly close to the visual edge of the object.
|
||||
QVector<glm::vec3> shrinkByMargin(const QVector<glm::vec3>& points, const glm::vec3 center, float margin) {
|
||||
QVector<glm::vec3> result(points.size());
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
glm::vec3 pVec = points[ i ] - center;
|
||||
glm::vec3 pVecNorm = glm::normalize(pVec);
|
||||
result[ i ] = center + pVec - (pVecNorm * margin);
|
||||
// Bullet puts "margins" around all the collision shapes. This can cause objects that use ConvexHull shapes
|
||||
// to have visible gaps between them and the surface they touch. One option is to reduce the size of the margin
|
||||
// but this can reduce the performance and stability of the simulation (e.g. the GJK algorithm will fail to provide
|
||||
// nearest contact points and narrow-phase collisions will fall into more expensive code paths). Alternatively
|
||||
// one can shift the geometry of the shape to make the margin surface approximately close to the visible surface.
|
||||
// This is the strategy we try, but if the object is too small then we start to reduce the margin down to some minimum.
|
||||
|
||||
const float MIN_MARGIN = 0.01f;
|
||||
glm::vec3 diagonal = maxCorner - minCorner;
|
||||
float minDimension = glm::min(diagonal[0], diagonal[1]);
|
||||
minDimension = glm::min(minDimension, diagonal[2]);
|
||||
margin = glm::min(glm::max(0.5f * minDimension, MIN_MARGIN), margin);
|
||||
hull->setMargin(margin);
|
||||
|
||||
// add the points, correcting for margin
|
||||
glm::vec3 relativeScale = (diagonal - glm::vec3(2.0f * margin)) / diagonal;
|
||||
glm::vec3 correctedPoint;
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
correctedPoint = (points[i] - center) * relativeScale + center;
|
||||
hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false);
|
||||
}
|
||||
return result;
|
||||
hull->recalcLocalAabb();
|
||||
return hull;
|
||||
}
|
||||
|
||||
|
||||
btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
||||
btCollisionShape* shape = NULL;
|
||||
switch(info.getType()) {
|
||||
|
@ -68,30 +80,14 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
|||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
uint32_t numSubShapes = info.getNumSubShapes();
|
||||
if (numSubShapes == 1) {
|
||||
auto hull = new btConvexHullShape();
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
glm::vec3 center = findCenter(points[0]);
|
||||
QVector<glm::vec3> shrunken = shrinkByMargin(points[0], center, hull->getMargin());
|
||||
foreach (glm::vec3 point, shrunken) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
shape = hull;
|
||||
shape = createConvexHull(info.getPoints()[0]);
|
||||
} else {
|
||||
assert(numSubShapes > 1);
|
||||
auto compound = new btCompoundShape();
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
foreach (QVector<glm::vec3> hullPoints, points) {
|
||||
auto hull = new btConvexHullShape();
|
||||
glm::vec3 center = findCenter(points[0]);
|
||||
QVector<glm::vec3> shrunken = shrinkByMargin(hullPoints, center, hull->getMargin());
|
||||
foreach (glm::vec3 point, shrunken) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
btConvexHullShape* hull = createConvexHull(hullPoints);
|
||||
compound->addChildShape (trans, hull);
|
||||
}
|
||||
shape = compound;
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
// TODO: rename this to ShapeFactory
|
||||
namespace ShapeInfoUtil {
|
||||
|
||||
btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points);
|
||||
|
||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
|
||||
|
@ -35,7 +36,7 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is
|
|||
isPending = true;
|
||||
bool alreadyWaiting = _scriptUsers.contains(url);
|
||||
_scriptUsers.insert(url, scriptUser);
|
||||
|
||||
|
||||
if (alreadyWaiting) {
|
||||
qCDebug(scriptengine) << "Already downloading script at:" << url.toString();
|
||||
} else {
|
||||
|
@ -43,7 +44,7 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is
|
|||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
||||
qCDebug(scriptengine) << "Downloading script at:" << url.toString();
|
||||
qCDebug(scriptengine) << "Downloading script at" << url.toString();
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
connect(reply, &QNetworkReply::finished, this, &ScriptCache::scriptDownloaded);
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ void ScriptCache::scriptDownloaded() {
|
|||
QUrl url = reply->url();
|
||||
QList<ScriptUser*> scriptUsers = _scriptUsers.values(url);
|
||||
_scriptUsers.remove(url);
|
||||
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
|
||||
_scriptCache[url] = reply->readAll();
|
||||
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
|
||||
|
@ -65,7 +66,9 @@ void ScriptCache::scriptDownloaded() {
|
|||
user->scriptContentsAvailable(url, _scriptCache[url]);
|
||||
}
|
||||
} else {
|
||||
qCDebug(scriptengine) << "ERROR Loading file:" << reply->url().toString();
|
||||
qCWarning(scriptengine) << "Error loading script from URL " << reply->url().toString()
|
||||
<< "- HTTP status code is" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
|
||||
<< "and error from QNetworkReply is" << reply->errorString();
|
||||
foreach(ScriptUser* user, scriptUsers) {
|
||||
user->errorInLoadingScript(url);
|
||||
}
|
||||
|
@ -73,4 +76,4 @@ void ScriptCache::scriptDownloaded() {
|
|||
reply->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue