Merge branch 'master' of https://github.com/worklist/hifi into seeing_voxels

This commit is contained in:
ZappoMan 2014-02-27 01:05:20 -08:00
commit 8d53fc9671
16 changed files with 169 additions and 58 deletions

View file

@ -3,6 +3,7 @@
// hifi
//
// Created by Stephen Birarda on 2/20/14.
// Modified by Philip on 2/26/14
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
// This is an example script that demonstrates an NPC avatar.
@ -17,22 +18,64 @@ function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// choose a random x and y in the range of 0 to 50
positionX = getRandomFloat(0, 18);
positionZ = getRandomFloat(0, 18);
var CHANCE_OF_MOVING = 0.005;
var CHANCE_OF_SOUND = 0.005;
var CHANCE_OF_HEAD_TURNING = 0.05;
var CHANCE_OF_BIG_MOVE = 0.1;
var isMoving = false;
var isTurningHead = false;
var STARTING_RANGE = 18.0;
var MAX_RANGE = 25.0;
var MOVE_RANGE_SMALL = 0.5;
var MOVE_RANGE_BIG = 5.0;
var TURN_RANGE = 45.0;
var STOP_TOLERANCE = 0.05;
var MOVE_RATE = 0.05;
var TURN_RATE = 0.15;
var PITCH_RATE = 0.20;
var PITCH_RANGE = 30.0;
var firstPosition = { x: getRandomFloat(0, STARTING_RANGE), y: 0, z: getRandomFloat(0, STARTING_RANGE) };
var targetPosition = { x: 0, y: 0, z: 0 };
var targetDirection = { x: 0, y: 0, z: 0, w: 0 };
var currentDirection = { x: 0, y: 0, z: 0, w: 0 };
var targetHeadPitch = 0.0;
var sounds = [];
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh1.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh2.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh3.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh4.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh5.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh6.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh7.raw"));
sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh8.raw"));
// Play a random sound from a list of conversational audio clips
function playRandomSound(position) {
var whichSound = Math.floor((Math.random() * sounds.length) % sounds.length);
var audioOptions = new AudioInjectionOptions();
audioOptions.volume = 0.25 + (Math.random() * 0.75);
audioOptions.position = position;
Audio.playSound(sounds[whichSound], audioOptions);
print("PlaySound " + whichSound);
}
// change the avatar's position to the random one
Avatar.position = {x: positionX, y: 0, z: positionZ};
Avatar.position = firstPosition;
// pick an integer between 1 and 20 for the face model for this bot
botNumber = getRandomInt(1, 100);
newBodyFilePrefix = "defaultAvatar";
if (botNumber <= 20) {
newFaceFilePrefix = "bot" + botNumber;
newBodyFilePrefix = "defaultAvatar_body"
} else {
if (botNumber <= 40) {
newFaceFilePrefix = "superhero";
} else if (botNumber <= 60) {
@ -52,4 +95,43 @@ Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/me
Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + ".fst";
Avatar.billboardURL = "https://dl.dropboxusercontent.com/u/1864924/bot-billboard.png";
Agent.isAvatar = true;
Agent.isAvatar = true;
function updateBehavior() {
if (Math.random() < CHANCE_OF_SOUND) {
playRandomSound(Avatar.position);
}
if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) {
targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE);
isTurningHead = true;
} else {
Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * PITCH_RATE;
if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE) {
isTurningHead = false;
}
}
if (!isMoving && (Math.random() < CHANCE_OF_MOVING)) {
// Set new target location
targetDirection = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 }));
var front = Quat.getFront(targetDirection);
if (Math.random() < CHANCE_OF_BIG_MOVE) {
targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_BIG)));
} else {
targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_SMALL)));
}
isMoving = true;
} else {
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE));
Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE);
if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) {
isMoving = false;
}
}
if (Vec3.length(Avatar.position) > MAX_RANGE) {
// Don't let our happy little person get out of the cage
isMoving = false;
Avatar.position = { x: 0, y: 0, z: 0 };
}
}
Script.willSendVisualDataCallback.connect(updateBehavior);

View file

@ -79,7 +79,8 @@ var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-publi
var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete+2.raw");
var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit+2.raw");
var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw");
var audioOptions = new AudioInjectionOptions();
var audioOptions = new AudioInjectionOptions();
audioOptions.volume = 0.5;
audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ); // start with audio slightly above the avatar

View file

@ -1487,8 +1487,7 @@ void Application::init() {
_myCamera.setModeShiftPeriod(1.0f);
_mirrorCamera.setMode(CAMERA_MODE_MIRROR);
_mirrorCamera.setAspectRatio((float)MIRROR_VIEW_WIDTH / (float)MIRROR_VIEW_HEIGHT);
_mirrorCamera.setFieldOfView(30);
_mirrorCamera.setModeShiftPeriod(0.0f);
OculusManager::connect();
if (OculusManager::isConnected()) {
@ -3368,9 +3367,9 @@ void Application::connectedToDomain(const QString& hostname) {
if (accountManager.isLoggedIn()) {
// update our domain-server with the data-server we're logged in with
QString domainPutJsonString = "{\"location\":{\"domain\":\"" + hostname + "\"}}";
QString domainPutJsonString = "{\"address\":{\"domain\":\"" + hostname + "\"}}";
accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation,
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), domainPutJsonString.toUtf8());
}
}

View file

@ -280,6 +280,7 @@ void Audio::start() {
// setup our general output device for audio-mixer audio
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
_audioOutput->setBufferSize(_ringBuffer.getSampleCapacity() * sizeof(int16_t));
_outputDevice = _audioOutput->start();
// setup a loopback audio output device
@ -556,7 +557,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
// if there is anything in the ring buffer, decide what to do
if (_ringBuffer.samplesAvailable() > 0) {
int numNetworkOutputSamples = _ringBuffer.samplesAvailable();
int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio;

View file

@ -126,7 +126,7 @@ void Camera::setModeShiftPeriod (float period) {
// if a zero period was requested, we clearly want to snap immediately to the target
if (period == 0.0f) {
update(MIN_PERIOD);
update(MAX_PERIOD);
}
}

View file

@ -993,7 +993,7 @@ void Menu::goTo() {
callbackParams.jsonCallbackMethod = "goToLocationFromResponse";
// there's a username entered by the user, make a request to the data-server for the associated location
AccountManager::getInstance().authenticatedRequest("/api/v1/users/" + gotoDialog.textValue() + "/location",
AccountManager::getInstance().authenticatedRequest("/api/v1/users/" + gotoDialog.textValue() + "/address",
QNetworkAccessManager::GetOperation,
callbackParams);
}

View file

@ -104,36 +104,7 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
return glm::angleAxis(angle, axis);
}
// Safe version of glm::mix; based on the code in Nick Bobick's article,
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
// adjust signs if necessary
if (cosa < 0.0f) {
cosa = -cosa;
ox = -ox;
oy = -oy;
oz = -oz;
ow = -ow;
}
// calculate coefficients; if the angle is too close to zero, we must fall back
// to linear interpolation
if ((1.0f - cosa) > EPSILON) {
float angle = acosf(cosa), sina = sinf(angle);
s0 = sinf((1.0f - proportion) * angle) / sina;
s1 = sinf(proportion * angle) / sina;
} else {
s0 = 1.0f - proportion;
s1 = proportion;
}
return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
}
glm::vec3 extractTranslation(const glm::mat4& matrix) {
return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);

View file

@ -45,8 +45,6 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
glm::vec3 extractTranslation(const glm::mat4& matrix);
void setTranslation(glm::mat4& matrix, const glm::vec3& translation);

View file

@ -1139,10 +1139,10 @@ void MyAvatar::updateLocationInDataServer() {
QString orientationString(createByteArray(safeEulerAngles(getOrientation())));
// construct the json to put the user's location
QString locationPutJson = QString() + "{\"location\":{\"position\":\""
QString locationPutJson = QString() + "{\"address\":{\"position\":\""
+ positionString + "\", \"orientation\":\"" + orientationString + "\"}}";
accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation,
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), locationPutJson.toUtf8());
}
}
@ -1154,7 +1154,7 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
sendKillAvatar();
QJsonObject locationObject = jsonObject["data"].toObject()["location"].toObject();
QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject();
QString positionString = locationObject["position"].toString();
QString orientationString = locationObject["orientation"].toString();
QString domainHostnameString = locationObject["domain"].toString();

View file

@ -1249,7 +1249,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
joint.boneRadius = 0.0f;
joint.inverseBindRotation = joint.inverseDefaultRotation;
geometry.joints.append(joint);
geometry.jointIndices.insert(model.name, geometry.joints.size() - 1);
geometry.jointIndices.insert(model.name, geometry.joints.size());
}
// find our special joints

View file

@ -46,6 +46,17 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
program.release();
}
QVector<Model::JointState> Model::createJointStates(const FBXGeometry& geometry) {
QVector<JointState> jointStates;
foreach (const FBXJoint& joint, geometry.joints) {
JointState state;
state.translation = joint.translation;
state.rotation = joint.rotation;
jointStates.append(state);
}
return jointStates;
}
bool Model::isLoadedWithTextures() const {
if (!isActive()) {
return false;
@ -106,9 +117,23 @@ void Model::reset() {
void Model::simulate(float deltaTime) {
// update our LOD
QVector<JointState> newJointStates;
if (_geometry) {
QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis);
if (_geometry != geometry) {
if (!_jointStates.isEmpty()) {
// copy the existing joint states
const FBXGeometry& oldGeometry = _geometry->getFBXGeometry();
const FBXGeometry& newGeometry = geometry->getFBXGeometry();
newJointStates = createJointStates(newGeometry);
for (QHash<QString, int>::const_iterator it = oldGeometry.jointIndices.constBegin();
it != oldGeometry.jointIndices.constEnd(); it++) {
int newIndex = newGeometry.jointIndices.value(it.key());
if (newIndex != 0) {
newJointStates[newIndex - 1] = _jointStates.at(it.value() - 1);
}
}
}
deleteGeometry();
_dilatedTextures.clear();
_geometry = geometry;
@ -121,12 +146,7 @@ void Model::simulate(float deltaTime) {
// set up world vertices on first simulate after load
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (_jointStates.isEmpty()) {
foreach (const FBXJoint& joint, geometry.joints) {
JointState state;
state.translation = joint.translation;
state.rotation = joint.rotation;
_jointStates.append(state);
}
_jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates;
foreach (const FBXMesh& mesh, geometry.meshes) {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());

View file

@ -269,6 +269,7 @@ private:
static SkinLocations _skinNormalMapLocations;
static void initSkinProgram(ProgramObject& program, SkinLocations& locations);
static QVector<JointState> createJointStates(const FBXGeometry& geometry);
};
#endif /* defined(__interface__Model__) */

View file

@ -15,6 +15,7 @@
#include <SharedUtil.h>
#include "Quat.h"
glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) {
return q1 * q2;
}
@ -31,7 +32,6 @@ glm::quat Quat::inverse(const glm::quat& q) {
return glm::inverse(q);
}
glm::vec3 Quat::getFront(const glm::quat& orientation) {
return orientation * IDENTITY_FRONT;
}
@ -52,3 +52,7 @@ glm::quat Quat::angleAxis(float angle, const glm::vec3& v) {
return glm::angleAxis(angle, v);
}
glm::quat Quat::mix(const glm::quat& q1, const glm::quat& q2, float alpha) {
return safeMix(q1, q2, alpha);
}

View file

@ -29,6 +29,7 @@ public slots:
glm::vec3 getUp(const glm::quat& orientation);
glm::vec3 safeEulerAngles(const glm::quat& orientation);
glm::quat angleAxis(float angle, const glm::vec3& v);
glm::quat mix(const glm::quat& q1, const glm::quat& q2, float alpha);
};
#endif /* defined(__hifi__Quat__) */

View file

@ -65,6 +65,38 @@ bool shouldDo(float desiredInterval, float deltaTime) {
return randFloat() < deltaTime / desiredInterval;
}
// Safe version of glm::mix; based on the code in Nick Bobick's article,
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
// adjust signs if necessary
if (cosa < 0.0f) {
cosa = -cosa;
ox = -ox;
oy = -oy;
oz = -oz;
ow = -ow;
}
// calculate coefficients; if the angle is too close to zero, we must fall back
// to linear interpolation
if ((1.0f - cosa) > EPSILON) {
float angle = acosf(cosa), sina = sinf(angle);
s0 = sinf((1.0f - proportion) * angle) / sina;
s1 = sinf(proportion * angle) / sina;
} else {
s0 = 1.0f - proportion;
s1 = proportion;
}
return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
}
void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {

View file

@ -75,6 +75,8 @@ float randFloatInRange (float min,float max);
unsigned char randomColorValue(int minimum);
bool randomBoolean();
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
bool shouldDo(float desiredInterval, float deltaTime);
void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL);