mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into seeing_voxels
This commit is contained in:
commit
8d53fc9671
16 changed files with 169 additions and 58 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue