Merge branch 'master' of https://github.com/highfidelity/hifi into red

This commit is contained in:
samcake 2016-01-28 11:19:37 -08:00
commit 0c50903030
15 changed files with 116 additions and 135 deletions

View file

@ -136,7 +136,7 @@ Item {
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Velocity: " + root.velocity.toFixed(1)
text: "Speed: " + root.speed.toFixed(1)
}
Text {
color: root.fontColor;

View file

@ -1085,6 +1085,8 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) {
nextAttitude(position, orientation);
_bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix);
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
// now that physics has adjusted our position, we can update attachements.
Avatar::simulateAttachments(deltaTime);
}

View file

@ -162,7 +162,7 @@ void Stats::updateStats(bool force) {
MyAvatar* myAvatar = avatarManager->getMyAvatar();
glm::vec3 avatarPos = myAvatar->getPosition();
STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f);
STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.1f);
STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
if (_expanded || force) {
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);

View file

@ -47,7 +47,7 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, entitiesPing, 0)
STATS_PROPERTY(int, assetPing, 0)
STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
STATS_PROPERTY(float, velocity, 0)
STATS_PROPERTY(float, speed, 0)
STATS_PROPERTY(float, yaw, 0)
STATS_PROPERTY(int, avatarMixerInKbps, 0)
STATS_PROPERTY(int, avatarMixerInPps, 0)
@ -138,7 +138,7 @@ signals:
void entitiesPingChanged();
void assetPingChanged();
void positionChanged();
void velocityChanged();
void speedChanged();
void yawChanged();
void avatarMixerInKbpsChanged();
void avatarMixerInPpsChanged();

View file

@ -246,7 +246,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
// deltas up the hierarchy. Its target position is enforced later by shifting the hips.
deltaRotation = target.getRotation() * glm::inverse(tipOrientation);
float dotSign = copysignf(1.0f, deltaRotation.w);
const float ANGLE_DISTRIBUTION_FACTOR = 0.35f;
const float ANGLE_DISTRIBUTION_FACTOR = 0.45f;
deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * deltaRotation, ANGLE_DISTRIBUTION_FACTOR));
}
@ -376,13 +376,26 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
++constraintItr;
}
} else {
// shift the hips according to the offset from the previous frame
// shift the everything according to the _hipsOffset from the previous frame
float offsetLength = glm::length(_hipsOffset);
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
// but only if offset is long enough
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
_relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + scaleFactor * _hipsOffset;
if (_hipsParentIndex == -1) {
// the hips are the root so _hipsOffset is in the correct frame
_relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + scaleFactor * _hipsOffset;
} else {
// the hips are NOT the root so we need to transform _hipsOffset into hips local-frame
glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot;
int index = _skeleton->getParentIndex(_hipsParentIndex);
while (index != -1) {
hipsFrameRotation *= _relativePoses[index].rot;
index = _skeleton->getParentIndex(index);
}
_relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans
+ glm::inverse(glm::normalize(hipsFrameRotation)) * (scaleFactor * _hipsOffset);
}
}
solveWithCyclicCoordinateDescent(targets);
@ -621,7 +634,7 @@ void AnimInverseKinematics::initConstraints() {
} else if (baseName.startsWith("Spine", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
const float MAX_SPINE_TWIST = PI / 8.0f;
const float MAX_SPINE_TWIST = PI / 12.0f;
stConstraint->setTwistLimits(-MAX_SPINE_TWIST, MAX_SPINE_TWIST);
std::vector<float> minDots;
@ -645,11 +658,11 @@ void AnimInverseKinematics::initConstraints() {
} else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
const float MAX_NECK_TWIST = PI / 6.0f;
const float MAX_NECK_TWIST = PI / 9.0f;
stConstraint->setTwistLimits(-MAX_NECK_TWIST, MAX_NECK_TWIST);
std::vector<float> minDots;
const float MAX_NECK_SWING = PI / 4.0f;
const float MAX_NECK_SWING = PI / 8.0f;
minDots.push_back(cosf(MAX_NECK_SWING));
stConstraint->setSwingLimits(minDots);
@ -657,11 +670,11 @@ void AnimInverseKinematics::initConstraints() {
} else if (0 == baseName.compare("Head", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
const float MAX_HEAD_TWIST = PI / 8.0f;
const float MAX_HEAD_TWIST = PI / 9.0f;
stConstraint->setTwistLimits(-MAX_HEAD_TWIST, MAX_HEAD_TWIST);
std::vector<float> minDots;
const float MAX_HEAD_SWING = PI / 6.0f;
const float MAX_HEAD_SWING = PI / 10.0f;
minDots.push_back(cosf(MAX_HEAD_SWING));
stConstraint->setSwingLimits(minDots);
@ -775,9 +788,13 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
initConstraints();
_headIndex = _skeleton->nameToJointIndex("Head");
_hipsIndex = _skeleton->nameToJointIndex("Hips");
// also cache the _hipsParentIndex for later
_hipsParentIndex = _skeleton->getParentIndex(_hipsIndex);
} else {
clearConstraints();
_headIndex = -1;
_hipsIndex = -1;
_hipsParentIndex = -1;
}
}

View file

@ -79,13 +79,14 @@ protected:
AnimPoseVec _relativePoses; // current relative poses
// experimental data for moving hips during IK
int _headIndex = -1;
int _hipsIndex = -1;
glm::vec3 _hipsOffset = Vectors::ZERO;
glm::vec3 _hipsOffset { Vectors::ZERO };
int _headIndex { -1 };
int _hipsIndex { -1 };
int _hipsParentIndex { -1 };
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
// during the the cyclic coordinate descent algorithm
int _maxTargetIndex = 0;
int _maxTargetIndex { 0 };
};
#endif // hifi_AnimInverseKinematics_h

View file

@ -18,7 +18,7 @@ const float AnimationLoop::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
AnimationLoop::AnimationLoop() :
_fps(30.0f),
_loop(false),
_loop(true),
_hold(false),
_startAutomatically(false),
_firstFrame(0.0f),

View file

@ -181,6 +181,15 @@ int64_t AudioInjector::injectNextFrame() {
// make sure we actually have samples downloaded to inject
if (_audioData.size()) {
int sampleSize = (_options.stereo ? 2 : 1) * sizeof(AudioConstants::AudioSample);
auto numSamples = static_cast<int>(_audioData.size() / sampleSize);
auto targetSize = numSamples * sampleSize;
if (targetSize != _audioData.size()) {
qDebug() << "Resizing audio that doesn't end at multiple of sample size, resizing from "
<< _audioData.size() << " to " << targetSize;
_audioData.resize(targetSize);
}
_outgoingSequenceNumber = 0;
_nextFrame = 0;
@ -272,7 +281,7 @@ int64_t AudioInjector::injectNextFrame() {
_currentPacket->write(_audioData.data() + _currentSendOffset, bytesToCopy);
_currentSendOffset += bytesToCopy;
totalBytesLeftToCopy -= bytesToCopy;
if (_currentSendOffset >= _audioData.size()) {
if (_options.loop && _currentSendOffset >= _audioData.size()) {
_currentSendOffset = 0;
}
}

View file

@ -390,6 +390,14 @@ glm::quat CharacterController::getFollowAngularDisplacement() const {
return bulletToGLM(_followAngularDisplacement);
}
glm::vec3 CharacterController::getFollowVelocity() const {
if (_followTime > 0.0f) {
return bulletToGLM(_followLinearDisplacement) / _followTime;
} else {
return glm::vec3();
}
}
glm::vec3 CharacterController::getLinearVelocity() const {
glm::vec3 velocity(0.0f);
if (_rigidBody) {

View file

@ -71,6 +71,7 @@ public:
float getFollowTime() const { return _followTime; }
glm::vec3 getFollowLinearDisplacement() const;
glm::quat getFollowAngularDisplacement() const;
glm::vec3 getFollowVelocity() const;
glm::vec3 getLinearVelocity() const;

View file

@ -90,15 +90,16 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
initDeferredPipelines(*shapePlumber);
// CPU: Fetch the renderOpaques
auto fetchedOpaques = addJob<FetchItems>("FetchOpaque");
auto culledOpaques = addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", fetchedOpaques, cullFunctor);
auto opaques = addJob<DepthSortItems>("DepthSortOpaque", culledOpaques);
const auto fetchedOpaques = addJob<FetchItems>("FetchOpaque");
const auto culledOpaques = addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", fetchedOpaques, cullFunctor);
const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", culledOpaques);
// CPU only, create the list of renderedTransparents items
auto fetchedTransparents = addJob<FetchItems>("FetchTransparent", FetchItems(
const auto fetchedTransparents = addJob<FetchItems>("FetchTransparent", FetchItems(
ItemFilter::Builder::transparentShape().withoutLayered()));
auto culledTransparents = addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", fetchedTransparents, cullFunctor);
auto transparents = addJob<DepthSortItems>("DepthSortTransparent", culledTransparents, DepthSortItems(false));
const auto culledTransparents =
addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", fetchedTransparents, cullFunctor);
const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", culledTransparents, DepthSortItems(false));
// GPU Jobs: Start preparing the deferred and lighting buffer
addJob<PrepareDeferred>("PrepareDeferred");

View file

@ -105,16 +105,16 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_sha
}
// CPU: Fetch shadow-casting opaques
auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
const auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
// CPU: Cull against KeyLight frustum (nearby viewing camera)
auto culledItems = addJob<CullItems<RenderDetails::SHADOW_ITEM>>("CullShadowMap", fetchedItems, cullFunctor);
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW_ITEM>>("CullShadowMap", fetchedItems, cullFunctor);
// CPU: Sort by pipeline
auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);
const auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);
// CPU: Sort front to back
auto shadowShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedShapes);
const auto shadowShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedShapes);
// GPU: Render to shadow map
addJob<RenderShadowMap>("RenderShadowMap", shadowShapes, shapePlumber);

View file

@ -52,6 +52,7 @@ protected:
class Job;
class Task;
class JobNoIO {};
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
class JobConfig : public QObject {
@ -101,16 +102,16 @@ template <class T, class C> void jobConfigure(T& data, const C& configuration) {
template<class T> void jobConfigure(T&, const JobConfig&) {
// nop, as the default JobConfig was used, so the data does not need a configure method
}
template <class T> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
template <class T> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const JobNoIO& input, JobNoIO& output) {
data.run(sceneContext, renderContext);
}
template <class T, class I> void jobRunI(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) {
template <class T, class I> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, JobNoIO& output) {
data.run(sceneContext, renderContext, input);
}
template <class T, class O> void jobRunO(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) {
template <class T, class O> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const JobNoIO& input, O& output) {
data.run(sceneContext, renderContext, output);
}
template <class T, class I, class O> void jobRunIO(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
template <class T, class I, class O> void jobRun(T& data, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) {
data.run(sceneContext, renderContext, input, output);
}
@ -118,6 +119,7 @@ class Job {
public:
using Config = JobConfig;
using QConfigPointer = std::shared_ptr<QObject>;
using None = JobNoIO;
// The guts of a job
class Concept {
@ -138,84 +140,7 @@ public:
};
using ConceptPointer = std::shared_ptr<Concept>;
template <class T, class C = Config> class Model : public Concept {
public:
using Data = T;
Data _data;
Model(Data data = Data()) : Concept(std::make_shared<C>()), _data(data) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRun(_data, sceneContext, renderContext);
}
renderContext->jobConfig.reset();
}
};
template <class T, class I, class C = Config> class ModelI : public Concept {
public:
using Data = T;
using Input = I;
Data _data;
Varying _input;
const Varying getInput() const { return _input; }
ModelI(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunI(_data, sceneContext, renderContext, _input.get<I>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class O, class C = Config> class ModelO : public Concept {
public:
using Data = T;
using Output = O;
Data _data;
Varying _output;
const Varying getOutput() const { return _output; }
ModelO(Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _output(Output()) {
applyConfiguration();
}
void applyConfiguration() {
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class I, class O, class C = Config> class ModelIO : public Concept {
template <class T, class C = Config, class I = None, class O = None> class Model : public Concept {
public:
using Data = T;
using Input = I;
@ -228,7 +153,7 @@ public:
const Varying getInput() const { return _input; }
const Varying getOutput() const { return _output; }
ModelIO(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input), _output(Output()) {
Model(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input), _output(Output()) {
applyConfiguration();
}
@ -239,11 +164,14 @@ public:
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
jobRun(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class I, class C = Config> using ModelI = Model<T, C, I, None>;
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {}
@ -278,17 +206,24 @@ class Task {
public:
using Config = TaskConfig;
using QConfigPointer = Job::QConfigPointer;
using None = Job::None;
template <class T, class C = Config> class Model : public Job::Concept {
template <class T, class C = Config, class I = None, class O = None> class Model : public Job::Concept {
public:
using Data = T;
using Input = I;
using Output = O;
Data _data;
Varying _input;
Varying _output;
Model(Data data = Data()) : Concept(std::make_shared<C>()), _data(data) {
const Varying getInput() const { return _input; }
const Varying getOutput() const { return _output; }
Model(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input), _output(Output()) {
_config = _data._config; // use the data's config
std::static_pointer_cast<Config>(_config)->init(&_data);
applyConfiguration();
}
@ -299,11 +234,14 @@ public:
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
renderContext->jobConfig = std::static_pointer_cast<Config>(_config);
if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->enabled) {
jobRun(_data, sceneContext, renderContext);
jobRun(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
}
renderContext->jobConfig.reset();
}
};
template <class T, class I, class C = Config> using ModelI = Model<T, C, I, None>;
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
using Jobs = std::vector<Job>;
@ -311,15 +249,21 @@ public:
Task() : _config{ std::make_shared<Config>() } {}
template <class C> Task(std::shared_ptr<C> config) : _config{ config } {}
// Queue a new job to the container; returns the job's output
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(std::forward<A>(args)...));
// Create a new job in the container's queue; returns the job's output
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(
input,
typename T::JobModel::Data(std::forward<A>(args)...)));
QConfigPointer config = _jobs.back().getConfiguration();
config->setParent(_config.get());
config->setObjectName(name.c_str());
QObject::connect(config.get(), SIGNAL(dirty()), _config.get(), SLOT(refresh()));
return _jobs.back().getOutput();
}
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
const auto input = Varying(typename T::JobModel::Input());
return addJob<T>(name, input, std::forward<A>(args)...);
}
std::shared_ptr<Config> getConfiguration() {
auto config = std::static_pointer_cast<Config>(_config);
@ -335,7 +279,7 @@ public:
}
protected:
template <class T, class C> friend class Model;
template <class T, class C, class I, class O> friend class Model;
QConfigPointer _config;
Jobs _jobs;

View file

@ -1110,9 +1110,9 @@
collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav",
name: "dice",
position: {
x: 541,
y: 494.96,
z: 509.1
x: 541.61,
y: 495.21,
z: 508.52
},
dimensions: {
x: 0.09,
@ -1144,16 +1144,15 @@
var dice1 = Entities.addEntity(diceProps);
diceProps.position = {
x: 541.05,
y: 494.96,
z: 509.0
x: 541.52,
y: 495.21,
z: 508.41
};
var dice2 = Entities.addEntity(diceProps);
}
function createGates() {
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/ryan/fence.fbx';

View file

@ -1098,9 +1098,9 @@ MasterReset = function() {
collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav",
name: "dice",
position: {
x: 541,
y: 494.96,
z: 509.1
x: 541.61,
y: 495.21,
z: 508.52
},
dimensions: {
x: 0.09,
@ -1132,16 +1132,15 @@ MasterReset = function() {
var dice1 = Entities.addEntity(diceProps);
diceProps.position = {
x: 541.05,
y: 494.96,
z: 509.0
x: 541.52,
y: 495.21,
z: 508.41
};
var dice2 = Entities.addEntity(diceProps);
}
function createGates() {
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/ryan/fence.fbx';