mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 19:16:56 +02:00
Merge branch 'master' of git://github.com/highfidelity/hifi into 19630
Conflicts: interface/src/Application.cpp
This commit is contained in:
commit
b48b8aab12
33 changed files with 308 additions and 137 deletions
|
@ -21,9 +21,9 @@ var roll = 0.0;
|
||||||
var rotation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll)
|
var rotation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll)
|
||||||
|
|
||||||
var originalProperties = {
|
var originalProperties = {
|
||||||
position: { x: 10,
|
position: { x: MyAvatar.position.x,
|
||||||
y: 0,
|
y: MyAvatar.position.y,
|
||||||
z: 0 },
|
z: MyAvatar.position.z },
|
||||||
|
|
||||||
radius : 1,
|
radius : 1,
|
||||||
|
|
||||||
|
@ -56,11 +56,11 @@ function moveModel(deltaTime) {
|
||||||
|
|
||||||
if (count % adjustFPSEveryWhile == 0) {
|
if (count % adjustFPSEveryWhile == 0) {
|
||||||
if (animationFPS == 30) {
|
if (animationFPS == 30) {
|
||||||
animationFPS = 10;
|
|
||||||
} else if (animationFPS == 10) {
|
|
||||||
animationFPS = 60;
|
|
||||||
} else if (animationFPS == 60) {
|
|
||||||
animationFPS = 30;
|
animationFPS = 30;
|
||||||
|
} else if (animationFPS == 10) {
|
||||||
|
animationFPS = 10;
|
||||||
|
} else if (animationFPS == 60) {
|
||||||
|
animationFPS = 60;
|
||||||
}
|
}
|
||||||
print("animationFPS=" + animationFPS);
|
print("animationFPS=" + animationFPS);
|
||||||
isPlaying = true;
|
isPlaying = true;
|
||||||
|
|
|
@ -25,7 +25,7 @@ function printVector(string, vector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var CHANCE_OF_MOVING = 0.005;
|
var CHANCE_OF_MOVING = 0.005;
|
||||||
var CHANCE_OF_SOUND = 0.000;
|
var CHANCE_OF_SOUND = 0.005;
|
||||||
var CHANCE_OF_HEAD_TURNING = 0.05;
|
var CHANCE_OF_HEAD_TURNING = 0.05;
|
||||||
var CHANCE_OF_BIG_MOVE = 0.1;
|
var CHANCE_OF_BIG_MOVE = 0.1;
|
||||||
var CHANCE_OF_WAVING = 0.009;
|
var CHANCE_OF_WAVING = 0.009;
|
||||||
|
@ -41,11 +41,11 @@ var isWaving = false;
|
||||||
var waveFrequency = 0.0;
|
var waveFrequency = 0.0;
|
||||||
var waveAmplitude = 0.0;
|
var waveAmplitude = 0.0;
|
||||||
|
|
||||||
var X_MIN = 20.0;
|
var X_MIN = 5.0;
|
||||||
var X_MAX = 25.0;
|
var X_MAX = 15.0;
|
||||||
var Z_MIN = 20.0;
|
var Z_MIN = 5.0;
|
||||||
var Z_MAX = 25.0;
|
var Z_MAX = 15.0;
|
||||||
var Y_PELVIS = 2.5;
|
var Y_PELVIS = 1.0;
|
||||||
var SPINE_JOINT_NUMBER = 13;
|
var SPINE_JOINT_NUMBER = 13;
|
||||||
var SHOULDER_JOINT_NUMBER = 17;
|
var SHOULDER_JOINT_NUMBER = 17;
|
||||||
var ELBOW_JOINT_NUMBER = 18;
|
var ELBOW_JOINT_NUMBER = 18;
|
||||||
|
|
|
@ -76,38 +76,42 @@ function controller(wichSide) {
|
||||||
this.oldModelRadius;
|
this.oldModelRadius;
|
||||||
|
|
||||||
this.laser = Overlays.addOverlay("line3d", {
|
this.laser = Overlays.addOverlay("line3d", {
|
||||||
position: this.palmPosition,
|
position: { x: 0, y: 0, z: 0 },
|
||||||
end: this.tipPosition,
|
end: { x: 0, y: 0, z: 0 },
|
||||||
color: LASER_COLOR,
|
color: LASER_COLOR,
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: false,
|
visible: false,
|
||||||
lineWidth: LASER_WIDTH
|
lineWidth: LASER_WIDTH,
|
||||||
|
anchor: "MyAvatar"
|
||||||
});
|
});
|
||||||
|
|
||||||
this.guideScale = 0.02;
|
this.guideScale = 0.02;
|
||||||
this.ball = Overlays.addOverlay("sphere", {
|
this.ball = Overlays.addOverlay("sphere", {
|
||||||
position: this.palmPosition,
|
position: { x: 0, y: 0, z: 0 },
|
||||||
size: this.guideScale,
|
size: this.guideScale,
|
||||||
solid: true,
|
solid: true,
|
||||||
color: { red: 0, green: 255, blue: 0 },
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: false,
|
visible: false,
|
||||||
|
anchor: "MyAvatar"
|
||||||
});
|
});
|
||||||
this.leftRight = Overlays.addOverlay("line3d", {
|
this.leftRight = Overlays.addOverlay("line3d", {
|
||||||
position: this.palmPosition,
|
position: { x: 0, y: 0, z: 0 },
|
||||||
end: this.tipPosition,
|
end: { x: 0, y: 0, z: 0 },
|
||||||
color: { red: 0, green: 0, blue: 255 },
|
color: { red: 0, green: 0, blue: 255 },
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: false,
|
visible: false,
|
||||||
lineWidth: LASER_WIDTH
|
lineWidth: LASER_WIDTH,
|
||||||
|
anchor: "MyAvatar"
|
||||||
});
|
});
|
||||||
this.topDown = Overlays.addOverlay("line3d", {
|
this.topDown = Overlays.addOverlay("line3d", {
|
||||||
position: this.palmPosition,
|
position: { x: 0, y: 0, z: 0 },
|
||||||
end: this.tipPosition,
|
end: { x: 0, y: 0, z: 0 },
|
||||||
color: { red: 0, green: 0, blue: 255 },
|
color: { red: 0, green: 0, blue: 255 },
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: false,
|
visible: false,
|
||||||
lineWidth: LASER_WIDTH
|
lineWidth: LASER_WIDTH,
|
||||||
|
anchor: "MyAvatar"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,10 +174,11 @@ function controller(wichSide) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.moveLaser = function () {
|
this.moveLaser = function () {
|
||||||
var endPosition = Vec3.sum(this.palmPosition, Vec3.multiply(this.front, LASER_LENGTH_FACTOR));
|
var startPosition = Vec3.subtract(this.palmPosition, MyAvatar.position);
|
||||||
|
var endPosition = Vec3.sum(startPosition, Vec3.multiply(this.front, LASER_LENGTH_FACTOR));
|
||||||
|
|
||||||
Overlays.editOverlay(this.laser, {
|
Overlays.editOverlay(this.laser, {
|
||||||
position: this.palmPosition,
|
position: startPosition,
|
||||||
end: endPosition,
|
end: endPosition,
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
|
@ -219,11 +224,11 @@ function controller(wichSide) {
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
modelRotation: newRotation
|
modelRotation: newRotation
|
||||||
});
|
});
|
||||||
print("Moving " + this.modelID.id);
|
// print("Moving " + this.modelID.id);
|
||||||
// Vec3.print("Old Position: ", this.oldModelPosition);
|
// Vec3.print("Old Position: ", this.oldModelPosition);
|
||||||
// Vec3.print("Sav Position: ", newPosition);
|
// Vec3.print("Sav Position: ", newPosition);
|
||||||
Quat.print("Old Rotation: ", this.oldModelRotation);
|
// Quat.print("Old Rotation: ", this.oldModelRotation);
|
||||||
Quat.print("New Rotation: ", newRotation);
|
// Quat.print("New Rotation: ", newRotation);
|
||||||
|
|
||||||
this.oldModelRotation = newRotation;
|
this.oldModelRotation = newRotation;
|
||||||
this.oldModelPosition = newPosition;
|
this.oldModelPosition = newPosition;
|
||||||
|
@ -301,7 +306,7 @@ var rightController = new controller(RIGHT);
|
||||||
|
|
||||||
function moveModels() {
|
function moveModels() {
|
||||||
if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) {
|
if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) {
|
||||||
print("Both controllers");
|
//print("Both controllers");
|
||||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||||
|
|
||||||
|
@ -319,7 +324,7 @@ function moveModels() {
|
||||||
|
|
||||||
var newPosition = Vec3.sum(middle,
|
var newPosition = Vec3.sum(middle,
|
||||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
||||||
Vec3.print("Ratio : " + ratio + " New position: ", newPosition);
|
//Vec3.print("Ratio : " + ratio + " New position: ", newPosition);
|
||||||
var rotation = Quat.multiply(leftController.rotation,
|
var rotation = Quat.multiply(leftController.rotation,
|
||||||
Quat.inverse(leftController.oldRotation));
|
Quat.inverse(leftController.oldRotation));
|
||||||
rotation = Quat.multiply(rotation, leftController.oldModelRotation);
|
rotation = Quat.multiply(rotation, leftController.oldModelRotation);
|
||||||
|
|
|
@ -39,7 +39,7 @@ var impactSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-pub
|
||||||
var targetHitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw");
|
var targetHitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw");
|
||||||
var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw");
|
var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw");
|
||||||
|
|
||||||
var gunModel = "http://highfidelity-public.s3-us-west-1.amazonaws.com/models/attachments/Raygun2.fst";
|
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
||||||
|
|
||||||
var audioOptions = new AudioInjectionOptions();
|
var audioOptions = new AudioInjectionOptions();
|
||||||
audioOptions.volume = 0.9;
|
audioOptions.volume = 0.9;
|
||||||
|
@ -199,7 +199,7 @@ function playLoadSound() {
|
||||||
Audio.playSound(loadSound, audioOptions);
|
Audio.playSound(loadSound, audioOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
//MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||||
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||||
|
|
||||||
// Give a bit of time to load before playing sound
|
// Give a bit of time to load before playing sound
|
||||||
|
@ -320,7 +320,6 @@ function scriptEnding() {
|
||||||
Overlays.deleteOverlay(reticle);
|
Overlays.deleteOverlay(reticle);
|
||||||
Overlays.deleteOverlay(text);
|
Overlays.deleteOverlay(text);
|
||||||
MyAvatar.detachOne(gunModel);
|
MyAvatar.detachOne(gunModel);
|
||||||
MyAvatar.detachOne(gunModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
||||||
|
|
|
@ -50,6 +50,13 @@ var LEFT_BUTTON_4 = 4;
|
||||||
var RIGHT_PALM = 2;
|
var RIGHT_PALM = 2;
|
||||||
var RIGHT_BUTTON_4 = 10;
|
var RIGHT_BUTTON_4 = 10;
|
||||||
|
|
||||||
|
|
||||||
|
function printVector(text, v, decimals) {
|
||||||
|
print(text + " " + v.x.toFixed(decimals) + ", " + v.y.toFixed(decimals) + ", " + v.z.toFixed(decimals));
|
||||||
|
}
|
||||||
|
|
||||||
|
var debug = false;
|
||||||
|
|
||||||
// Used by handleGrabBehavior() for managing the grab position changes
|
// Used by handleGrabBehavior() for managing the grab position changes
|
||||||
function getAndResetGrabDelta() {
|
function getAndResetGrabDelta() {
|
||||||
var HAND_GRAB_SCALE_DISTANCE = 2.0;
|
var HAND_GRAB_SCALE_DISTANCE = 2.0;
|
||||||
|
@ -60,24 +67,12 @@ function getAndResetGrabDelta() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by handleGrabBehavior() for managing the grab velocity feature
|
function getGrabRotation() {
|
||||||
function getAndResetGrabDeltaVelocity() {
|
|
||||||
var HAND_GRAB_SCALE_VELOCITY = 50.0;
|
|
||||||
var delta = Vec3.multiply(grabDeltaVelocity, (MyAvatar.scale * HAND_GRAB_SCALE_VELOCITY));
|
|
||||||
grabDeltaVelocity = { x: 0, y: 0, z: 0};
|
|
||||||
var avatarRotation = MyAvatar.orientation;
|
|
||||||
var result = Quat.multiply(avatarRotation, Vec3.multiply(delta, -1));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by handleGrabBehavior() for managing the grab rotation feature
|
|
||||||
function getAndResetGrabRotation() {
|
|
||||||
var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation));
|
var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation));
|
||||||
grabStartRotation = grabCurrentRotation;
|
|
||||||
return quatDiff;
|
return quatDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles all the grab related behavior: position (crawl), velocity (flick), and rotate (twist)
|
// When move button is pressed, process results
|
||||||
function handleGrabBehavior(deltaTime) {
|
function handleGrabBehavior(deltaTime) {
|
||||||
// check for and handle grab behaviors
|
// check for and handle grab behaviors
|
||||||
grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4);
|
grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4);
|
||||||
|
@ -88,9 +83,11 @@ function handleGrabBehavior(deltaTime) {
|
||||||
if (grabbingWithRightHand && !wasGrabbingWithRightHand) {
|
if (grabbingWithRightHand && !wasGrabbingWithRightHand) {
|
||||||
// Just starting grab, capture starting rotation
|
// Just starting grab, capture starting rotation
|
||||||
grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
||||||
|
grabStartPosition = Controller.getSpatialControlPosition(RIGHT_PALM);
|
||||||
|
if (debug) printVector("start position", grabStartPosition, 3);
|
||||||
}
|
}
|
||||||
if (grabbingWithRightHand) {
|
if (grabbingWithRightHand) {
|
||||||
grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime));
|
grabDelta = Vec3.subtract(Controller.getSpatialControlPosition(RIGHT_PALM), grabStartPosition);
|
||||||
grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
||||||
}
|
}
|
||||||
if (!grabbingWithRightHand && wasGrabbingWithRightHand) {
|
if (!grabbingWithRightHand && wasGrabbingWithRightHand) {
|
||||||
|
@ -102,10 +99,12 @@ function handleGrabBehavior(deltaTime) {
|
||||||
if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) {
|
if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) {
|
||||||
// Just starting grab, capture starting rotation
|
// Just starting grab, capture starting rotation
|
||||||
grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
||||||
|
grabStartPosition = Controller.getSpatialControlPosition(LEFT_PALM);
|
||||||
|
if (debug) printVector("start position", grabStartPosition, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grabbingWithLeftHand) {
|
if (grabbingWithLeftHand) {
|
||||||
grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(LEFT_PALM), deltaTime));
|
grabDelta = Vec3.subtract(Controller.getSpatialControlPosition(LEFT_PALM), grabStartPosition);
|
||||||
grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
||||||
}
|
}
|
||||||
if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) {
|
if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) {
|
||||||
|
@ -119,44 +118,57 @@ function handleGrabBehavior(deltaTime) {
|
||||||
|
|
||||||
if (grabbing) {
|
if (grabbing) {
|
||||||
|
|
||||||
// move position
|
var headOrientation = MyAvatar.headOrientation;
|
||||||
var moveFromGrab = getAndResetGrabDelta();
|
var front = Quat.getFront(headOrientation);
|
||||||
if (Vec3.length(moveFromGrab) > EPSILON) {
|
var right = Quat.getRight(headOrientation);
|
||||||
MyAvatar.position = Vec3.sum(MyAvatar.position, moveFromGrab);
|
var up = Quat.getUp(headOrientation);
|
||||||
velocity = { x: 0, y: 0, z: 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
// add some rotation...
|
|
||||||
var deltaRotation = getAndResetGrabRotation();
|
|
||||||
var GRAB_CONTROLLER_TURN_SCALING = 0.5;
|
|
||||||
var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING);
|
|
||||||
|
|
||||||
// Adjust body yaw by yaw from controller
|
grabDelta = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiply(grabDelta, -1));
|
||||||
var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation);
|
|
||||||
|
if (debug) {
|
||||||
|
printVector("grabDelta: ", grabDelta, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var THRUST_GRAB_SCALING = 0.0;
|
||||||
|
|
||||||
|
var thrustFront = Vec3.multiply(front, MyAvatar.scale * grabDelta.z * THRUST_GRAB_SCALING * deltaTime);
|
||||||
|
MyAvatar.addThrust(thrustFront);
|
||||||
|
var thrustRight = Vec3.multiply(right, MyAvatar.scale * grabDelta.x * THRUST_GRAB_SCALING * deltaTime);
|
||||||
|
MyAvatar.addThrust(thrustRight);
|
||||||
|
var thrustUp = Vec3.multiply(up, MyAvatar.scale * grabDelta.y * THRUST_GRAB_SCALING * deltaTime);
|
||||||
|
MyAvatar.addThrust(thrustUp);
|
||||||
|
|
||||||
|
|
||||||
|
// add some rotation...
|
||||||
|
var deltaRotation = getGrabRotation();
|
||||||
|
var PITCH_SCALING = 2.0;
|
||||||
|
var PITCH_DEAD_ZONE = 2.0;
|
||||||
|
var YAW_SCALING = 2.0;
|
||||||
|
var ROLL_SCALING = 2.0;
|
||||||
|
|
||||||
|
var euler = Quat.safeEulerAngles(deltaRotation);
|
||||||
|
|
||||||
|
// Adjust body yaw by roll from controller
|
||||||
|
var orientation = Quat.multiply(Quat.angleAxis(((euler.y * YAW_SCALING) +
|
||||||
|
(euler.z * ROLL_SCALING)) * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation);
|
||||||
MyAvatar.orientation = orientation;
|
MyAvatar.orientation = orientation;
|
||||||
|
|
||||||
// Adjust head pitch from controller
|
// Adjust head pitch from controller
|
||||||
MyAvatar.headPitch = MyAvatar.headPitch - euler.x;
|
var pitch = 0.0;
|
||||||
|
if (Math.abs(euler.x) > PITCH_DEAD_ZONE) {
|
||||||
|
pitch = (euler.x < 0.0) ? (euler.x + PITCH_DEAD_ZONE) : (euler.x - PITCH_DEAD_ZONE);
|
||||||
|
}
|
||||||
|
MyAvatar.headPitch = MyAvatar.headPitch + (pitch * PITCH_SCALING * deltaTime);
|
||||||
|
|
||||||
|
// TODO: Add some camera roll proportional to the rate of turn (so it feels like an airplane or roller coaster)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add some velocity...
|
|
||||||
if (stoppedGrabbing) {
|
|
||||||
velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity());
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle residual velocity
|
|
||||||
if(Vec3.length(velocity) > EPSILON) {
|
|
||||||
MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(velocity, deltaTime));
|
|
||||||
// damp velocity
|
|
||||||
velocity = Vec3.multiply(velocity, damping);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
wasGrabbingWithRightHand = grabbingWithRightHand;
|
wasGrabbingWithRightHand = grabbingWithRightHand;
|
||||||
wasGrabbingWithLeftHand = grabbingWithLeftHand;
|
wasGrabbingWithLeftHand = grabbingWithLeftHand;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main update function that handles flying and grabbing behaviort
|
// Update for joysticks and move button
|
||||||
function flyWithHydra(deltaTime) {
|
function flyWithHydra(deltaTime) {
|
||||||
var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
|
var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ void main(void) {
|
||||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position)));
|
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
// compute the specular component (sans exponent)
|
// compute the specular component (sans exponent)
|
||||||
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal));
|
float specular = max(0.0, dot(gl_LightSource[0].position, normalizedNormal));
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||||
|
|
|
@ -36,7 +36,7 @@ void main(void) {
|
||||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position)));
|
gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
// compute the specular component (sans exponent)
|
// compute the specular component (sans exponent)
|
||||||
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), viewNormal));
|
float specular = max(0.0, dot(gl_LightSource[0].position, viewNormal));
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||||
|
|
|
@ -39,7 +39,7 @@ void main(void) {
|
||||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position)));
|
gl_FrontLightProduct[0].diffuse * max(0.0, dot(viewNormal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
// compute the specular component (sans exponent)
|
// compute the specular component (sans exponent)
|
||||||
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), viewNormal));
|
float specular = max(0.0, dot(gl_LightSource[0].position, viewNormal));
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
||||||
|
|
|
@ -27,7 +27,7 @@ void main(void) {
|
||||||
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position)));
|
gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
// compute the specular component (sans exponent)
|
// compute the specular component (sans exponent)
|
||||||
float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal));
|
float specular = max(0.0, dot(gl_LightSource[0].position, normalizedNormal));
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
||||||
|
|
|
@ -170,7 +170,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_packetsPerSecond(0),
|
_packetsPerSecond(0),
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
_previousScriptLocation(),
|
_previousScriptLocation(),
|
||||||
_logger(new FileLogger(this)),
|
|
||||||
_nodeBoundsDisplay(this),
|
_nodeBoundsDisplay(this),
|
||||||
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
_runningScriptsWidget(new RunningScriptsWidget(_window)),
|
||||||
_runningScriptsWidgetWasVisible(false)
|
_runningScriptsWidgetWasVisible(false)
|
||||||
|
@ -191,6 +190,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
setOrganizationName(applicationInfo.value("organizationName").toString());
|
setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||||
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
||||||
|
|
||||||
|
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||||
|
|
||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
|
|
||||||
_myAvatar = _avatarManager.getMyAvatar();
|
_myAvatar = _avatarManager.getMyAvatar();
|
||||||
|
@ -237,6 +238,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
|
|
||||||
connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||||
connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
|
connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
|
||||||
|
|
||||||
|
// update our location every 5 seconds in the data-server, assuming that we are authenticated with one
|
||||||
|
const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5.0f * 1000.0f;
|
||||||
|
|
||||||
|
QTimer* locationUpdateTimer = new QTimer(this);
|
||||||
|
connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer);
|
||||||
|
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
|
||||||
|
|
||||||
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
|
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||||
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
|
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
|
||||||
|
@ -3117,6 +3125,34 @@ void Application::updateWindowTitle(){
|
||||||
_window->setWindowTitle(title);
|
_window->setWindowTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::updateLocationInServer() {
|
||||||
|
|
||||||
|
AccountManager& accountManager = AccountManager::getInstance();
|
||||||
|
|
||||||
|
if (accountManager.isLoggedIn()) {
|
||||||
|
|
||||||
|
static QJsonObject lastLocationObject;
|
||||||
|
|
||||||
|
// construct a QJsonObject given the user's current address information
|
||||||
|
QJsonObject updatedLocationObject;
|
||||||
|
|
||||||
|
QJsonObject addressObject;
|
||||||
|
addressObject.insert("position", QString(createByteArray(_myAvatar->getPosition())));
|
||||||
|
addressObject.insert("orientation", QString(createByteArray(glm::degrees(safeEulerAngles(_myAvatar->getOrientation())))));
|
||||||
|
addressObject.insert("domain", NodeList::getInstance()->getDomainHandler().getHostname());
|
||||||
|
|
||||||
|
updatedLocationObject.insert("address", addressObject);
|
||||||
|
|
||||||
|
if (updatedLocationObject != lastLocationObject) {
|
||||||
|
|
||||||
|
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
|
||||||
|
JSONCallbackParameters(), QJsonDocument(updatedLocationObject).toJson());
|
||||||
|
|
||||||
|
lastLocationObject = updatedLocationObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::domainChanged(const QString& domainHostname) {
|
void Application::domainChanged(const QString& domainHostname) {
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
|
|
||||||
|
|
|
@ -281,6 +281,7 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
|
void updateLocationInServer();
|
||||||
void nodeAdded(SharedNodePointer node);
|
void nodeAdded(SharedNodePointer node);
|
||||||
void nodeKilled(SharedNodePointer node);
|
void nodeKilled(SharedNodePointer node);
|
||||||
void packetSent(quint64 length);
|
void packetSent(quint64 length);
|
||||||
|
|
|
@ -345,7 +345,7 @@ Menu::Menu() :
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_VISAGE
|
#ifdef HAVE_VISAGE
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true,
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, false,
|
||||||
appInstance->getVisage(), SLOT(updateEnabled()));
|
appInstance->getVisage(), SLOT(updateEnabled()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -365,6 +365,7 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true);
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,7 @@ private:
|
||||||
namespace MenuOption {
|
namespace MenuOption {
|
||||||
const QString AboutApp = "About Interface";
|
const QString AboutApp = "About Interface";
|
||||||
const QString AlignForearmsWithWrists = "Align Forearms with Wrists";
|
const QString AlignForearmsWithWrists = "Align Forearms with Wrists";
|
||||||
|
const QString AlternateIK = "Alternate IK";
|
||||||
const QString AmbientOcclusion = "Ambient Occlusion";
|
const QString AmbientOcclusion = "Ambient Occlusion";
|
||||||
const QString Atmosphere = "Atmosphere";
|
const QString Atmosphere = "Atmosphere";
|
||||||
const QString Attachments = "Attachments...";
|
const QString Attachments = "Attachments...";
|
||||||
|
|
|
@ -49,8 +49,6 @@ const float COLLISION_RADIUS_SCALE = 0.125f;
|
||||||
const float MIN_KEYBOARD_CONTROL_SPEED = 2.0f;
|
const float MIN_KEYBOARD_CONTROL_SPEED = 2.0f;
|
||||||
const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED;
|
const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED;
|
||||||
|
|
||||||
const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5.0f * 1000.0f;
|
|
||||||
|
|
||||||
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
||||||
// to properly follow avatar size.
|
// to properly follow avatar size.
|
||||||
float DEFAULT_MOTOR_TIMESCALE = 0.25f;
|
float DEFAULT_MOTOR_TIMESCALE = 0.25f;
|
||||||
|
@ -83,11 +81,6 @@ MyAvatar::MyAvatar() :
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||||
_driveKeys[i] = 0.0f;
|
_driveKeys[i] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update our location every 5 seconds in the data-server, assuming that we are authenticated with one
|
|
||||||
QTimer* locationUpdateTimer = new QTimer(this);
|
|
||||||
connect(locationUpdateTimer, &QTimer::timeout, this, &MyAvatar::updateLocationInDataServer);
|
|
||||||
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar::~MyAvatar() {
|
MyAvatar::~MyAvatar() {
|
||||||
|
@ -237,7 +230,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
void MyAvatar::updateFromTrackers(float deltaTime) {
|
void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||||
glm::vec3 estimatedPosition, estimatedRotation;
|
glm::vec3 estimatedPosition, estimatedRotation;
|
||||||
|
|
||||||
if (Application::getInstance()->getPrioVR()->isActive()) {
|
if (Application::getInstance()->getPrioVR()->hasHeadRotation()) {
|
||||||
estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation()));
|
estimatedRotation = glm::degrees(safeEulerAngles(Application::getInstance()->getPrioVR()->getHeadRotation()));
|
||||||
estimatedRotation.x *= -1.0f;
|
estimatedRotation.x *= -1.0f;
|
||||||
estimatedRotation.z *= -1.0f;
|
estimatedRotation.z *= -1.0f;
|
||||||
|
@ -1434,29 +1427,6 @@ void MyAvatar::resetSize() {
|
||||||
qDebug("Reseted scale to %f", _targetScale);
|
qDebug("Reseted scale to %f", _targetScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray createByteArray(const glm::vec3& vector) {
|
|
||||||
return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::updateLocationInDataServer() {
|
|
||||||
// TODO: don't re-send this when it hasn't change or doesn't change by some threshold
|
|
||||||
// This will required storing the last sent values and clearing them when the AccountManager rootURL changes
|
|
||||||
|
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
|
||||||
|
|
||||||
if (accountManager.isLoggedIn()) {
|
|
||||||
QString positionString(createByteArray(_position));
|
|
||||||
QString orientationString(createByteArray(glm::degrees(safeEulerAngles(getOrientation()))));
|
|
||||||
|
|
||||||
// construct the json to put the user's location
|
|
||||||
QString locationPutJson = QString() + "{\"address\":{\"position\":\""
|
|
||||||
+ positionString + "\", \"orientation\":\"" + orientationString + "\"}}";
|
|
||||||
|
|
||||||
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
|
|
||||||
JSONCallbackParameters(), locationPutJson.toUtf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
|
void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
|
||||||
|
|
||||||
if (jsonObject["status"].toString() == "success") {
|
if (jsonObject["status"].toString() == "success") {
|
||||||
|
|
|
@ -108,7 +108,6 @@ public slots:
|
||||||
void decreaseSize();
|
void decreaseSize();
|
||||||
void resetSize();
|
void resetSize();
|
||||||
|
|
||||||
void updateLocationInDataServer();
|
|
||||||
void goToLocationFromResponse(const QJsonObject& jsonObject);
|
void goToLocationFromResponse(const QJsonObject& jsonObject);
|
||||||
|
|
||||||
// Set/Get update the thrust that will move the avatar around
|
// Set/Get update the thrust that will move the avatar around
|
||||||
|
|
|
@ -164,7 +164,8 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||||
|
|
||||||
// rotate palm to align with its normal (normal points out of hand's palm)
|
// rotate palm to align with its normal (normal points out of hand's palm)
|
||||||
glm::quat palmRotation;
|
glm::quat palmRotation;
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
||||||
getJointRotation(parentJointIndex, palmRotation, true);
|
getJointRotation(parentJointIndex, palmRotation, true);
|
||||||
} else {
|
} else {
|
||||||
getJointRotation(jointIndex, palmRotation, true);
|
getJointRotation(jointIndex, palmRotation, true);
|
||||||
|
@ -176,7 +177,10 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||||
palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation;
|
palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation;
|
||||||
|
|
||||||
// set hand position, rotation
|
// set hand position, rotation
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) {
|
||||||
|
setHandPosition(jointIndex, palm.getPosition(), palmRotation);
|
||||||
|
|
||||||
|
} else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
|
||||||
glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f);
|
glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f);
|
||||||
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
|
||||||
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale));
|
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale));
|
||||||
|
@ -276,3 +280,68 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
|
||||||
glLineWidth(1.0f);
|
glLineWidth(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation) {
|
||||||
|
// this algorithm is from sample code from sixense
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex;
|
||||||
|
if (elbowJointIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex;
|
||||||
|
glm::vec3 shoulderPosition;
|
||||||
|
if (!getJointPosition(shoulderJointIndex, shoulderPosition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// precomputed lengths
|
||||||
|
float scale = extractUniformScale(_scale);
|
||||||
|
float upperArmLength = geometry.joints.at(elbowJointIndex).distanceToParent * scale;
|
||||||
|
float lowerArmLength = geometry.joints.at(jointIndex).distanceToParent * scale;
|
||||||
|
|
||||||
|
// first set wrist position
|
||||||
|
glm::vec3 wristPosition = position;
|
||||||
|
|
||||||
|
glm::vec3 shoulderToWrist = wristPosition - shoulderPosition;
|
||||||
|
float distanceToWrist = glm::length(shoulderToWrist);
|
||||||
|
|
||||||
|
// prevent gimbal lock
|
||||||
|
if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) {
|
||||||
|
distanceToWrist = upperArmLength + lowerArmLength - EPSILON;
|
||||||
|
shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist;
|
||||||
|
wristPosition = shoulderPosition + shoulderToWrist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cosine of angle from upper arm to hand vector
|
||||||
|
float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) /
|
||||||
|
(2 * upperArmLength * distanceToWrist);
|
||||||
|
float mid = upperArmLength * cosA;
|
||||||
|
float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA);
|
||||||
|
|
||||||
|
// direction of the elbow
|
||||||
|
glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist
|
||||||
|
glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down
|
||||||
|
const float NORMAL_WEIGHT = 0.5f;
|
||||||
|
glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT);
|
||||||
|
|
||||||
|
bool rightHand = (jointIndex == geometry.rightHandJointIndex);
|
||||||
|
if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) {
|
||||||
|
finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal));
|
||||||
|
|
||||||
|
// ik solution
|
||||||
|
glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height;
|
||||||
|
|
||||||
|
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
glm::quat shoulderRotation;
|
||||||
|
getJointRotation(shoulderJointIndex, shoulderRotation, true);
|
||||||
|
applyRotationDelta(shoulderJointIndex, rotationBetween(shoulderRotation * forwardVector, elbowPosition - shoulderPosition), false);
|
||||||
|
|
||||||
|
glm::quat elbowRotation;
|
||||||
|
getJointRotation(elbowJointIndex, elbowRotation, true);
|
||||||
|
applyRotationDelta(elbowJointIndex, rotationBetween(elbowRotation * forwardVector, wristPosition - elbowPosition), false);
|
||||||
|
|
||||||
|
setJointRotation(jointIndex, rotation, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void renderJointConstraints(int jointIndex);
|
void renderJointConstraints(int jointIndex);
|
||||||
|
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
|
||||||
|
|
||||||
Avatar* _owningAvatar;
|
Avatar* _owningAvatar;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,7 @@ PrioVR::PrioVR() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_jointRotations.resize(LIST_LENGTH);
|
_jointRotations.resize(LIST_LENGTH);
|
||||||
|
_lastJointRotations.resize(LIST_LENGTH);
|
||||||
for (int i = 0; i < LIST_LENGTH; i++) {
|
for (int i = 0; i < LIST_LENGTH; i++) {
|
||||||
_humanIKJointIndices.append(jointsDiscovered[i] ? indexOfHumanIKJoint(JOINT_NAMES[i]) : -1);
|
_humanIKJointIndices.append(jointsDiscovered[i] ? indexOfHumanIKJoint(JOINT_NAMES[i]) : -1);
|
||||||
}
|
}
|
||||||
|
@ -62,8 +63,13 @@ PrioVR::~PrioVR() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat PrioVR::getHeadRotation() const {
|
const int HEAD_ROTATION_INDEX = 0;
|
||||||
const int HEAD_ROTATION_INDEX = 0;
|
|
||||||
|
bool PrioVR::hasHeadRotation() const {
|
||||||
|
return _humanIKJointIndices.size() > HEAD_ROTATION_INDEX && _humanIKJointIndices.at(HEAD_ROTATION_INDEX) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat PrioVR::getHeadRotation() const {
|
||||||
return _jointRotations.size() > HEAD_ROTATION_INDEX ? _jointRotations.at(HEAD_ROTATION_INDEX) : glm::quat();
|
return _jointRotations.size() > HEAD_ROTATION_INDEX ? _jointRotations.at(HEAD_ROTATION_INDEX) : glm::quat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +87,14 @@ void PrioVR::update() {
|
||||||
yei_getLastStreamDataAll(_skeletalDevice, (char*)_jointRotations.data(),
|
yei_getLastStreamDataAll(_skeletalDevice, (char*)_jointRotations.data(),
|
||||||
_jointRotations.size() * sizeof(glm::quat), ×tamp);
|
_jointRotations.size() * sizeof(glm::quat), ×tamp);
|
||||||
|
|
||||||
// convert to our expected coordinate system
|
// convert to our expected coordinate system, average with last rotations to smooth
|
||||||
for (int i = 0; i < _jointRotations.size(); i++) {
|
for (int i = 0; i < _jointRotations.size(); i++) {
|
||||||
_jointRotations[i].y *= -1.0f;
|
_jointRotations[i].y *= -1.0f;
|
||||||
_jointRotations[i].z *= -1.0f;
|
_jointRotations[i].z *= -1.0f;
|
||||||
|
|
||||||
|
glm::quat lastRotation = _lastJointRotations.at(i);
|
||||||
|
_lastJointRotations[i] = _jointRotations.at(i);
|
||||||
|
_jointRotations[i] = safeMix(lastRotation, _jointRotations.at(i), 0.5f);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ public:
|
||||||
|
|
||||||
bool isActive() const { return !_jointRotations.isEmpty(); }
|
bool isActive() const { return !_jointRotations.isEmpty(); }
|
||||||
|
|
||||||
|
bool hasHeadRotation() const;
|
||||||
|
|
||||||
glm::quat getHeadRotation() const;
|
glm::quat getHeadRotation() const;
|
||||||
glm::quat getTorsoRotation() const;
|
glm::quat getTorsoRotation() const;
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ private:
|
||||||
|
|
||||||
QVector<int> _humanIKJointIndices;
|
QVector<int> _humanIKJointIndices;
|
||||||
QVector<glm::quat> _jointRotations;
|
QVector<glm::quat> _jointRotations;
|
||||||
|
QVector<glm::quat> _lastJointRotations;
|
||||||
|
|
||||||
QDateTime _calibrationCountdownStarted;
|
QDateTime _calibrationCountdownStarted;
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,6 +74,7 @@ Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||||
|
args->_elementsTouched++;
|
||||||
// actually render it here...
|
// actually render it here...
|
||||||
// we need to iterate the actual modelItems of the element
|
// we need to iterate the actual modelItems of the element
|
||||||
ModelTreeElement* modelTreeElement = (ModelTreeElement*)element;
|
ModelTreeElement* modelTreeElement = (ModelTreeElement*)element;
|
||||||
|
@ -165,7 +166,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
|
|
||||||
bool drawAsModel = modelItem.hasModel();
|
bool drawAsModel = modelItem.hasModel();
|
||||||
|
|
||||||
args->_renderedItems++;
|
args->_itemsRendered++;
|
||||||
|
|
||||||
if (drawAsModel) {
|
if (drawAsModel) {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
@ -220,6 +221,8 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
glutSolidSphere(radius, 15, 15);
|
glutSolidSphere(radius, 15, 15);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
args->_itemsOutOfView++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
|
||||||
|
|
||||||
bool drawAsModel = particle.hasModel();
|
bool drawAsModel = particle.hasModel();
|
||||||
|
|
||||||
args->_renderedItems++;
|
args->_itemsRendered++;
|
||||||
|
|
||||||
if (drawAsModel) {
|
if (drawAsModel) {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
|
@ -23,7 +23,8 @@ Overlay::Overlay() :
|
||||||
_parent(NULL),
|
_parent(NULL),
|
||||||
_alpha(DEFAULT_ALPHA),
|
_alpha(DEFAULT_ALPHA),
|
||||||
_color(DEFAULT_BACKGROUND_COLOR),
|
_color(DEFAULT_BACKGROUND_COLOR),
|
||||||
_visible(true)
|
_visible(true),
|
||||||
|
_anchor(NO_ANCHOR)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +52,15 @@ void Overlay::setProperties(const QScriptValue& properties) {
|
||||||
if (properties.property("alpha").isValid()) {
|
if (properties.property("alpha").isValid()) {
|
||||||
setAlpha(properties.property("alpha").toVariant().toFloat());
|
setAlpha(properties.property("alpha").toVariant().toFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.property("visible").isValid()) {
|
if (properties.property("visible").isValid()) {
|
||||||
setVisible(properties.property("visible").toVariant().toBool());
|
setVisible(properties.property("visible").toVariant().toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.property("anchor").isValid()) {
|
||||||
|
QString property = properties.property("anchor").toVariant().toString();
|
||||||
|
if (property == "MyAvatar") {
|
||||||
|
setAnchor(MY_AVATAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ class Overlay : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Anchor {
|
||||||
|
NO_ANCHOR,
|
||||||
|
MY_AVATAR
|
||||||
|
};
|
||||||
|
|
||||||
Overlay();
|
Overlay();
|
||||||
~Overlay();
|
~Overlay();
|
||||||
void init(QGLWidget* parent);
|
void init(QGLWidget* parent);
|
||||||
|
@ -38,11 +43,13 @@ public:
|
||||||
bool getVisible() const { return _visible; }
|
bool getVisible() const { return _visible; }
|
||||||
const xColor& getColor() const { return _color; }
|
const xColor& getColor() const { return _color; }
|
||||||
float getAlpha() const { return _alpha; }
|
float getAlpha() const { return _alpha; }
|
||||||
|
Anchor getAnchor() const { return _anchor; }
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setVisible(bool visible) { _visible = visible; }
|
void setVisible(bool visible) { _visible = visible; }
|
||||||
void setColor(const xColor& color) { _color = color; }
|
void setColor(const xColor& color) { _color = color; }
|
||||||
void setAlpha(float alpha) { _alpha = alpha; }
|
void setAlpha(float alpha) { _alpha = alpha; }
|
||||||
|
void setAnchor(Anchor anchor) { _anchor = anchor; }
|
||||||
|
|
||||||
virtual void setProperties(const QScriptValue& properties);
|
virtual void setProperties(const QScriptValue& properties);
|
||||||
|
|
||||||
|
@ -51,6 +58,7 @@ protected:
|
||||||
float _alpha;
|
float _alpha;
|
||||||
xColor _color;
|
xColor _color;
|
||||||
bool _visible; // should the overlay be drawn at all
|
bool _visible; // should the overlay be drawn at all
|
||||||
|
Anchor _anchor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
|
||||||
#include "Cube3DOverlay.h"
|
#include "Cube3DOverlay.h"
|
||||||
#include "ImageOverlay.h"
|
#include "ImageOverlay.h"
|
||||||
|
@ -57,8 +58,19 @@ void Overlays::render2D() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::render3D() {
|
void Overlays::render3D() {
|
||||||
|
glm::vec3 myAvatarPosition = Application::getInstance()->getAvatar()->getPosition();
|
||||||
|
|
||||||
foreach(Overlay* thisOverlay, _overlays3D) {
|
foreach(Overlay* thisOverlay, _overlays3D) {
|
||||||
|
glPushMatrix();
|
||||||
|
switch (thisOverlay->getAnchor()) {
|
||||||
|
case Overlay::MY_AVATAR:
|
||||||
|
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
thisOverlay->render();
|
thisOverlay->render();
|
||||||
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,11 +491,12 @@ void ModelTree::update() {
|
||||||
lockForWrite();
|
lockForWrite();
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
|
|
||||||
ModelTreeUpdateArgs args = { };
|
ModelTreeUpdateArgs args;
|
||||||
recurseTreeWithOperation(updateOperation, &args);
|
recurseTreeWithOperation(updateOperation, &args);
|
||||||
|
|
||||||
// now add back any of the particles that moved elements....
|
// now add back any of the particles that moved elements....
|
||||||
int movingModels = args._movingModels.size();
|
int movingModels = args._movingModels.size();
|
||||||
|
|
||||||
for (int i = 0; i < movingModels; i++) {
|
for (int i = 0; i < movingModels; i++) {
|
||||||
bool shouldDie = args._movingModels[i].getShouldDie();
|
bool shouldDie = args._movingModels[i].getShouldDie();
|
||||||
|
|
||||||
|
@ -553,7 +554,7 @@ bool ModelTree::encodeModelsDeletedSince(quint64& sinceTime, unsigned char* outp
|
||||||
memcpy(copyAt, &numberOfIds, sizeof(numberOfIds));
|
memcpy(copyAt, &numberOfIds, sizeof(numberOfIds));
|
||||||
copyAt += sizeof(numberOfIds);
|
copyAt += sizeof(numberOfIds);
|
||||||
outputLength += sizeof(numberOfIds);
|
outputLength += sizeof(numberOfIds);
|
||||||
|
|
||||||
// we keep a multi map of model IDs to timestamps, we only want to include the model IDs that have been
|
// we keep a multi map of model IDs to timestamps, we only want to include the model IDs that have been
|
||||||
// deleted since we last sent to this node
|
// deleted since we last sent to this node
|
||||||
_recentlyDeletedModelsLock.lockForRead();
|
_recentlyDeletedModelsLock.lockForRead();
|
||||||
|
@ -595,7 +596,6 @@ bool ModelTree::encodeModelsDeletedSince(quint64& sinceTime, unsigned char* outp
|
||||||
|
|
||||||
// replace the correct count for ids included
|
// replace the correct count for ids included
|
||||||
memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds));
|
memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds));
|
||||||
|
|
||||||
return hasMoreToSend;
|
return hasMoreToSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,14 +84,17 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelTreeElement::containsModelBounds(const ModelItem& model) const {
|
bool ModelTreeElement::containsModelBounds(const ModelItem& model) const {
|
||||||
return _box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint());
|
glm::vec3 clampedMin = glm::clamp(model.getMinimumPoint(), 0.0f, 1.0f);
|
||||||
|
glm::vec3 clampedMax = glm::clamp(model.getMaximumPoint(), 0.0f, 1.0f);
|
||||||
|
return _box.contains(clampedMin) && _box.contains(clampedMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const {
|
bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const {
|
||||||
if (_box.contains(model.getMinimumPoint()) && _box.contains(model.getMaximumPoint())) {
|
glm::vec3 clampedMin = glm::clamp(model.getMinimumPoint(), 0.0f, 1.0f);
|
||||||
int childForMinimumPoint = getMyChildContainingPoint(model.getMinimumPoint());
|
glm::vec3 clampedMax = glm::clamp(model.getMaximumPoint(), 0.0f, 1.0f);
|
||||||
int childForMaximumPoint = getMyChildContainingPoint(model.getMaximumPoint());
|
if (_box.contains(clampedMin) && _box.contains(clampedMax)) {
|
||||||
|
int childForMinimumPoint = getMyChildContainingPoint(clampedMin);
|
||||||
|
int childForMaximumPoint = getMyChildContainingPoint(clampedMax);
|
||||||
// If I contain both the minimum and maximum point, but two different children of mine
|
// If I contain both the minimum and maximum point, but two different children of mine
|
||||||
// contain those points, then I am the best fit for that model
|
// contain those points, then I am the best fit for that model
|
||||||
if (childForMinimumPoint != childForMaximumPoint) {
|
if (childForMinimumPoint != childForMaximumPoint) {
|
||||||
|
@ -102,10 +105,12 @@ bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
||||||
|
args._totalElements++;
|
||||||
// update our contained models
|
// update our contained models
|
||||||
QList<ModelItem>::iterator modelItr = _modelItems->begin();
|
QList<ModelItem>::iterator modelItr = _modelItems->begin();
|
||||||
while(modelItr != _modelItems->end()) {
|
while(modelItr != _modelItems->end()) {
|
||||||
ModelItem& model = (*modelItr);
|
ModelItem& model = (*modelItr);
|
||||||
|
args._totalItems++;
|
||||||
|
|
||||||
// TODO: this _lastChanged isn't actually changing because we're not marking this element as changed.
|
// TODO: this _lastChanged isn't actually changing because we're not marking this element as changed.
|
||||||
// how do we want to handle this??? We really only want to consider an element changed when it is
|
// how do we want to handle this??? We really only want to consider an element changed when it is
|
||||||
|
@ -119,6 +124,8 @@ void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
|
||||||
|
|
||||||
// erase this model
|
// erase this model
|
||||||
modelItr = _modelItems->erase(modelItr);
|
modelItr = _modelItems->erase(modelItr);
|
||||||
|
|
||||||
|
args._movingItems++;
|
||||||
|
|
||||||
// this element has changed so mark it...
|
// this element has changed so mark it...
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
|
|
@ -23,7 +23,16 @@ class ModelTreeElement;
|
||||||
|
|
||||||
class ModelTreeUpdateArgs {
|
class ModelTreeUpdateArgs {
|
||||||
public:
|
public:
|
||||||
|
ModelTreeUpdateArgs() :
|
||||||
|
_totalElements(0),
|
||||||
|
_totalItems(0),
|
||||||
|
_movingItems(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
QList<ModelItem> _movingModels;
|
QList<ModelItem> _movingModels;
|
||||||
|
int _totalElements;
|
||||||
|
int _totalItems;
|
||||||
|
int _movingItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FindAndUpdateModelItemIDArgs {
|
class FindAndUpdateModelItemIDArgs {
|
||||||
|
@ -63,7 +72,11 @@ public:
|
||||||
|
|
||||||
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
||||||
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
||||||
virtual bool hasContent() const { return isLeaf(); }
|
virtual bool hasContent() const { return hasModels(); }
|
||||||
|
|
||||||
|
/// Should this element be considered to have detailed content in it. Specifically should it be rendered.
|
||||||
|
/// By default we assume that only leaves have detailed content, but some octrees may have different semantics.
|
||||||
|
virtual bool hasDetailedContent() const { return hasModels(); }
|
||||||
|
|
||||||
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
||||||
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
||||||
|
@ -92,7 +105,7 @@ public:
|
||||||
|
|
||||||
const QList<ModelItem>& getModels() const { return *_modelItems; }
|
const QList<ModelItem>& getModels() const { return *_modelItems; }
|
||||||
QList<ModelItem>& getModels() { return *_modelItems; }
|
QList<ModelItem>& getModels() { return *_modelItems; }
|
||||||
bool hasModels() const { return _modelItems->size() > 0; }
|
bool hasModels() const { return _modelItems ? _modelItems->size() > 0 : false; }
|
||||||
|
|
||||||
void update(ModelTreeUpdateArgs& args);
|
void update(ModelTreeUpdateArgs& args);
|
||||||
void setTree(ModelTree* tree) { _myTree = tree; }
|
void setTree(ModelTree* tree) { _myTree = tree; }
|
||||||
|
|
|
@ -1213,7 +1213,7 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float
|
||||||
float furthestDistance = furthestDistanceToCamera(*viewFrustum);
|
float furthestDistance = furthestDistanceToCamera(*viewFrustum);
|
||||||
float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize);
|
float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize);
|
||||||
bool inChildBoundary = (furthestDistance <= childBoundary);
|
bool inChildBoundary = (furthestDistance <= childBoundary);
|
||||||
if (isLeaf() && inChildBoundary) {
|
if (hasDetailedContent() && inChildBoundary) {
|
||||||
shouldRender = true;
|
shouldRender = true;
|
||||||
} else {
|
} else {
|
||||||
float boundary = childBoundary * 2.0f; // the boundary is always twice the distance of the child boundary
|
float boundary = childBoundary * 2.0f; // the boundary is always twice the distance of the child boundary
|
||||||
|
|
|
@ -71,6 +71,10 @@ public:
|
||||||
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
||||||
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
||||||
virtual bool hasContent() const { return isLeaf(); }
|
virtual bool hasContent() const { return isLeaf(); }
|
||||||
|
|
||||||
|
/// Should this element be considered to have detailed content in it. Specifically should it be rendered.
|
||||||
|
/// By default we assume that only leaves have detailed content, but some octrees may have different semantics.
|
||||||
|
virtual bool hasDetailedContent() const { return isLeaf(); }
|
||||||
|
|
||||||
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
||||||
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
||||||
|
|
|
@ -156,7 +156,7 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeRenderer::render(RenderMode renderMode) {
|
void OctreeRenderer::render(RenderMode renderMode) {
|
||||||
RenderArgs args = { 0, this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode };
|
RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, 0, 0, 0 };
|
||||||
if (_tree) {
|
if (_tree) {
|
||||||
_tree->lockForRead();
|
_tree->lockForRead();
|
||||||
_tree->recurseTreeWithOperation(renderOperation, &args);
|
_tree->recurseTreeWithOperation(renderOperation, &args);
|
||||||
|
|
|
@ -71,12 +71,15 @@ protected:
|
||||||
|
|
||||||
class RenderArgs {
|
class RenderArgs {
|
||||||
public:
|
public:
|
||||||
int _renderedItems;
|
|
||||||
OctreeRenderer* _renderer;
|
OctreeRenderer* _renderer;
|
||||||
ViewFrustum* _viewFrustum;
|
ViewFrustum* _viewFrustum;
|
||||||
float _sizeScale;
|
float _sizeScale;
|
||||||
int _boundaryLevelAdjust;
|
int _boundaryLevelAdjust;
|
||||||
OctreeRenderer::RenderMode _renderMode;
|
OctreeRenderer::RenderMode _renderMode;
|
||||||
|
|
||||||
|
int _elementsTouched;
|
||||||
|
int _itemsRendered;
|
||||||
|
int _itemsOutOfView;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -828,3 +828,7 @@ bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, f
|
||||||
float positionDistance = glm::distance(positionA, positionB);
|
float positionDistance = glm::distance(positionA, positionB);
|
||||||
return (positionDistance <= similarEnough);
|
return (positionDistance <= similarEnough);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray createByteArray(const glm::vec3& vector) {
|
||||||
|
return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z);
|
||||||
|
}
|
||||||
|
|
|
@ -187,4 +187,6 @@ bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, f
|
||||||
/// \return bool is the float NaN
|
/// \return bool is the float NaN
|
||||||
bool isNaN(float value);
|
bool isNaN(float value);
|
||||||
|
|
||||||
|
QByteArray createByteArray(const glm::vec3& vector);
|
||||||
|
|
||||||
#endif // hifi_SharedUtil_h
|
#endif // hifi_SharedUtil_h
|
||||||
|
|
Loading…
Reference in a new issue