mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 21:29:33 +02:00
Merge pull request #7387 from ZappoMan/fixBlenderCrash
Fix ModelBlender crash
This commit is contained in:
commit
d7d428d1b2
23 changed files with 165 additions and 339 deletions
|
@ -222,7 +222,6 @@ void Agent::executeScript() {
|
||||||
scriptedAvatar->setForceFaceTrackerConnected(true);
|
scriptedAvatar->setForceFaceTrackerConnected(true);
|
||||||
|
|
||||||
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
||||||
scriptedAvatar->setFaceModelURL(QUrl());
|
|
||||||
scriptedAvatar->setSkeletonModelURL(QUrl());
|
scriptedAvatar->setSkeletonModelURL(QUrl());
|
||||||
|
|
||||||
// give this AvatarData object to the script engine
|
// give this AvatarData object to the script engine
|
||||||
|
|
|
@ -757,7 +757,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
connect(&nodeList->getPacketReceiver(), &PacketReceiver::dataReceived,
|
connect(&nodeList->getPacketReceiver(), &PacketReceiver::dataReceived,
|
||||||
bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
|
bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
|
||||||
|
|
||||||
connect(&getMyAvatar()->getSkeletonModel(), &SkeletonModel::skeletonLoaded,
|
// FIXME -- I'm a little concerned about this.
|
||||||
|
connect(getMyAvatar()->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded,
|
||||||
this, &Application::checkSkeleton, Qt::QueuedConnection);
|
this, &Application::checkSkeleton, Qt::QueuedConnection);
|
||||||
|
|
||||||
// Setup the userInputMapper with the actions
|
// Setup the userInputMapper with the actions
|
||||||
|
@ -4603,7 +4604,7 @@ void Application::notifyPacketVersionMismatch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::checkSkeleton() {
|
void Application::checkSkeleton() {
|
||||||
if (getMyAvatar()->getSkeletonModel().isActive() && !getMyAvatar()->getSkeletonModel().hasSkeleton()) {
|
if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
|
||||||
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
|
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
|
||||||
|
|
||||||
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
|
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
|
||||||
|
|
|
@ -79,7 +79,6 @@ namespace render {
|
||||||
|
|
||||||
Avatar::Avatar(RigPointer rig) :
|
Avatar::Avatar(RigPointer rig) :
|
||||||
AvatarData(),
|
AvatarData(),
|
||||||
_skeletonModel(this, nullptr, rig),
|
|
||||||
_skeletonOffset(0.0f),
|
_skeletonOffset(0.0f),
|
||||||
_bodyYawDelta(0.0f),
|
_bodyYawDelta(0.0f),
|
||||||
_positionDeltaAccumulator(0.0f),
|
_positionDeltaAccumulator(0.0f),
|
||||||
|
@ -100,6 +99,8 @@ Avatar::Avatar(RigPointer rig) :
|
||||||
|
|
||||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||||
_headData = static_cast<HeadData*>(new Head(this));
|
_headData = static_cast<HeadData*>(new Head(this));
|
||||||
|
|
||||||
|
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr, rig);
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
|
@ -112,19 +113,19 @@ Avatar::~Avatar() {
|
||||||
|
|
||||||
void Avatar::init() {
|
void Avatar::init() {
|
||||||
getHead()->init();
|
getHead()->init();
|
||||||
_skeletonModel.init();
|
_skeletonModel->init();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getChestPosition() const {
|
glm::vec3 Avatar::getChestPosition() const {
|
||||||
// for now, let's just assume that the "chest" is halfway between the root and the neck
|
// for now, let's just assume that the "chest" is halfway between the root and the neck
|
||||||
glm::vec3 neckPosition;
|
glm::vec3 neckPosition;
|
||||||
return _skeletonModel.getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition();
|
return _skeletonModel->getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getNeckPosition() const {
|
glm::vec3 Avatar::getNeckPosition() const {
|
||||||
glm::vec3 neckPosition;
|
glm::vec3 neckPosition;
|
||||||
return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : getPosition();
|
return _skeletonModel->getNeckPosition(neckPosition) ? neckPosition : getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,10 +138,10 @@ AABox Avatar::getBounds() const {
|
||||||
// Except, that getPartBounds produces an infinite, uncentered bounding box when the model is not yet parsed,
|
// Except, that getPartBounds produces an infinite, uncentered bounding box when the model is not yet parsed,
|
||||||
// and we want a centered one. NOTE: There is code that may never try to render, and thus never load and get the
|
// and we want a centered one. NOTE: There is code that may never try to render, and thus never load and get the
|
||||||
// real model bounds, if this is unrealistically small.
|
// real model bounds, if this is unrealistically small.
|
||||||
if (!_skeletonModel.isRenderable()) {
|
if (!_skeletonModel->isRenderable()) {
|
||||||
return AABox(getPosition(), getUniformScale()); // approximately 2m tall, scaled to user request.
|
return AABox(getPosition(), getUniformScale()); // approximately 2m tall, scaled to user request.
|
||||||
}
|
}
|
||||||
return _skeletonModel.getPartBounds(0, 0, getPosition(), getOrientation());
|
return _skeletonModel->getPartBounds(0, 0, getPosition(), getOrientation());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::animateScaleChanges(float deltaTime) {
|
void Avatar::animateScaleChanges(float deltaTime) {
|
||||||
|
@ -191,8 +192,8 @@ void Avatar::simulate(float deltaTime) {
|
||||||
if (_shouldAnimate && !_shouldSkipRender && inView) {
|
if (_shouldAnimate && !_shouldSkipRender && inView) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
_skeletonModel.getRig()->copyJointsFromJointData(_jointData);
|
_skeletonModel->getRig()->copyJointsFromJointData(_jointData);
|
||||||
_skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
|
_skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
|
||||||
locationChanged(); // joints changed, so if there are any children, update them.
|
locationChanged(); // joints changed, so if there are any children, update them.
|
||||||
_hasNewJointRotations = false;
|
_hasNewJointRotations = false;
|
||||||
_hasNewJointTranslations = false;
|
_hasNewJointTranslations = false;
|
||||||
|
@ -200,7 +201,7 @@ void Avatar::simulate(float deltaTime) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("head");
|
PerformanceTimer perfTimer("head");
|
||||||
glm::vec3 headPosition = getPosition();
|
glm::vec3 headPosition = getPosition();
|
||||||
_skeletonModel.getHeadPosition(headPosition);
|
_skeletonModel->getHeadPosition(headPosition);
|
||||||
Head* head = getHead();
|
Head* head = getHead();
|
||||||
head->setPosition(headPosition);
|
head->setPosition(headPosition);
|
||||||
head->setScale(getUniformScale());
|
head->setScale(getUniformScale());
|
||||||
|
@ -295,8 +296,7 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene>
|
||||||
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
|
||||||
_renderItemID = scene->allocateID();
|
_renderItemID = scene->allocateID();
|
||||||
pendingChanges.resetItem(_renderItemID, avatarPayloadPointer);
|
pendingChanges.resetItem(_renderItemID, avatarPayloadPointer);
|
||||||
_skeletonModel.addToScene(scene, pendingChanges);
|
_skeletonModel->addToScene(scene, pendingChanges);
|
||||||
getHead()->getFaceModel().addToScene(scene, pendingChanges);
|
|
||||||
|
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
attachmentModel->addToScene(scene, pendingChanges);
|
attachmentModel->addToScene(scene, pendingChanges);
|
||||||
|
@ -308,8 +308,7 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene>
|
||||||
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||||
pendingChanges.removeItem(_renderItemID);
|
pendingChanges.removeItem(_renderItemID);
|
||||||
render::Item::clearID(_renderItemID);
|
render::Item::clearID(_renderItemID);
|
||||||
_skeletonModel.removeFromScene(scene, pendingChanges);
|
_skeletonModel->removeFromScene(scene, pendingChanges);
|
||||||
getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
|
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
attachmentModel->removeFromScene(scene, pendingChanges);
|
attachmentModel->removeFromScene(scene, pendingChanges);
|
||||||
}
|
}
|
||||||
|
@ -340,12 +339,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
if (_handState & IS_FINGER_POINTING_FLAG) {
|
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||||
int leftIndexTip = getJointIndex("LeftHandIndex4");
|
int leftIndexTip = getJointIndex("LeftHandIndex4");
|
||||||
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
|
int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
|
||||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftIndexTip, position);
|
havePosition = _skeletonModel->getJointPositionInWorldFrame(leftIndexTip, position);
|
||||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
|
haveRotation = _skeletonModel->getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
|
||||||
} else {
|
} else {
|
||||||
int leftHand = _skeletonModel.getLeftHandJointIndex();
|
int leftHand = _skeletonModel->getLeftHandJointIndex();
|
||||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(leftHand, position);
|
havePosition = _skeletonModel->getJointPositionInWorldFrame(leftHand, position);
|
||||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftHand, rotation);
|
haveRotation = _skeletonModel->getJointRotationInWorldFrame(leftHand, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (havePosition && haveRotation) {
|
if (havePosition && haveRotation) {
|
||||||
|
@ -364,12 +363,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
if (_handState & IS_FINGER_POINTING_FLAG) {
|
if (_handState & IS_FINGER_POINTING_FLAG) {
|
||||||
int rightIndexTip = getJointIndex("RightHandIndex4");
|
int rightIndexTip = getJointIndex("RightHandIndex4");
|
||||||
int rightIndexTipJoint = getJointIndex("RightHandIndex3");
|
int rightIndexTipJoint = getJointIndex("RightHandIndex3");
|
||||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightIndexTip, position);
|
havePosition = _skeletonModel->getJointPositionInWorldFrame(rightIndexTip, position);
|
||||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
|
haveRotation = _skeletonModel->getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
|
||||||
} else {
|
} else {
|
||||||
int rightHand = _skeletonModel.getRightHandJointIndex();
|
int rightHand = _skeletonModel->getRightHandJointIndex();
|
||||||
havePosition = _skeletonModel.getJointPositionInWorldFrame(rightHand, position);
|
havePosition = _skeletonModel->getJointPositionInWorldFrame(rightHand, position);
|
||||||
haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightHand, rotation);
|
haveRotation = _skeletonModel->getJointRotationInWorldFrame(rightHand, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (havePosition && haveRotation) {
|
if (havePosition && haveRotation) {
|
||||||
|
@ -426,7 +425,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
const float LIGHT_EXPONENT = 1.0f;
|
const float LIGHT_EXPONENT = 1.0f;
|
||||||
const float LIGHT_CUTOFF = glm::radians(80.0f);
|
const float LIGHT_CUTOFF = glm::radians(80.0f);
|
||||||
float distance = BASE_LIGHT_DISTANCE * getUniformScale();
|
float distance = BASE_LIGHT_DISTANCE * getUniformScale();
|
||||||
glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
|
glm::vec3 position = _skeletonModel->getTranslation();
|
||||||
glm::quat orientation = getOrientation();
|
glm::quat orientation = getOrientation();
|
||||||
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
foreach (const AvatarManager::LocalLight& light, DependencyManager::get<AvatarManager>()->getLocalLights()) {
|
||||||
glm::vec3 direction = orientation * light.direction;
|
glm::vec3 direction = orientation * light.direction;
|
||||||
|
@ -436,10 +435,10 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
|
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
|
||||||
if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) {
|
if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
||||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||||
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
||||||
_skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
_skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the avatar being looked at, render a little ball above their head
|
// If this is the avatar being looked at, render a little ball above their head
|
||||||
|
@ -468,7 +467,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
* (1.0f - ((float)(now - getHead()->getLookingAtMeStarted()))
|
* (1.0f - ((float)(now - getHead()->getLookingAtMeStarted()))
|
||||||
/ (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND));
|
/ (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND));
|
||||||
if (alpha > 0.0f) {
|
if (alpha > 0.0f) {
|
||||||
QSharedPointer<NetworkGeometry> geometry = _skeletonModel.getGeometry();
|
QSharedPointer<NetworkGeometry> geometry = _skeletonModel->getGeometry();
|
||||||
if (geometry && geometry->isLoaded()) {
|
if (geometry && geometry->isLoaded()) {
|
||||||
const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye
|
const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye
|
||||||
const float RADIUS_INCREMENT = 0.005f;
|
const float RADIUS_INCREMENT = 0.005f;
|
||||||
|
@ -539,14 +538,9 @@ void Avatar::fixupModelsInScene() {
|
||||||
// fix them up in the scene
|
// fix them up in the scene
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
if (_skeletonModel.isRenderable() && _skeletonModel.needsFixupInScene()) {
|
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
||||||
_skeletonModel.removeFromScene(scene, pendingChanges);
|
_skeletonModel->removeFromScene(scene, pendingChanges);
|
||||||
_skeletonModel.addToScene(scene, pendingChanges);
|
_skeletonModel->addToScene(scene, pendingChanges);
|
||||||
}
|
|
||||||
Model& faceModel = getHead()->getFaceModel();
|
|
||||||
if (faceModel.isRenderable() && faceModel.needsFixupInScene()) {
|
|
||||||
faceModel.removeFromScene(scene, pendingChanges);
|
|
||||||
faceModel.addToScene(scene, pendingChanges);
|
|
||||||
}
|
}
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
||||||
|
@ -564,14 +558,7 @@ void Avatar::fixupModelsInScene() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) {
|
void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) {
|
||||||
|
|
||||||
fixupModelsInScene();
|
fixupModelsInScene();
|
||||||
|
|
||||||
{
|
|
||||||
if (_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable()) {
|
|
||||||
getHead()->render(renderArgs, 1.0f, renderFrustum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getHead()->renderLookAts(renderArgs);
|
getHead()->renderLookAts(renderArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,8 +580,8 @@ void Avatar::simulateAttachments(float deltaTime) {
|
||||||
model->setRotation(getOrientation() * Quaternions::Y_180);
|
model->setRotation(getOrientation() * Quaternions::Y_180);
|
||||||
model->simulate(deltaTime);
|
model->simulate(deltaTime);
|
||||||
} else {
|
} else {
|
||||||
if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) &&
|
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
|
||||||
_skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) {
|
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
|
||||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale());
|
model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale());
|
||||||
model->setRotation(jointRotation * attachment.rotation);
|
model->setRotation(jointRotation * attachment.rotation);
|
||||||
model->setScaleToFit(true, getUniformScale() * attachment.scale, true); // hack to force rescale
|
model->setScaleToFit(true, getUniformScale() * attachment.scale, true); // hack to force rescale
|
||||||
|
@ -635,7 +622,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
|
||||||
glm::vec3 bodyUpDirection = getBodyUpDirection();
|
glm::vec3 bodyUpDirection = getBodyUpDirection();
|
||||||
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
|
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
|
||||||
|
|
||||||
if (getSkeletonModel().getNeckPosition(namePosition)) {
|
if (getSkeletonModel()->getNeckPosition(namePosition)) {
|
||||||
float headHeight = getHeadHeight();
|
float headHeight = getHeadHeight();
|
||||||
DEBUG_VALUE("namePosition =", namePosition);
|
DEBUG_VALUE("namePosition =", namePosition);
|
||||||
DEBUG_VALUE("headHeight =", headHeight);
|
DEBUG_VALUE("headHeight =", headHeight);
|
||||||
|
@ -780,46 +767,46 @@ QVector<glm::quat> Avatar::getJointRotations() const {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
return AvatarData::getJointRotations();
|
return AvatarData::getJointRotations();
|
||||||
}
|
}
|
||||||
QVector<glm::quat> jointRotations(_skeletonModel.getJointStateCount());
|
QVector<glm::quat> jointRotations(_skeletonModel->getJointStateCount());
|
||||||
for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) {
|
for (int i = 0; i < _skeletonModel->getJointStateCount(); ++i) {
|
||||||
_skeletonModel.getJointRotation(i, jointRotations[i]);
|
_skeletonModel->getJointRotation(i, jointRotations[i]);
|
||||||
}
|
}
|
||||||
return jointRotations;
|
return jointRotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::getJointRotation(int index) const {
|
glm::quat Avatar::getJointRotation(int index) const {
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
_skeletonModel.getJointRotation(index, rotation);
|
_skeletonModel->getJointRotation(index, rotation);
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getJointTranslation(int index) const {
|
glm::vec3 Avatar::getJointTranslation(int index) const {
|
||||||
glm::vec3 translation;
|
glm::vec3 translation;
|
||||||
_skeletonModel.getJointTranslation(index, translation);
|
_skeletonModel->getJointTranslation(index, translation);
|
||||||
return translation;
|
return translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::getDefaultJointRotation(int index) const {
|
glm::quat Avatar::getDefaultJointRotation(int index) const {
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
_skeletonModel.getRelativeDefaultJointRotation(index, rotation);
|
_skeletonModel->getRelativeDefaultJointRotation(index, rotation);
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
|
glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
|
||||||
glm::vec3 translation;
|
glm::vec3 translation;
|
||||||
_skeletonModel.getRelativeDefaultJointTranslation(index, translation);
|
_skeletonModel->getRelativeDefaultJointTranslation(index, translation);
|
||||||
return translation;
|
return translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
_skeletonModel.getAbsoluteJointRotationInRigFrame(index, rotation);
|
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
|
||||||
return Quaternions::Y_180 * rotation;
|
return Quaternions::Y_180 * rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
glm::vec3 translation;
|
glm::vec3 translation;
|
||||||
_skeletonModel.getAbsoluteJointTranslationInRigFrame(index, translation);
|
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
|
||||||
return Quaternions::Y_180 * translation;
|
return Quaternions::Y_180 * translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,7 +817,7 @@ int Avatar::getJointIndex(const QString& name) const {
|
||||||
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
|
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointIndex(name) : -1;
|
return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointIndex(name) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Avatar::getJointNames() const {
|
QStringList Avatar::getJointNames() const {
|
||||||
|
@ -840,7 +827,7 @@ QStringList Avatar::getJointNames() const {
|
||||||
Q_RETURN_ARG(QStringList, result));
|
Q_RETURN_ARG(QStringList, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointNames() : QStringList();
|
return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointNames() : QStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Avatar::getJointPosition(int index) const {
|
glm::vec3 Avatar::getJointPosition(int index) const {
|
||||||
|
@ -851,7 +838,7 @@ glm::vec3 Avatar::getJointPosition(int index) const {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
_skeletonModel.getJointPositionInWorldFrame(index, position);
|
_skeletonModel->getJointPositionInWorldFrame(index, position);
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,7 +850,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
_skeletonModel.getJointPositionInWorldFrame(getJointIndex(name), position);
|
_skeletonModel->getJointPositionInWorldFrame(getJointIndex(name), position);
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,14 +859,9 @@ void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
||||||
positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition());
|
positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setFaceModelURL(const QUrl& faceModelURL) {
|
|
||||||
AvatarData::setFaceModelURL(faceModelURL);
|
|
||||||
getHead()->getFaceModel().setURL(_faceModelURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||||
_skeletonModel.setURL(_skeletonModelURL);
|
_skeletonModel->setURL(_skeletonModelURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new model, can return an instance of a SoftAttachmentModel rather then Model
|
// create new model, can return an instance of a SoftAttachmentModel rather then Model
|
||||||
|
@ -912,12 +894,12 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
for (int i = 0; i < attachmentData.size(); i++) {
|
for (int i = 0; i < attachmentData.size(); i++) {
|
||||||
if (i == (int)_attachmentModels.size()) {
|
if (i == (int)_attachmentModels.size()) {
|
||||||
// if number of attachments has been increased, we need to allocate a new model
|
// if number of attachments has been increased, we need to allocate a new model
|
||||||
_attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel.getRig()));
|
_attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig()));
|
||||||
}
|
}
|
||||||
else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
|
else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
|
||||||
// if the attachment has changed type, we need to re-allocate a new one.
|
// if the attachment has changed type, we need to re-allocate a new one.
|
||||||
_attachmentsToRemove.push_back(_attachmentModels[i]);
|
_attachmentsToRemove.push_back(_attachmentModels[i]);
|
||||||
_attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel.getRig());
|
_attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig());
|
||||||
}
|
}
|
||||||
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
|
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
|
||||||
}
|
}
|
||||||
|
@ -1004,24 +986,14 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g
|
||||||
}
|
}
|
||||||
|
|
||||||
float Avatar::getSkeletonHeight() const {
|
float Avatar::getSkeletonHeight() const {
|
||||||
Extents extents = _skeletonModel.getBindExtents();
|
Extents extents = _skeletonModel->getBindExtents();
|
||||||
return extents.maximum.y - extents.minimum.y;
|
return extents.maximum.y - extents.minimum.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Avatar::getHeadHeight() const {
|
float Avatar::getHeadHeight() const {
|
||||||
Extents extents = getHead()->getFaceModel().getMeshExtents();
|
Extents extents = _skeletonModel->getMeshExtents();
|
||||||
if (!extents.isEmpty() && extents.isValid()) {
|
|
||||||
|
|
||||||
// HACK: We have a really odd case when fading out for some models where this value explodes
|
|
||||||
float result = extents.maximum.y - extents.minimum.y;
|
|
||||||
if (result >= 0.0f && result < 100.0f * getUniformScale() ) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extents = _skeletonModel.getMeshExtents();
|
|
||||||
glm::vec3 neckPosition;
|
glm::vec3 neckPosition;
|
||||||
if (!extents.isEmpty() && extents.isValid() && _skeletonModel.getNeckPosition(neckPosition)) {
|
if (!extents.isEmpty() && extents.isValid() && _skeletonModel->getNeckPosition(neckPosition)) {
|
||||||
return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y;
|
return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,7 +1002,7 @@ float Avatar::getHeadHeight() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
float Avatar::getPelvisFloatingHeight() const {
|
float Avatar::getPelvisFloatingHeight() const {
|
||||||
return -_skeletonModel.getBindExtents().minimum.y;
|
return -_skeletonModel->getBindExtents().minimum.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setShowDisplayName(bool showDisplayName) {
|
void Avatar::setShowDisplayName(bool showDisplayName) {
|
||||||
|
@ -1058,9 +1030,9 @@ void Avatar::setShowDisplayName(bool showDisplayName) {
|
||||||
// virtual
|
// virtual
|
||||||
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
float uniformScale = getUniformScale();
|
float uniformScale = getUniformScale();
|
||||||
shapeInfo.setCapsuleY(uniformScale * _skeletonModel.getBoundingCapsuleRadius(),
|
shapeInfo.setCapsuleY(uniformScale * _skeletonModel->getBoundingCapsuleRadius(),
|
||||||
0.5f * uniformScale * _skeletonModel.getBoundingCapsuleHeight());
|
0.5f * uniformScale * _skeletonModel->getBoundingCapsuleHeight());
|
||||||
shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset());
|
shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setMotionState(AvatarMotionState* motionState) {
|
void Avatar::setMotionState(AvatarMotionState* motionState) {
|
||||||
|
@ -1098,12 +1070,12 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const {
|
||||||
assert(QThread::currentThread() == thread()); // main thread access only
|
assert(QThread::currentThread() == thread()); // main thread access only
|
||||||
glm::quat leftPalmRotation;
|
glm::quat leftPalmRotation;
|
||||||
glm::vec3 leftPalmPosition;
|
glm::vec3 leftPalmPosition;
|
||||||
if (_skeletonModel.getLeftGrabPosition(leftPalmPosition)) {
|
if (_skeletonModel->getLeftGrabPosition(leftPalmPosition)) {
|
||||||
return leftPalmPosition;
|
return leftPalmPosition;
|
||||||
}
|
}
|
||||||
// avatar didn't have a LeftHandMiddle1 joint, fall back on this:
|
// avatar didn't have a LeftHandMiddle1 joint, fall back on this:
|
||||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation);
|
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation);
|
||||||
getSkeletonModel().getLeftHandPosition(leftPalmPosition);
|
getSkeletonModel()->getLeftHandPosition(leftPalmPosition);
|
||||||
leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation);
|
leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation);
|
||||||
return leftPalmPosition;
|
return leftPalmPosition;
|
||||||
}
|
}
|
||||||
|
@ -1111,7 +1083,7 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const {
|
||||||
glm::quat Avatar::getUncachedLeftPalmRotation() const {
|
glm::quat Avatar::getUncachedLeftPalmRotation() const {
|
||||||
assert(QThread::currentThread() == thread()); // main thread access only
|
assert(QThread::currentThread() == thread()); // main thread access only
|
||||||
glm::quat leftPalmRotation;
|
glm::quat leftPalmRotation;
|
||||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation);
|
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation);
|
||||||
return leftPalmRotation;
|
return leftPalmRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1119,12 +1091,12 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const {
|
||||||
assert(QThread::currentThread() == thread()); // main thread access only
|
assert(QThread::currentThread() == thread()); // main thread access only
|
||||||
glm::quat rightPalmRotation;
|
glm::quat rightPalmRotation;
|
||||||
glm::vec3 rightPalmPosition;
|
glm::vec3 rightPalmPosition;
|
||||||
if (_skeletonModel.getRightGrabPosition(rightPalmPosition)) {
|
if (_skeletonModel->getRightGrabPosition(rightPalmPosition)) {
|
||||||
return rightPalmPosition;
|
return rightPalmPosition;
|
||||||
}
|
}
|
||||||
// avatar didn't have a RightHandMiddle1 joint, fall back on this:
|
// avatar didn't have a RightHandMiddle1 joint, fall back on this:
|
||||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation);
|
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation);
|
||||||
getSkeletonModel().getRightHandPosition(rightPalmPosition);
|
getSkeletonModel()->getRightHandPosition(rightPalmPosition);
|
||||||
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
|
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
|
||||||
return rightPalmPosition;
|
return rightPalmPosition;
|
||||||
}
|
}
|
||||||
|
@ -1132,7 +1104,7 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const {
|
||||||
glm::quat Avatar::getUncachedRightPalmRotation() const {
|
glm::quat Avatar::getUncachedRightPalmRotation() const {
|
||||||
assert(QThread::currentThread() == thread()); // main thread access only
|
assert(QThread::currentThread() == thread()); // main thread access only
|
||||||
glm::quat rightPalmRotation;
|
glm::quat rightPalmRotation;
|
||||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation);
|
getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation);
|
||||||
return rightPalmRotation;
|
return rightPalmRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ public:
|
||||||
bool getIsLookAtTarget() const { return _isLookAtTarget; }
|
bool getIsLookAtTarget() const { return _isLookAtTarget; }
|
||||||
//getters
|
//getters
|
||||||
bool isInitialized() const { return _initialized; }
|
bool isInitialized() const { return _initialized; }
|
||||||
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
SkeletonModelPointer getSkeletonModel() { return _skeletonModel; }
|
||||||
const SkeletonModel& getSkeletonModel() const { return _skeletonModel; }
|
const SkeletonModelPointer getSkeletonModel() const { return _skeletonModel; }
|
||||||
glm::vec3 getChestPosition() const;
|
glm::vec3 getChestPosition() const;
|
||||||
float getUniformScale() const { return getScale().y; }
|
float getUniformScale() const { return getScale().y; }
|
||||||
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
||||||
|
@ -114,7 +114,6 @@ public:
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
||||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
|
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
|
||||||
|
|
||||||
virtual void setFaceModelURL(const QUrl& faceModelURL) override;
|
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
||||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ public:
|
||||||
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
|
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
|
||||||
|
|
||||||
void slamPosition(const glm::vec3& position);
|
void slamPosition(const glm::vec3& position);
|
||||||
virtual void updateAttitude() override { _skeletonModel.updateAttitude(); }
|
virtual void updateAttitude() override { _skeletonModel->updateAttitude(); }
|
||||||
|
|
||||||
// Call this when updating Avatar position with a delta. This will allow us to
|
// Call this when updating Avatar position with a delta. This will allow us to
|
||||||
// _accurately_ measure position changes and compute the resulting velocity
|
// _accurately_ measure position changes and compute the resulting velocity
|
||||||
|
@ -188,7 +187,7 @@ protected:
|
||||||
|
|
||||||
void setMotionState(AvatarMotionState* motionState);
|
void setMotionState(AvatarMotionState* motionState);
|
||||||
|
|
||||||
SkeletonModel _skeletonModel;
|
SkeletonModelPointer _skeletonModel;
|
||||||
glm::vec3 _skeletonOffset;
|
glm::vec3 _skeletonOffset;
|
||||||
std::vector<std::shared_ptr<Model>> _attachmentModels;
|
std::vector<std::shared_ptr<Model>> _attachmentModels;
|
||||||
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
|
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// FaceModel.cpp
|
|
||||||
// interface/src/avatar
|
|
||||||
//
|
|
||||||
// Created by Andrzej Kapolka on 9/16/13.
|
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <glm/gtx/transform.hpp>
|
|
||||||
|
|
||||||
#include "Avatar.h"
|
|
||||||
#include "FaceModel.h"
|
|
||||||
#include "Head.h"
|
|
||||||
#include "Menu.h"
|
|
||||||
|
|
||||||
FaceModel::FaceModel(Head* owningHead, RigPointer rig) :
|
|
||||||
Model(rig, nullptr),
|
|
||||||
_owningHead(owningHead)
|
|
||||||
{
|
|
||||||
assert(_rig);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
|
||||||
updateGeometry();
|
|
||||||
|
|
||||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningHead->_owningAvatar);
|
|
||||||
glm::vec3 neckPosition;
|
|
||||||
if (!owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) {
|
|
||||||
neckPosition = owningAvatar->getPosition();
|
|
||||||
}
|
|
||||||
setTranslation(neckPosition);
|
|
||||||
glm::quat neckParentRotation = owningAvatar->getOrientation();
|
|
||||||
setRotation(neckParentRotation);
|
|
||||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale());
|
|
||||||
|
|
||||||
setPupilDilation(_owningHead->getPupilDilation());
|
|
||||||
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
|
|
||||||
|
|
||||||
// FIXME - this is very expensive, we shouldn't do it if we don't have to
|
|
||||||
//invalidCalculatedMeshBoxes();
|
|
||||||
|
|
||||||
if (isActive()) {
|
|
||||||
setOffset(-_geometry->getFBXGeometry().neckPivot);
|
|
||||||
Model::simulateInternal(deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FaceModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
|
||||||
if (!isActive()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
|
||||||
return getJointPositionInWorldFrame(geometry.leftEyeJointIndex, firstEyePosition) &&
|
|
||||||
getJointPositionInWorldFrame(geometry.rightEyeJointIndex, secondEyePosition);
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// FaceModel.h
|
|
||||||
// interface/src/avatar
|
|
||||||
//
|
|
||||||
// Created by Andrzej Kapolka on 9/16/13.
|
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_FaceModel_h
|
|
||||||
#define hifi_FaceModel_h
|
|
||||||
|
|
||||||
#include <Model.h>
|
|
||||||
|
|
||||||
class Head;
|
|
||||||
|
|
||||||
/// A face formed from a linear mix of blendshapes according to a set of coefficients.
|
|
||||||
class FaceModel : public Model {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FaceModel(Head* owningHead, RigPointer rig);
|
|
||||||
|
|
||||||
virtual void simulate(float deltaTime, bool fullUpdate = true);
|
|
||||||
|
|
||||||
/// Retrieve the positions of up to two eye meshes.
|
|
||||||
/// \return whether or not both eye meshes were found
|
|
||||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Head* _owningHead;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_FaceModel_h
|
|
|
@ -62,20 +62,17 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_isLookingAtMe(false),
|
_isLookingAtMe(false),
|
||||||
_lookingAtMeStarted(0),
|
_lookingAtMeStarted(0),
|
||||||
_wasLastLookingAtMe(0),
|
_wasLastLookingAtMe(0),
|
||||||
_faceModel(this, std::make_shared<Rig>()),
|
|
||||||
_leftEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID()),
|
_leftEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID()),
|
||||||
_rightEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID())
|
_rightEyeLookAtID(DependencyManager::get<GeometryCache>()->allocateID())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::init() {
|
void Head::init() {
|
||||||
_faceModel.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::reset() {
|
void Head::reset() {
|
||||||
_baseYaw = _basePitch = _baseRoll = 0.0f;
|
_baseYaw = _basePitch = _baseRoll = 0.0f;
|
||||||
_leanForward = _leanSideways = 0.0f;
|
_leanForward = _leanSideways = 0.0f;
|
||||||
_faceModel.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
|
@ -233,12 +230,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_leftEyePosition = _rightEyePosition = getPosition();
|
_leftEyePosition = _rightEyePosition = getPosition();
|
||||||
if (!billboard) {
|
|
||||||
_faceModel.simulate(deltaTime);
|
|
||||||
if (!_faceModel.getEyePositions(_leftEyePosition, _rightEyePosition)) {
|
|
||||||
static_cast<Avatar*>(_owningAvatar)->getSkeletonModel().getEyePositions(_leftEyePosition, _rightEyePosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_eyePosition = calculateAverageEyePosition();
|
_eyePosition = calculateAverageEyePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +402,7 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Head::getScalePivot() const {
|
glm::vec3 Head::getScalePivot() const {
|
||||||
return _faceModel.isActive() ? _faceModel.getTranslation() : _position;
|
return _position;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::setFinalPitch(float finalPitch) {
|
void Head::setFinalPitch(float finalPitch) {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include <HeadData.h>
|
#include <HeadData.h>
|
||||||
|
|
||||||
#include "FaceModel.h"
|
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,9 +75,6 @@ public:
|
||||||
glm::vec3 getLeftEarPosition() const { return _leftEyePosition + (getRightDirection() * -EYE_EAR_GAP) + (getFrontDirection() * -EYE_EAR_GAP); }
|
glm::vec3 getLeftEarPosition() const { return _leftEyePosition + (getRightDirection() * -EYE_EAR_GAP) + (getFrontDirection() * -EYE_EAR_GAP); }
|
||||||
glm::vec3 getMouthPosition() const { return _eyePosition - getUpDirection() * glm::length(_rightEyePosition - _leftEyePosition); }
|
glm::vec3 getMouthPosition() const { return _eyePosition - getUpDirection() * glm::length(_rightEyePosition - _leftEyePosition); }
|
||||||
|
|
||||||
FaceModel& getFaceModel() { return _faceModel; }
|
|
||||||
const FaceModel& getFaceModel() const { return _faceModel; }
|
|
||||||
|
|
||||||
bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||||
float getAverageLoudness() const { return _averageLoudness; }
|
float getAverageLoudness() const { return _averageLoudness; }
|
||||||
/// \return the point about which scaling occurs.
|
/// \return the point about which scaling occurs.
|
||||||
|
@ -150,7 +146,6 @@ private:
|
||||||
bool _isLookingAtMe;
|
bool _isLookingAtMe;
|
||||||
quint64 _lookingAtMeStarted;
|
quint64 _lookingAtMeStarted;
|
||||||
quint64 _wasLastLookingAtMe;
|
quint64 _wasLastLookingAtMe;
|
||||||
FaceModel _faceModel;
|
|
||||||
|
|
||||||
glm::vec3 _correctedLookAtPosition;
|
glm::vec3 _correctedLookAtPosition;
|
||||||
|
|
||||||
|
@ -162,8 +157,6 @@ private:
|
||||||
void renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition);
|
void renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition);
|
||||||
void calculateMouthShapes();
|
void calculateMouthShapes();
|
||||||
void applyEyelidOffset(glm::quat headOrientation);
|
void applyEyelidOffset(glm::quat headOrientation);
|
||||||
|
|
||||||
friend class FaceModel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Head_h
|
#endif // hifi_Head_h
|
||||||
|
|
|
@ -167,11 +167,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
||||||
}
|
}
|
||||||
|
|
||||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||||
if (recordingInterface->getPlayerUseHeadModel() && dummyAvatar.getFaceModelURL().isValid() &&
|
|
||||||
(dummyAvatar.getFaceModelURL() != getFaceModelURL())) {
|
|
||||||
// FIXME
|
|
||||||
//myAvatar->setFaceModelURL(_dummyAvatar.getFaceModelURL());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
|
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
|
||||||
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
|
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
|
||||||
|
@ -237,7 +232,7 @@ void MyAvatar::reset(bool andReload) {
|
||||||
// Reset dynamic state.
|
// Reset dynamic state.
|
||||||
_wasPushing = _isPushing = _isBraking = false;
|
_wasPushing = _isPushing = _isBraking = false;
|
||||||
_follow.deactivate();
|
_follow.deactivate();
|
||||||
_skeletonModel.reset();
|
_skeletonModel->reset();
|
||||||
getHead()->reset();
|
getHead()->reset();
|
||||||
_targetVelocity = glm::vec3(0.0f);
|
_targetVelocity = glm::vec3(0.0f);
|
||||||
setThrust(glm::vec3(0.0f));
|
setThrust(glm::vec3(0.0f));
|
||||||
|
@ -343,10 +338,10 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
_skeletonModel.simulate(deltaTime);
|
_skeletonModel->simulate(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_skeletonModel.hasSkeleton()) {
|
if (!_skeletonModel->hasSkeleton()) {
|
||||||
// All the simulation that can be done has been done
|
// All the simulation that can be done has been done
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +356,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
PerformanceTimer perfTimer("head");
|
PerformanceTimer perfTimer("head");
|
||||||
Head* head = getHead();
|
Head* head = getHead();
|
||||||
glm::vec3 headPosition;
|
glm::vec3 headPosition;
|
||||||
if (!_skeletonModel.getHeadPosition(headPosition)) {
|
if (!_skeletonModel->getHeadPosition(headPosition)) {
|
||||||
headPosition = getPosition();
|
headPosition = getPosition();
|
||||||
}
|
}
|
||||||
head->setPosition(headPosition);
|
head->setPosition(headPosition);
|
||||||
|
@ -716,7 +711,7 @@ void MyAvatar::setEnableDebugDrawSensorToWorldMatrix(bool isEnabled) {
|
||||||
|
|
||||||
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
_skeletonModel.setVisibleInScene(isEnabled, scene);
|
_skeletonModel->setVisibleInScene(isEnabled, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setUseAnimPreAndPostRotations(bool isEnabled) {
|
void MyAvatar::setUseAnimPreAndPostRotations(bool isEnabled) {
|
||||||
|
@ -783,7 +778,7 @@ void MyAvatar::loadData() {
|
||||||
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
|
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.beginGroup("savedAttachmentData");
|
settings.beginGroup("savedAttachmentData");
|
||||||
settings.beginGroup(_skeletonModel.getURL().toString());
|
settings.beginGroup(_skeletonModel->getURL().toString());
|
||||||
settings.beginGroup(attachment.modelURL.toString());
|
settings.beginGroup(attachment.modelURL.toString());
|
||||||
settings.setValue("jointName", attachment.jointName);
|
settings.setValue("jointName", attachment.jointName);
|
||||||
|
|
||||||
|
@ -806,7 +801,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
|
||||||
AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const {
|
AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.beginGroup("savedAttachmentData");
|
settings.beginGroup("savedAttachmentData");
|
||||||
settings.beginGroup(_skeletonModel.getURL().toString());
|
settings.beginGroup(_skeletonModel->getURL().toString());
|
||||||
settings.beginGroup(modelURL.toString());
|
settings.beginGroup(modelURL.toString());
|
||||||
|
|
||||||
AttachmentData attachment;
|
AttachmentData attachment;
|
||||||
|
@ -951,17 +946,17 @@ eyeContactTarget MyAvatar::getEyeContactTarget() {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getDefaultEyePosition() const {
|
glm::vec3 MyAvatar::getDefaultEyePosition() const {
|
||||||
return getPosition() + getWorldAlignedOrientation() * Quaternions::Y_180 * _skeletonModel.getDefaultEyeModelPosition();
|
return getPosition() + getWorldAlignedOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
const float SCRIPT_PRIORITY = 1.0f + 1.0f;
|
const float SCRIPT_PRIORITY = 1.0f + 1.0f;
|
||||||
const float RECORDER_PRIORITY = 1.0f + 1.0f;
|
const float RECORDER_PRIORITY = 1.0f + 1.0f;
|
||||||
|
|
||||||
void MyAvatar::setJointRotations(QVector<glm::quat> jointRotations) {
|
void MyAvatar::setJointRotations(QVector<glm::quat> jointRotations) {
|
||||||
int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size());
|
int numStates = glm::min(_skeletonModel->getJointStateCount(), jointRotations.size());
|
||||||
for (int i = 0; i < numStates; ++i) {
|
for (int i = 0; i < numStates; ++i) {
|
||||||
// HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here
|
// HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here
|
||||||
_skeletonModel.setJointRotation(i, true, jointRotations[i], RECORDER_PRIORITY);
|
_skeletonModel->setJointRotation(i, true, jointRotations[i], RECORDER_PRIORITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1009,18 +1004,11 @@ void MyAvatar::clearJointsData() {
|
||||||
_rig->clearJointStates();
|
_rig->clearJointStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
|
||||||
|
|
||||||
Avatar::setFaceModelURL(faceModelURL);
|
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
|
||||||
getHead()->getFaceModel().setVisibleInScene(_prevShouldDrawHead, scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
|
|
||||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
_skeletonModel.setVisibleInScene(true, scene);
|
_skeletonModel->setVisibleInScene(true, scene);
|
||||||
_headBoneSet.clear();
|
_headBoneSet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,10 +1039,6 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getFaceModelURLString().isEmpty()) {
|
|
||||||
setFaceModelURL(QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& urlString = fullAvatarURL.toString();
|
const QString& urlString = fullAvatarURL.toString();
|
||||||
if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) {
|
if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) {
|
||||||
qApp->setRawAvatarUpdateThreading(false);
|
qApp->setRawAvatarUpdateThreading(false);
|
||||||
|
@ -1088,10 +1072,10 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
|
||||||
void MyAvatar::rebuildCollisionShape() {
|
void MyAvatar::rebuildCollisionShape() {
|
||||||
// compute localAABox
|
// compute localAABox
|
||||||
float scale = getUniformScale();
|
float scale = getUniformScale();
|
||||||
float radius = scale * _skeletonModel.getBoundingCapsuleRadius();
|
float radius = scale * _skeletonModel->getBoundingCapsuleRadius();
|
||||||
float height = scale * _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius;
|
float height = scale * _skeletonModel->getBoundingCapsuleHeight() + 2.0f * radius;
|
||||||
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
||||||
corner += scale * _skeletonModel.getBoundingCapsuleOffset();
|
corner += scale * _skeletonModel->getBoundingCapsuleOffset();
|
||||||
glm::vec3 diagonal(2.0f * radius, height, 2.0f * radius);
|
glm::vec3 diagonal(2.0f * radius, height, 2.0f * radius);
|
||||||
_characterController.setLocalBoundingBox(corner, diagonal);
|
_characterController.setLocalBoundingBox(corner, diagonal);
|
||||||
}
|
}
|
||||||
|
@ -1243,7 +1227,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
||||||
|
|
||||||
void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) {
|
void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) {
|
||||||
|
|
||||||
if (!_skeletonModel.isRenderable()) {
|
if (!_skeletonModel->isRenderable()) {
|
||||||
return; // wait until all models are loaded
|
return; // wait until all models are loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1283,8 +1267,8 @@ void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene
|
||||||
|
|
||||||
void MyAvatar::initHeadBones() {
|
void MyAvatar::initHeadBones() {
|
||||||
int neckJointIndex = -1;
|
int neckJointIndex = -1;
|
||||||
if (_skeletonModel.getGeometry()) {
|
if (_skeletonModel->getGeometry()) {
|
||||||
neckJointIndex = _skeletonModel.getGeometry()->getFBXGeometry().neckJointIndex;
|
neckJointIndex = _skeletonModel->getGeometry()->getFBXGeometry().neckJointIndex;
|
||||||
}
|
}
|
||||||
if (neckJointIndex == -1) {
|
if (neckJointIndex == -1) {
|
||||||
return;
|
return;
|
||||||
|
@ -1297,8 +1281,8 @@ void MyAvatar::initHeadBones() {
|
||||||
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
|
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
|
||||||
while (q.size() > 0) {
|
while (q.size() > 0) {
|
||||||
int jointIndex = q.front();
|
int jointIndex = q.front();
|
||||||
for (int i = 0; i < _skeletonModel.getJointStateCount(); i++) {
|
for (int i = 0; i < _skeletonModel->getJointStateCount(); i++) {
|
||||||
if (jointIndex == _skeletonModel.getParentJointIndex(i)) {
|
if (jointIndex == _skeletonModel->getParentJointIndex(i)) {
|
||||||
_headBoneSet.insert(i);
|
_headBoneSet.insert(i);
|
||||||
q.push(i);
|
q.push(i);
|
||||||
}
|
}
|
||||||
|
@ -1312,7 +1296,7 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
destroyAnimGraph();
|
destroyAnimGraph();
|
||||||
_skeletonModel.reset(); // Why is this necessary? Without this, we crash in the next render.
|
_skeletonModel->reset(); // Why is this necessary? Without this, we crash in the next render.
|
||||||
_animGraphUrl = url;
|
_animGraphUrl = url;
|
||||||
initAnimGraph();
|
initAnimGraph();
|
||||||
}
|
}
|
||||||
|
@ -1351,9 +1335,9 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||||
|
|
||||||
if (_skeletonModel.initWhenReady(scene)) {
|
if (_skeletonModel->initWhenReady(scene)) {
|
||||||
initHeadBones();
|
initHeadBones();
|
||||||
_skeletonModel.setCauterizeBoneSet(_headBoneSet);
|
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
||||||
initAnimGraph();
|
initAnimGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1362,7 +1346,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
auto animSkeleton = _rig->getAnimSkeleton();
|
auto animSkeleton = _rig->getAnimSkeleton();
|
||||||
|
|
||||||
// the rig is in the skeletonModel frame
|
// the rig is in the skeletonModel frame
|
||||||
AnimPose xform(glm::vec3(1), _skeletonModel.getRotation(), _skeletonModel.getTranslation());
|
AnimPose xform(glm::vec3(1), _skeletonModel->getRotation(), _skeletonModel->getTranslation());
|
||||||
|
|
||||||
if (_enableDebugDrawDefaultPose && animSkeleton) {
|
if (_enableDebugDrawDefaultPose && animSkeleton) {
|
||||||
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
|
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
|
||||||
|
@ -1402,7 +1386,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
||||||
|
|
||||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||||
_skeletonModel.setCauterizeBones(!shouldDrawHead);
|
_skeletonModel->setCauterizeBones(!shouldDrawHead);
|
||||||
}
|
}
|
||||||
_prevShouldDrawHead = shouldDrawHead;
|
_prevShouldDrawHead = shouldDrawHead;
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,8 +178,6 @@ public:
|
||||||
Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); }
|
Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); }
|
||||||
Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); }
|
Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); }
|
||||||
Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); }
|
Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); }
|
||||||
Q_INVOKABLE int getFaceBlendCoefNum() const { return getHead()->getFaceModel().getBlendshapeCoefficientsNum(); }
|
|
||||||
Q_INVOKABLE float getFaceBlendCoef(int index) const { return getHead()->getFaceModel().getBlendshapeCoefficient(index); }
|
|
||||||
|
|
||||||
Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); }
|
Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); }
|
||||||
|
|
||||||
|
@ -279,7 +277,7 @@ public slots:
|
||||||
void setEnableDebugDrawPosition(bool isEnabled);
|
void setEnableDebugDrawPosition(bool isEnabled);
|
||||||
void setEnableDebugDrawHandControllers(bool isEnabled);
|
void setEnableDebugDrawHandControllers(bool isEnabled);
|
||||||
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
|
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
|
||||||
bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); }
|
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); }
|
||||||
void setEnableMeshVisible(bool isEnabled);
|
void setEnableMeshVisible(bool isEnabled);
|
||||||
void setUseAnimPreAndPostRotations(bool isEnabled);
|
void setUseAnimPreAndPostRotations(bool isEnabled);
|
||||||
void setEnableInverseKinematics(bool isEnabled);
|
void setEnableInverseKinematics(bool isEnabled);
|
||||||
|
@ -328,7 +326,6 @@ private:
|
||||||
bool cameraInsideHead() const;
|
bool cameraInsideHead() const;
|
||||||
|
|
||||||
// These are made private for MyAvatar so that you will use the "use" methods instead
|
// These are made private for MyAvatar so that you will use the "use" methods instead
|
||||||
virtual void setFaceModelURL(const QUrl& faceModelURL) override;
|
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
||||||
|
|
||||||
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
class Avatar;
|
class Avatar;
|
||||||
class MuscleConstraint;
|
class MuscleConstraint;
|
||||||
|
|
||||||
|
class SkeletonModel;
|
||||||
|
using SkeletonModelPointer = std::shared_ptr<SkeletonModel>;
|
||||||
|
using SkeletonModelWeakPointer = std::weak_ptr<SkeletonModel>;
|
||||||
|
|
||||||
/// A skeleton loaded from a model.
|
/// A skeleton loaded from a model.
|
||||||
class SkeletonModel : public Model {
|
class SkeletonModel : public Model {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -79,6 +79,6 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu
|
||||||
// post the blender if we're not currently waiting for one to finish
|
// post the blender if we're not currently waiting for one to finish
|
||||||
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||||
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||||
DependencyManager::get<ModelBlender>()->noteRequiresBlend(this);
|
DependencyManager::get<ModelBlender>()->noteRequiresBlend(getThisPointer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ AvatarData::AvatarData() :
|
||||||
_hasNewJointRotations(true),
|
_hasNewJointRotations(true),
|
||||||
_hasNewJointTranslations(true),
|
_hasNewJointTranslations(true),
|
||||||
_headData(NULL),
|
_headData(NULL),
|
||||||
_faceModelURL("http://invalid.com"),
|
|
||||||
_displayNameTargetAlpha(1.0f),
|
_displayNameTargetAlpha(1.0f),
|
||||||
_displayNameAlpha(1.0f),
|
_displayNameAlpha(1.0f),
|
||||||
_billboard(),
|
_billboard(),
|
||||||
|
@ -989,18 +988,14 @@ bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) {
|
||||||
QDataStream packetStream(data);
|
QDataStream packetStream(data);
|
||||||
|
|
||||||
QUuid avatarUUID;
|
QUuid avatarUUID;
|
||||||
QUrl faceModelURL, skeletonModelURL;
|
QUrl unusedModelURL; // legacy faceModel support
|
||||||
|
QUrl skeletonModelURL;
|
||||||
QVector<AttachmentData> attachmentData;
|
QVector<AttachmentData> attachmentData;
|
||||||
QString displayName;
|
QString displayName;
|
||||||
packetStream >> avatarUUID >> faceModelURL >> skeletonModelURL >> attachmentData >> displayName;
|
packetStream >> avatarUUID >> unusedModelURL >> skeletonModelURL >> attachmentData >> displayName;
|
||||||
|
|
||||||
bool hasIdentityChanged = false;
|
bool hasIdentityChanged = false;
|
||||||
|
|
||||||
if (faceModelURL != _faceModelURL) {
|
|
||||||
setFaceModelURL(faceModelURL);
|
|
||||||
hasIdentityChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skeletonModelURL != _skeletonModelURL) {
|
if (skeletonModelURL != _skeletonModelURL) {
|
||||||
setSkeletonModelURL(skeletonModelURL);
|
setSkeletonModelURL(skeletonModelURL);
|
||||||
hasIdentityChanged = true;
|
hasIdentityChanged = true;
|
||||||
|
@ -1025,7 +1020,9 @@ QByteArray AvatarData::identityByteArray() {
|
||||||
QUrl emptyURL("");
|
QUrl emptyURL("");
|
||||||
const QUrl& urlToSend = (_skeletonModelURL == AvatarData::defaultFullAvatarModelUrl()) ? emptyURL : _skeletonModelURL;
|
const QUrl& urlToSend = (_skeletonModelURL == AvatarData::defaultFullAvatarModelUrl()) ? emptyURL : _skeletonModelURL;
|
||||||
|
|
||||||
identityStream << QUuid() << _faceModelURL << urlToSend << _attachmentData << _displayName;
|
QUrl unusedModelURL; // legacy faceModel support
|
||||||
|
|
||||||
|
identityStream << QUuid() << unusedModelURL << urlToSend << _attachmentData << _displayName;
|
||||||
|
|
||||||
return identityData;
|
return identityData;
|
||||||
}
|
}
|
||||||
|
@ -1038,12 +1035,6 @@ bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& data) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::setFaceModelURL(const QUrl& faceModelURL) {
|
|
||||||
_faceModelURL = faceModelURL;
|
|
||||||
|
|
||||||
qCDebug(avatars) << "Changing face model for avatar to" << _faceModelURL.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
|
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
|
||||||
if (expanded == _skeletonModelURL) {
|
if (expanded == _skeletonModelURL) {
|
||||||
|
@ -1445,9 +1436,6 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
|
||||||
QJsonObject AvatarData::toJson() const {
|
QJsonObject AvatarData::toJson() const {
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
|
|
||||||
if (!getFaceModelURL().isEmpty()) {
|
|
||||||
root[JSON_AVATAR_HEAD_MODEL] = getFaceModelURL().toString();
|
|
||||||
}
|
|
||||||
if (!getSkeletonModelURL().isEmpty()) {
|
if (!getSkeletonModelURL().isEmpty()) {
|
||||||
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
|
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
|
||||||
}
|
}
|
||||||
|
@ -1514,15 +1502,6 @@ void AvatarData::fromJson(const QJsonObject& json) {
|
||||||
_headData->fromJson(json[JSON_AVATAR_HEAD].toObject());
|
_headData->fromJson(json[JSON_AVATAR_HEAD].toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.contains(JSON_AVATAR_HEAD_MODEL)) {
|
|
||||||
auto faceModelURL = json[JSON_AVATAR_HEAD_MODEL].toString();
|
|
||||||
if (faceModelURL != getFaceModelURL().toString()) {
|
|
||||||
QUrl faceModel(faceModelURL);
|
|
||||||
if (faceModel.isValid()) {
|
|
||||||
setFaceModelURL(faceModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (json.contains(JSON_AVATAR_BODY_MODEL)) {
|
if (json.contains(JSON_AVATAR_BODY_MODEL)) {
|
||||||
auto bodyModelURL = json[JSON_AVATAR_BODY_MODEL].toString();
|
auto bodyModelURL = json[JSON_AVATAR_BODY_MODEL].toString();
|
||||||
if (bodyModelURL != getSkeletonModelURL().toString()) {
|
if (bodyModelURL != getSkeletonModelURL().toString()) {
|
||||||
|
|
|
@ -158,7 +158,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
||||||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||||
|
|
||||||
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
|
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
|
||||||
Q_PROPERTY(QString faceModelURL READ getFaceModelURLFromScript WRITE setFaceModelURLFromScript)
|
|
||||||
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
|
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
|
||||||
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
|
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
|
||||||
Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL)
|
Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL)
|
||||||
|
@ -296,11 +295,8 @@ public:
|
||||||
|
|
||||||
bool hasBillboardChangedAfterParsing(const QByteArray& data);
|
bool hasBillboardChangedAfterParsing(const QByteArray& data);
|
||||||
|
|
||||||
const QUrl& getFaceModelURL() const { return _faceModelURL; }
|
|
||||||
QString getFaceModelURLString() const { return _faceModelURL.toString(); }
|
|
||||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||||
const QString& getDisplayName() const { return _displayName; }
|
const QString& getDisplayName() const { return _displayName; }
|
||||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||||
|
|
||||||
virtual void setDisplayName(const QString& displayName);
|
virtual void setDisplayName(const QString& displayName);
|
||||||
|
@ -322,9 +318,6 @@ public:
|
||||||
void setBillboardFromURL(const QString& billboardURL);
|
void setBillboardFromURL(const QString& billboardURL);
|
||||||
const QString& getBillboardURL() { return _billboardURL; }
|
const QString& getBillboardURL() { return _billboardURL; }
|
||||||
|
|
||||||
QString getFaceModelURLFromScript() const { return _faceModelURL.toString(); }
|
|
||||||
void setFaceModelURLFromScript(const QString& faceModelString) { setFaceModelURL(faceModelString); }
|
|
||||||
|
|
||||||
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
|
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
|
||||||
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
|
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
|
||||||
|
|
||||||
|
@ -383,7 +376,6 @@ protected:
|
||||||
|
|
||||||
HeadData* _headData;
|
HeadData* _headData;
|
||||||
|
|
||||||
QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
|
||||||
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||||
QUrl _skeletonFBXURL;
|
QUrl _skeletonFBXURL;
|
||||||
QVector<AttachmentData> _attachmentData;
|
QVector<AttachmentData> _attachmentData;
|
||||||
|
|
|
@ -122,10 +122,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
|
||||||
// mesh URL for a UUID, find avatar in our list
|
// mesh URL for a UUID, find avatar in our list
|
||||||
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
|
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
|
||||||
|
|
||||||
if (avatar->getFaceModelURL() != faceMeshURL) {
|
|
||||||
avatar->setFaceModelURL(faceMeshURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avatar->getSkeletonModelURL().isEmpty() || (avatar->getSkeletonModelURL() != skeletonURL)) {
|
if (avatar->getSkeletonModelURL().isEmpty() || (avatar->getSkeletonModelURL() != skeletonURL)) {
|
||||||
avatar->setSkeletonModelURL(skeletonURL); // Will expand "" to default and so will not continuously fire
|
avatar->setSkeletonModelURL(skeletonURL); // Will expand "" to default and so will not continuously fire
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,7 +420,7 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en
|
||||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||||
assert(modelEntityItem); // we need this!!!
|
assert(modelEntityItem); // we need this!!!
|
||||||
Model* model = modelEntityItem->getModel(this);
|
ModelPointer model = modelEntityItem->getModel(this);
|
||||||
if (model) {
|
if (model) {
|
||||||
result = &model->getGeometry()->getFBXGeometry();
|
result = &model->getGeometry()->getFBXGeometry();
|
||||||
}
|
}
|
||||||
|
@ -428,8 +428,8 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Model* EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityItem) {
|
ModelPointer EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityItem) {
|
||||||
const Model* result = NULL;
|
ModelPointer result = nullptr;
|
||||||
if (entityItem->getType() == EntityTypes::Model) {
|
if (entityItem->getType() == EntityTypes::Model) {
|
||||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||||
|
@ -445,7 +445,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
|
||||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||||
if (modelEntityItem->hasCompoundShapeURL()) {
|
if (modelEntityItem->hasCompoundShapeURL()) {
|
||||||
Model* model = modelEntityItem->getModel(this);
|
ModelPointer model = modelEntityItem->getModel(this);
|
||||||
if (model) {
|
if (model) {
|
||||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
|
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
|
||||||
if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) {
|
if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) {
|
||||||
|
@ -461,25 +461,25 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha
|
||||||
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
|
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) {
|
ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) {
|
||||||
Model* model = NULL;
|
ModelPointer model = nullptr;
|
||||||
// Make sure we only create and delete models on the thread that owns the EntityTreeRenderer
|
// Make sure we only create and delete models on the thread that owns the EntityTreeRenderer
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(Model*, model),
|
Q_RETURN_ARG(ModelPointer, model),
|
||||||
Q_ARG(const QString&, url));
|
Q_ARG(const QString&, url));
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
model = new Model(std::make_shared<Rig>());
|
model = std::make_shared<Model>(std::make_shared<Rig>());
|
||||||
model->init();
|
model->init();
|
||||||
model->setURL(QUrl(url));
|
model->setURL(QUrl(url));
|
||||||
model->setCollisionModelURL(QUrl(collisionUrl));
|
model->setCollisionModelURL(QUrl(collisionUrl));
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, const QString& collisionUrl) {
|
ModelPointer EntityTreeRenderer::updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl) {
|
||||||
Model* model = NULL;
|
ModelPointer model = nullptr;
|
||||||
|
|
||||||
// The caller shouldn't call us if the URL doesn't need to change. But if they
|
// The caller shouldn't call us if the URL doesn't need to change. But if they
|
||||||
// do, we just return their original back to them.
|
// do, we just return their original back to them.
|
||||||
|
@ -490,8 +490,8 @@ Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, c
|
||||||
// Before we do any creating or deleting, make sure we're on our renderer thread
|
// Before we do any creating or deleting, make sure we're on our renderer thread
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(Model*, model),
|
Q_RETURN_ARG(ModelPointer, model),
|
||||||
Q_ARG(Model*, original),
|
Q_ARG(ModelPointer, original),
|
||||||
Q_ARG(const QString&, newUrl));
|
Q_ARG(const QString&, newUrl));
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
@ -500,11 +500,11 @@ Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, c
|
||||||
// at this point we know we need to replace the model, and we know we're on the
|
// at this point we know we need to replace the model, and we know we're on the
|
||||||
// correct thread, so we can do all our work.
|
// correct thread, so we can do all our work.
|
||||||
if (original) {
|
if (original) {
|
||||||
delete original; // delete the old model...
|
original.reset(); // delete the old model...
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the model and correctly initialize it with the new url
|
// create the model and correctly initialize it with the new url
|
||||||
model = new Model(std::make_shared<Rig>());
|
model = std::make_shared<Model>(std::make_shared<Rig>());
|
||||||
model->init();
|
model->init();
|
||||||
model->setURL(QUrl(newUrl));
|
model->setURL(QUrl(newUrl));
|
||||||
model->setCollisionModelURL(QUrl(collisionUrl));
|
model->setCollisionModelURL(QUrl(collisionUrl));
|
||||||
|
@ -512,19 +512,19 @@ Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, c
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::releaseModel(Model* model) {
|
void EntityTreeRenderer::releaseModel(ModelPointer model) {
|
||||||
// If we're not on the renderer's thread, then remember this model to be deleted later
|
// If we're not on the renderer's thread, then remember this model to be deleted later
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
_releasedModels << model;
|
_releasedModels << model;
|
||||||
} else { // otherwise just delete it right away
|
} else { // otherwise just delete it right away
|
||||||
delete model;
|
model.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::deleteReleasedModels() {
|
void EntityTreeRenderer::deleteReleasedModels() {
|
||||||
if (_releasedModels.size() > 0) {
|
if (_releasedModels.size() > 0) {
|
||||||
foreach(Model* model, _releasedModels) {
|
foreach(ModelPointer model, _releasedModels) {
|
||||||
delete model;
|
model.reset();
|
||||||
}
|
}
|
||||||
_releasedModels.clear();
|
_releasedModels.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ class Model;
|
||||||
class ScriptEngine;
|
class ScriptEngine;
|
||||||
class ZoneEntityItem;
|
class ZoneEntityItem;
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
using ModelPointer = std::shared_ptr<Model>;
|
||||||
|
using ModelWeakPointer = std::weak_ptr<Model>;
|
||||||
|
|
||||||
// Generic client side Octree renderer class.
|
// Generic client side Octree renderer class.
|
||||||
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public Dependency {
|
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public Dependency {
|
||||||
|
@ -53,7 +56,7 @@ public:
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem);
|
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem);
|
||||||
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem);
|
virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem);
|
||||||
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem);
|
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem);
|
||||||
|
|
||||||
/// clears the tree
|
/// clears the tree
|
||||||
|
@ -63,13 +66,13 @@ public:
|
||||||
void reloadEntityScripts();
|
void reloadEntityScripts();
|
||||||
|
|
||||||
/// if a renderable entity item needs a model, we will allocate it for them
|
/// if a renderable entity item needs a model, we will allocate it for them
|
||||||
Q_INVOKABLE Model* allocateModel(const QString& url, const QString& collisionUrl);
|
Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl);
|
||||||
|
|
||||||
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
||||||
Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl, const QString& collisionUrl);
|
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl);
|
||||||
|
|
||||||
/// if a renderable entity item is done with a model, it should return it to us
|
/// if a renderable entity item is done with a model, it should return it to us
|
||||||
void releaseModel(Model* model);
|
void releaseModel(ModelPointer model);
|
||||||
|
|
||||||
void deleteReleasedModels();
|
void deleteReleasedModels();
|
||||||
|
|
||||||
|
@ -129,7 +132,7 @@ private:
|
||||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||||
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
|
||||||
|
|
||||||
QList<Model*> _releasedModels;
|
QList<ModelPointer> _releasedModels;
|
||||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>(),
|
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>(),
|
||||||
const QVector<EntityItemID>& entityIdsToDiscard = QVector<EntityItemID>());
|
const QVector<EntityItemID>& entityIdsToDiscard = QVector<EntityItemID>());
|
||||||
|
|
|
@ -463,8 +463,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
Model* result = NULL;
|
ModelPointer result = nullptr;
|
||||||
|
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -506,7 +506,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
|
|
||||||
// release interest
|
// release interest
|
||||||
_myRenderer->releaseModel(_model);
|
_myRenderer->releaseModel(_model);
|
||||||
result = _model = NULL;
|
result = _model = nullptr;
|
||||||
_needsInitialSimulation = true;
|
_needsInitialSimulation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
BoxFace& face, glm::vec3& surfaceNormal,
|
BoxFace& face, glm::vec3& surfaceNormal,
|
||||||
void** intersectedObject, bool precisionPicking) const override;
|
void** intersectedObject, bool precisionPicking) const override;
|
||||||
|
|
||||||
Model* getModel(EntityTreeRenderer* renderer);
|
ModelPointer getModel(EntityTreeRenderer* renderer);
|
||||||
|
|
||||||
virtual bool needsToCallUpdate() const override;
|
virtual bool needsToCallUpdate() const override;
|
||||||
virtual void update(const quint64& now) override;
|
virtual void update(const quint64& now) override;
|
||||||
|
@ -87,7 +87,7 @@ private:
|
||||||
QVariantMap parseTexturesToMap(QString textures);
|
QVariantMap parseTexturesToMap(QString textures);
|
||||||
void remapTextures();
|
void remapTextures();
|
||||||
|
|
||||||
Model* _model = nullptr;
|
ModelPointer _model = nullptr;
|
||||||
bool _needsInitialSimulation = true;
|
bool _needsInitialSimulation = true;
|
||||||
bool _needsModelReload = true;
|
bool _needsModelReload = true;
|
||||||
EntityTreeRenderer* _myRenderer = nullptr;
|
EntityTreeRenderer* _myRenderer = nullptr;
|
||||||
|
|
|
@ -25,6 +25,9 @@ typedef std::shared_ptr<EntityTree> EntityTreePointer;
|
||||||
#include "DeleteEntityOperator.h"
|
#include "DeleteEntityOperator.h"
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
using ModelPointer = std::shared_ptr<Model>;
|
||||||
|
using ModelWeakPointer = std::weak_ptr<Model>;
|
||||||
|
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
|
|
||||||
class NewlyCreatedEntityHook {
|
class NewlyCreatedEntityHook {
|
||||||
|
@ -35,7 +38,7 @@ public:
|
||||||
class EntityItemFBXService {
|
class EntityItemFBXService {
|
||||||
public:
|
public:
|
||||||
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0;
|
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0;
|
||||||
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem) = 0;
|
virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) = 0;
|
||||||
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) = 0;
|
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,7 +174,7 @@ public:
|
||||||
const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) {
|
const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) {
|
||||||
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
|
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
|
||||||
}
|
}
|
||||||
const Model* getModelForEntityItem(EntityItemPointer entityItem) {
|
ModelPointer getModelForEntityItem(EntityItemPointer entityItem) {
|
||||||
return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL;
|
return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,11 @@ QStringList FBXGeometry::getJointNames() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FBXGeometry::hasBlendedMeshes() const {
|
bool FBXGeometry::hasBlendedMeshes() const {
|
||||||
foreach (const FBXMesh& mesh, meshes) {
|
if (!meshes.isEmpty()) {
|
||||||
if (!mesh.blendshapes.isEmpty()) {
|
foreach (const FBXMesh& mesh, meshes) {
|
||||||
return true;
|
if (!mesh.blendshapes.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1068,7 +1068,7 @@ void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrient
|
||||||
// post the blender if we're not currently waiting for one to finish
|
// post the blender if we're not currently waiting for one to finish
|
||||||
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||||
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||||
DependencyManager::get<ModelBlender>()->noteRequiresBlend(this);
|
DependencyManager::get<ModelBlender>()->noteRequiresBlend(getThisPointer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,16 +1276,14 @@ ModelBlender::ModelBlender() :
|
||||||
ModelBlender::~ModelBlender() {
|
ModelBlender::~ModelBlender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBlender::noteRequiresBlend(Model* model) {
|
void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
||||||
if (_pendingBlenders < QThread::idealThreadCount()) {
|
if (_pendingBlenders < QThread::idealThreadCount()) {
|
||||||
if (model->maybeStartBlender()) {
|
if (model->maybeStartBlender()) {
|
||||||
_pendingBlenders++;
|
_pendingBlenders++;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_modelsRequiringBlends.contains(model)) {
|
_modelsRequiringBlends.insert(model);
|
||||||
_modelsRequiringBlends.append(model);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBlender::setBlendedVertices(const QPointer<Model>& model, int blendNumber,
|
void ModelBlender::setBlendedVertices(const QPointer<Model>& model, int blendNumber,
|
||||||
|
@ -1294,8 +1292,9 @@ void ModelBlender::setBlendedVertices(const QPointer<Model>& model, int blendNum
|
||||||
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
||||||
}
|
}
|
||||||
_pendingBlenders--;
|
_pendingBlenders--;
|
||||||
while (!_modelsRequiringBlends.isEmpty()) {
|
while (!_modelsRequiringBlends.empty()) {
|
||||||
Model* nextModel = _modelsRequiringBlends.takeFirst();
|
auto fistItem = _modelsRequiringBlends.begin();
|
||||||
|
ModelPointer nextModel = fistItem->lock();
|
||||||
if (nextModel && nextModel->maybeStartBlender()) {
|
if (nextModel && nextModel->maybeStartBlender()) {
|
||||||
_pendingBlenders++;
|
_pendingBlenders++;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -50,8 +50,13 @@ inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
|
||||||
return qHash(a.get(), seed);
|
return qHash(a.get(), seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
using ModelPointer = std::shared_ptr<Model>;
|
||||||
|
using ModelWeakPointer = std::weak_ptr<Model>;
|
||||||
|
|
||||||
|
|
||||||
/// A generic 3D model displaying geometry loaded from a URL.
|
/// A generic 3D model displaying geometry loaded from a URL.
|
||||||
class Model : public QObject {
|
class Model : public QObject, public std::enable_shared_from_this<Model> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -63,6 +68,9 @@ public:
|
||||||
Model(RigPointer rig, QObject* parent = nullptr);
|
Model(RigPointer rig, QObject* parent = nullptr);
|
||||||
virtual ~Model();
|
virtual ~Model();
|
||||||
|
|
||||||
|
inline ModelPointer getThisPointer() const {
|
||||||
|
return std::static_pointer_cast<Model>(std::const_pointer_cast<Model>(shared_from_this()));
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the URL of the model to render.
|
/// Sets the URL of the model to render.
|
||||||
Q_INVOKABLE void setURL(const QUrl& url);
|
Q_INVOKABLE void setURL(const QUrl& url);
|
||||||
|
@ -387,7 +395,7 @@ class ModelBlender : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// Adds the specified model to the list requiring vertex blends.
|
/// Adds the specified model to the list requiring vertex blends.
|
||||||
void noteRequiresBlend(Model* model);
|
void noteRequiresBlend(ModelPointer model);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setBlendedVertices(const QPointer<Model>& model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
void setBlendedVertices(const QPointer<Model>& model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
|
@ -397,7 +405,7 @@ private:
|
||||||
ModelBlender();
|
ModelBlender();
|
||||||
virtual ~ModelBlender();
|
virtual ~ModelBlender();
|
||||||
|
|
||||||
QList<QPointer<Model> > _modelsRequiringBlends;
|
std::set<ModelWeakPointer, std::owner_less<ModelWeakPointer>> _modelsRequiringBlends;
|
||||||
int _pendingBlenders;
|
int _pendingBlenders;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue