Merge pull request #16321 from samcake/instancing

Instancing: applying the new hfm shape to create the render items of the model
This commit is contained in:
Sam Gateau 2019-10-10 16:08:42 -07:00 committed by GitHub
commit a68e34b3e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 388 additions and 230 deletions

View file

@ -5244,23 +5244,23 @@
"transitions": [ "transitions": [
{ {
"state": "idle", "state": "idle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5313,19 +5313,19 @@
"transitions": [ "transitions": [
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5380,19 +5380,19 @@
}, },
{ {
"state": "idle", "state": "idle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5469,19 +5469,19 @@
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "strafeRightHmd", "state": "strafeRightHmd",
@ -5533,19 +5533,19 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5597,19 +5597,19 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5661,19 +5661,19 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5725,19 +5725,19 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5794,19 +5794,19 @@
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnLeft", "state": "turnLeft",
@ -5859,19 +5859,19 @@
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5919,15 +5919,15 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "strafeLeftHmd", "state": "strafeLeftHmd",
@ -5935,11 +5935,11 @@
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -5983,15 +5983,15 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotMoving" "var": "isNotInput"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "strafeRightHmd", "state": "strafeRightHmd",
@ -5999,11 +5999,11 @@
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",
@ -6128,19 +6128,19 @@
"transitions": [ "transitions": [
{ {
"state": "WALKFWD", "state": "WALKFWD",
"var": "isMovingForward" "var": "isInputForward"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
"var": "isMovingBackward" "var": "isInputBackward"
}, },
{ {
"state": "STRAFERIGHT", "state": "STRAFERIGHT",
"var": "isMovingRight" "var": "isInputRight"
}, },
{ {
"state": "STRAFELEFT", "state": "STRAFELEFT",
"var": "isMovingLeft" "var": "isInputLeft"
}, },
{ {
"state": "turnRight", "state": "turnRight",

View file

@ -79,7 +79,7 @@ void AvatarDoctor::startDiagnosing() {
_missingTextureCount = 0; _missingTextureCount = 0;
_unsupportedTextureCount = 0; _unsupportedTextureCount = 0;
const auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(_avatarFSTFileUrl); const auto resource = DependencyManager::get<ModelCache>()->getModelResource(_avatarFSTFileUrl);
resource->refresh(); resource->refresh();
const auto resourceLoaded = [this, resource](bool success) { const auto resourceLoaded = [this, resource](bool success) {
@ -297,7 +297,7 @@ void AvatarDoctor::startDiagnosing() {
if (resource->isLoaded()) { if (resource->isLoaded()) {
resourceLoaded(!resource->isFailed()); resourceLoaded(!resource->isFailed());
} else { } else {
connect(resource.data(), &GeometryResource::finished, this, resourceLoaded); connect(resource.data(), &ModelResource::finished, this, resourceLoaded);
} }
} else { } else {
addError("Model file cannot be opened", "missing-file"); addError("Model file cannot be opened", "missing-file");

View file

@ -53,7 +53,7 @@ private:
int _materialMappingCount = 0; int _materialMappingCount = 0;
int _materialMappingLoadedCount = 0; int _materialMappingLoadedCount = 0;
GeometryResource::Pointer _model; ModelResource::Pointer _model;
bool _isDiagnosing = false; bool _isDiagnosing = false;
}; };

View file

@ -2496,7 +2496,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
if (_fullAvatarModelName.isEmpty()) { if (_fullAvatarModelName.isEmpty()) {
// Store the FST file name into preferences // Store the FST file name into preferences
const auto& mapping = _skeletonModel->getGeometry()->getMapping(); const auto& mapping = _skeletonModel->getNetworkModel()->getMapping();
if (mapping.value("name").isValid()) { if (mapping.value("name").isValid()) {
_fullAvatarModelName = mapping.value("name").toString(); _fullAvatarModelName = mapping.value("name").toString();
} }
@ -2504,7 +2504,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
initHeadBones(); initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet); _skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); _fstAnimGraphOverrideUrl = _skeletonModel->getNetworkModel()->getAnimGraphOverrideUrl();
initAnimGraph(); initAnimGraph();
initFlowFromFST(); initFlowFromFST();

View file

@ -315,6 +315,10 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
const float TALKING_TIME_THRESHOLD = 0.75f; const float TALKING_TIME_THRESHOLD = 0.75f;
params.isTalking = head->getTimeWithoutTalking() <= TALKING_TIME_THRESHOLD; params.isTalking = head->getTimeWithoutTalking() <= TALKING_TIME_THRESHOLD;
//pass X and Z input key floats (-1 to 1) to rig
params.inputX = myAvatar->getDriveKey(MyAvatar::TRANSLATE_X);
params.inputZ = myAvatar->getDriveKey(MyAvatar::TRANSLATE_Z);
myAvatar->updateRigControllerParameters(params); myAvatar->updateRigControllerParameters(params);
_rig.updateFromControllerParameters(params, deltaTime); _rig.updateFromControllerParameters(params, deltaTime);

View file

@ -134,7 +134,7 @@ bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) {
return _mathPick.loaded; return _mathPick.loaded;
} }
void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource) { void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource) {
ShapeType type = shapeInfo.getType(); ShapeType type = shapeInfo.getType();
glm::vec3 dimensions = pick.transform.getScale(); glm::vec3 dimensions = pick.transform.getScale();
QString modelURL = (resource ? resource->getURL().toString() : ""); QString modelURL = (resource ? resource->getURL().toString() : "");
@ -147,7 +147,7 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick,
} }
} }
void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource) { void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource) {
// This code was copied and modified from RenderableModelEntityItem::computeShapeInfo // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo
// TODO: Move to some shared code area (in entities-renderer? model-networking?) // TODO: Move to some shared code area (in entities-renderer? model-networking?)
// after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo
@ -381,7 +381,7 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e
_scaleWithParent(scaleWithParent), _scaleWithParent(scaleWithParent),
_physicsEngine(physicsEngine) { _physicsEngine(physicsEngine) {
if (collisionRegion.shouldComputeShapeInfo()) { if (collisionRegion.shouldComputeShapeInfo()) {
_cachedResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(collisionRegion.modelURL); _cachedResource = DependencyManager::get<ModelCache>()->getCollisionModelResource(collisionRegion.modelURL);
} }
_mathPick.loaded = isLoaded(); _mathPick.loaded = isLoaded();
} }

View file

@ -63,14 +63,14 @@ protected:
bool isLoaded() const; bool isLoaded() const;
// Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use.
bool getShapeInfoReady(const CollisionRegion& pick); bool getShapeInfoReady(const CollisionRegion& pick);
void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource); void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource);
void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource); void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource);
void filterIntersections(std::vector<ContactTestResult>& intersections) const; void filterIntersections(std::vector<ContactTestResult>& intersections) const;
bool _scaleWithParent; bool _scaleWithParent;
PhysicsEnginePointer _physicsEngine; PhysicsEnginePointer _physicsEngine;
QSharedPointer<GeometryResource> _cachedResource; QSharedPointer<ModelResource> _cachedResource;
// Options for what information to get from collision results // Options for what information to get from collision results
bool _includeNormals; bool _includeNormals;

View file

@ -2160,6 +2160,51 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
} }
} }
//deadzone constant
const float INPUT_DEADZONE_THRESHOLD = 0.05f;
if (fabsf(params.inputX) <= INPUT_DEADZONE_THRESHOLD && fabsf(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) {
// no WASD input
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", true);
} else if (fabsf(params.inputZ) >= fabsf(params.inputX)) {
if (params.inputZ > 0.0f) {
// forward
_animVars.set("isInputForward", true);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
} else {
// backward
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", true);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
}
} else {
if (params.inputX > 0.0f) {
// right
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", true);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
} else {
// left
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", true);
_animVars.set("isNotInput", false);
}
}
_headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled; _headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled;
bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled; bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled;
bool rightHandEnabled = params.primaryControllerFlags[PrimaryControllerType_RightHand] & (uint8_t)ControllerFlags::Enabled; bool rightHandEnabled = params.primaryControllerFlags[PrimaryControllerType_RightHand] & (uint8_t)ControllerFlags::Enabled;

View file

@ -88,6 +88,8 @@ public:
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
uint8_t secondaryControllerFlags[NumSecondaryControllerTypes]; uint8_t secondaryControllerFlags[NumSecondaryControllerTypes];
bool isTalking; bool isTalking;
float inputX;
float inputZ;
bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS]; bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS];
bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS]; bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS];
HFMJointShapeInfo hipsShapeInfo; HFMJointShapeInfo hipsShapeInfo;

View file

@ -955,7 +955,7 @@ void Avatar::simulateAttachments(float deltaTime) {
bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i); bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i);
// Watch for texture loading // Watch for texture loading
if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { if (!texturesLoaded && model->getNetworkModel() && model->getNetworkModel()->areTexturesLoaded()) {
_attachmentModelsTexturesLoaded[i] = true; _attachmentModelsTexturesLoaded[i] = true;
model->updateRenderItems(); model->updateRenderItems();
} }

View file

@ -177,7 +177,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
// FIXME: This texture loading logic should probably live in Avatar, to mirror RenderableModelEntityItem, // FIXME: This texture loading logic should probably live in Avatar, to mirror RenderableModelEntityItem,
// but Avatars don't get updates in the same way // but Avatars don't get updates in the same way
if (!_texturesLoaded && getGeometry() && getGeometry()->areTexturesLoaded()) { if (!_texturesLoaded && getNetworkModel() && getNetworkModel()->areTexturesLoaded()) {
_texturesLoaded = true; _texturesLoaded = true;
updateRenderItems(); updateRenderItems();
} }

View file

@ -282,7 +282,7 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
} }
void RenderableModelEntityItem::fetchCollisionGeometryResource() { void RenderableModelEntityItem::fetchCollisionGeometryResource() {
_collisionGeometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCollisionShapeURL()); _collisionGeometryResource = DependencyManager::get<ModelCache>()->getCollisionModelResource(getCollisionShapeURL());
} }
bool RenderableModelEntityItem::unableToLoadCollisionShape() { bool RenderableModelEntityItem::unableToLoadCollisionShape() {
@ -504,7 +504,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
meshes.push_back(hfmMesh._mesh); meshes.push_back(hfmMesh._mesh);
} }
} else { } else {
meshes = model->getGeometry()->getMeshes(); meshes = model->getNetworkModel()->getMeshes();
} }
int32_t numMeshes = (int32_t)(meshes.size()); int32_t numMeshes = (int32_t)(meshes.size());
@ -1431,7 +1431,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
} }
} }
if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { if (!_texturesLoaded && model->getNetworkModel() && model->getNetworkModel()->areTexturesLoaded()) {
withWriteLock([&] { withWriteLock([&] {
_texturesLoaded = true; _texturesLoaded = true;
}); });

View file

@ -120,7 +120,7 @@ private:
bool readyToAnimate() const; bool readyToAnimate() const;
void fetchCollisionGeometryResource(); void fetchCollisionGeometryResource();
GeometryResource::Pointer _collisionGeometryResource; ModelResource::Pointer _collisionGeometryResource;
std::vector<int> _jointMap; std::vector<int> _jointMap;
QVariantMap _originalTextures; QVariantMap _originalTextures;
bool _jointMapCompleted { false }; bool _jointMapCompleted { false };

View file

@ -194,7 +194,7 @@ float importanceSample3DDimension(float startDim) {
} }
ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties,
const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const ShapeType& shapeType, const ModelResource::Pointer& geometryResource,
const TriangleInfo& triangleInfo) { const TriangleInfo& triangleInfo) {
CpuParticle particle; CpuParticle particle;
@ -379,7 +379,7 @@ void ParticleEffectEntityRenderer::stepSimulation() {
particle::Properties particleProperties; particle::Properties particleProperties;
ShapeType shapeType; ShapeType shapeType;
GeometryResource::Pointer geometryResource; ModelResource::Pointer geometryResource;
withReadLock([&] { withReadLock([&] {
particleProperties = _particleProperties; particleProperties = _particleProperties;
shapeType = _shapeType; shapeType = _shapeType;
@ -482,7 +482,7 @@ void ParticleEffectEntityRenderer::fetchGeometryResource() {
if (hullURL.isEmpty()) { if (hullURL.isEmpty()) {
_geometryResource.reset(); _geometryResource.reset();
} else { } else {
_geometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL); _geometryResource = DependencyManager::get<ModelCache>()->getCollisionModelResource(hullURL);
} }
} }

View file

@ -89,7 +89,7 @@ private:
} _triangleInfo; } _triangleInfo;
static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties,
const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const ShapeType& shapeType, const ModelResource::Pointer& geometryResource,
const TriangleInfo& triangleInfo); const TriangleInfo& triangleInfo);
void stepSimulation(); void stepSimulation();
@ -108,7 +108,7 @@ private:
QString _compoundShapeURL; QString _compoundShapeURL;
void fetchGeometryResource(); void fetchGeometryResource();
GeometryResource::Pointer _geometryResource; ModelResource::Pointer _geometryResource;
NetworkTexturePointer _networkTexture; NetworkTexturePointer _networkTexture;
ScenePointer _scene; ScenePointer _scene;

View file

@ -345,7 +345,7 @@ bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, c
} }
bool ZoneEntityItem::contains(const glm::vec3& point) const { bool ZoneEntityItem::contains(const glm::vec3& point) const {
GeometryResource::Pointer resource = _shapeResource; ModelResource::Pointer resource = _shapeResource;
if (_shapeType == SHAPE_TYPE_COMPOUND && resource) { if (_shapeType == SHAPE_TYPE_COMPOUND && resource) {
if (resource->isLoaded()) { if (resource->isLoaded()) {
const HFMModel& hfmModel = resource->getHFMModel(); const HFMModel& hfmModel = resource->getHFMModel();
@ -462,7 +462,7 @@ void ZoneEntityItem::fetchCollisionGeometryResource() {
if (hullURL.isEmpty()) { if (hullURL.isEmpty()) {
_shapeResource.reset(); _shapeResource.reset();
} else { } else {
_shapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL); _shapeResource = DependencyManager::get<ModelCache>()->getCollisionModelResource(hullURL);
} }
} }

View file

@ -167,7 +167,7 @@ protected:
static bool _zonesArePickable; static bool _zonesArePickable;
void fetchCollisionGeometryResource(); void fetchCollisionGeometryResource();
GeometryResource::Pointer _shapeResource; ModelResource::Pointer _shapeResource;
}; };

View file

@ -145,6 +145,42 @@ public:
bool isLimbNode; // is this FBXModel transform is a "LimbNode" i.e. a joint bool isLimbNode; // is this FBXModel transform is a "LimbNode" i.e. a joint
}; };
glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
const QHash<QString, FBXModel>& fbxModels, QString nodeID, bool mixamoHack, const QString& url) {
glm::mat4 globalTransform;
QVector<QString> visitedNodes; // Used to prevent following a cycle
while (!nodeID.isNull()) {
visitedNodes.append(nodeID); // Append each node we visit
const FBXModel& fbxModel = fbxModels.value(nodeID);
globalTransform = glm::translate(fbxModel.translation) * fbxModel.preTransform * glm::mat4_cast(fbxModel.preRotation *
fbxModel.rotation * fbxModel.postRotation) * fbxModel.postTransform * globalTransform;
if (fbxModel.hasGeometricOffset) {
glm::mat4 geometricOffset = createMatFromScaleQuatAndPos(fbxModel.geometricScaling, fbxModel.geometricRotation, fbxModel.geometricTranslation);
globalTransform = globalTransform * geometricOffset;
}
if (mixamoHack) {
// there's something weird about the models from Mixamo Fuse; they don't skin right with the full transform
return globalTransform;
}
QList<QString> parentIDs = _connectionParentMap.values(nodeID);
nodeID = QString();
foreach(const QString& parentID, parentIDs) {
if (visitedNodes.contains(parentID)) {
qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url;
continue;
}
if (fbxModels.contains(parentID)) {
nodeID = parentID;
break;
}
}
}
return globalTransform;
}
std::vector<QString> getModelIDsForMeshID(const QString& meshID, const QHash<QString, FBXModel>& fbxModels, const QMultiMap<QString, QString>& _connectionParentMap) { std::vector<QString> getModelIDsForMeshID(const QString& meshID, const QHash<QString, FBXModel>& fbxModels, const QMultiMap<QString, QString>& _connectionParentMap) {
std::vector<QString> modelsForMesh; std::vector<QString> modelsForMesh;
if (fbxModels.contains(meshID)) { if (fbxModels.contains(meshID)) {
@ -494,8 +530,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
if (object.properties.at(2) == "Mesh") { if (object.properties.at(2) == "Mesh") {
meshes.insert(getID(object.properties), extractMesh(object, meshIndex, deduplicateIndices)); meshes.insert(getID(object.properties), extractMesh(object, meshIndex, deduplicateIndices));
} else { // object.properties.at(2) == "Shape" } else { // object.properties.at(2) == "Shape"
ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) }; ExtractedBlendshape blendshape = { getID(object.properties), extractBlendshape(object) };
blendshapes.append(extracted); blendshapes.append(blendshape);
} }
} else if (object.name == "Model") { } else if (object.name == "Model") {
QString name = getModelName(object.properties); QString name = getModelName(object.properties);
@ -669,8 +705,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
// add the blendshapes included in the model, if any // add the blendshapes included in the model, if any
if (mesh) { if (mesh) {
foreach (const ExtractedBlendshape& extracted, blendshapes) { foreach (const ExtractedBlendshape& blendshape, blendshapes) {
addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh); addBlendshapes(blendshape, blendshapeIndices.values(blendshape.id.toLatin1()), *mesh);
} }
} }
@ -1193,11 +1229,11 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
} }
// assign the blendshapes to their corresponding meshes // assign the blendshapes to their corresponding meshes
foreach (const ExtractedBlendshape& extracted, blendshapes) { foreach (const ExtractedBlendshape& blendshape, blendshapes) {
QString blendshapeChannelID = _connectionParentMap.value(extracted.id); QString blendshapeChannelID = _connectionParentMap.value(blendshape.id);
QString blendshapeID = _connectionParentMap.value(blendshapeChannelID); QString blendshapeID = _connectionParentMap.value(blendshapeChannelID);
QString meshID = _connectionParentMap.value(blendshapeID); QString meshID = _connectionParentMap.value(blendshapeID);
addBlendshapes(extracted, blendshapeChannelIndices.values(blendshapeChannelID), meshes[meshID]); addBlendshapes(blendshape, blendshapeChannelIndices.values(blendshapeChannelID), meshes[meshID]);
} }
// get offset transform from mapping // get offset transform from mapping
@ -1341,10 +1377,13 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
// Now that we've initialized the joint, we can define the transform // Now that we've initialized the joint, we can define the transform
// modelIDs is ordered from parent to children, so we can safely get parent transforms from earlier joints as we iterate // modelIDs is ordered from parent to children, so we can safely get parent transforms from earlier joints as we iterate
joint.globalTransform = glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation * joint.postRotation) * joint.postTransform; joint.localTransform = glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation * joint.postRotation) * joint.postTransform;
joint.globalTransform = joint.localTransform;
if (joint.parentIndex != -1 && joint.parentIndex < (int)jointIndex && !needMixamoHack) { if (joint.parentIndex != -1 && joint.parentIndex < (int)jointIndex && !needMixamoHack) {
hfm::Joint& parentJoint = hfmModel.joints[joint.parentIndex]; hfm::Joint& parentJoint = hfmModel.joints[joint.parentIndex];
joint.globalTransform = joint.globalTransform * parentJoint.globalTransform; // SG Change: i think this not correct and the [parent]*[local] is the correct answer here
//joint.globalTransform = joint.globalTransform * parentJoint.globalTransform;
joint.globalTransform = parentJoint.globalTransform * joint.localTransform;
if (parentJoint.hasGeometricOffset) { if (parentJoint.hasGeometricOffset) {
// Per the FBX standard, geometric offset should not propagate to children. // Per the FBX standard, geometric offset should not propagate to children.
// However, we must be careful when modifying the behavior of FBXSerializer. // However, we must be careful when modifying the behavior of FBXSerializer.
@ -1359,6 +1398,21 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
joint.globalTransform = joint.globalTransform * geometricOffset; joint.globalTransform = joint.globalTransform * geometricOffset;
} }
// TODO: Remove these lines, just here to make sure we are not breaking the transform computation
// QString modelID = fbxModels.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key());
glm::mat4 anotherModelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url);
auto col0 = (glm::epsilonNotEqual(anotherModelTransform[0], joint.globalTransform[0], 0.001f));
auto col1 = (glm::epsilonNotEqual(anotherModelTransform[1], joint.globalTransform[1], 0.001f));
auto col2 = (glm::epsilonNotEqual(anotherModelTransform[2], joint.globalTransform[2], 0.001f));
auto col3 = (glm::epsilonNotEqual(anotherModelTransform[3], joint.globalTransform[3], 0.001f));
if ( glm::any(col0)
|| glm::any(col1)
|| glm::any(col2)
|| glm::any(col3)) {
anotherModelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url);
// joint.globalTransform = anotherModelTransform;
}
hfmModel.joints.push_back(joint); hfmModel.joints.push_back(joint);
} }
@ -1426,6 +1480,12 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
// meshShapes will be added to hfmModel at the very end // meshShapes will be added to hfmModel at the very end
std::vector<hfm::Shape> meshShapes; std::vector<hfm::Shape> meshShapes;
meshShapes.reserve(instanceModelIDs.size() * mesh.parts.size()); meshShapes.reserve(instanceModelIDs.size() * mesh.parts.size());
if (instanceModelIDs.size() > 1) {
qCDebug(modelformat) << "Mesh " << meshID << " made of " << mesh.parts.size() << " parts is instanced " << instanceModelIDs.size() << " times!!!";
}
if (mesh.parts.size() < 1) {
qCDebug(modelformat) << "Mesh " << meshID << " made of " << mesh.parts.size() << " parts !!!!! ";
}
for (const QString& modelID : instanceModelIDs) { for (const QString& modelID : instanceModelIDs) {
// The transform node has the same indexing order as the joints // The transform node has the same indexing order as the joints
const uint32_t transformIndex = (uint32_t)modelIDs.indexOf(modelID); const uint32_t transformIndex = (uint32_t)modelIDs.indexOf(modelID);
@ -1447,6 +1507,14 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
shape.meshPart = i; shape.meshPart = i;
shape.transform = transformIndex; shape.transform = transformIndex;
auto matName = mesh.parts[i].materialID;
auto materialIt = materialNameToID.find(matName.toStdString());
if (materialIt != materialNameToID.end()) {
shape.material = materialIt->second;
} else {
qCDebug(modelformat) << "Unknown material ? " << matName;
}
shape.transformedExtents.reset(); shape.transformedExtents.reset();
// compute the shape extents from the transformed vertices // compute the shape extents from the transformed vertices
for (const glm::vec3& vertex : mesh.vertices) { for (const glm::vec3& vertex : mesh.vertices) {
@ -1492,6 +1560,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
} }
// For baked models with FBX_DRACO_MESH_VERSION >= 2, get materials from extracted.materialIDPerMeshPart // For baked models with FBX_DRACO_MESH_VERSION >= 2, get materials from extracted.materialIDPerMeshPart
if (!extracted.materialIDPerMeshPart.empty()) { if (!extracted.materialIDPerMeshPart.empty()) {
/* if (partShapes.size() == extracted.materialIDPerMeshPart.size()) {
for (uint32_t i = 0; i < (uint32_t)extracted.materialIDPerMeshPart.size(); ++i) { for (uint32_t i = 0; i < (uint32_t)extracted.materialIDPerMeshPart.size(); ++i) {
hfm::Shape& shape = partShapes[i]; hfm::Shape& shape = partShapes[i];
const std::string& materialID = extracted.materialIDPerMeshPart[i]; const std::string& materialID = extracted.materialIDPerMeshPart[i];
@ -1500,6 +1569,12 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
shape.material = materialIt->second; shape.material = materialIt->second;
} }
} }
} else {
for (int p = 0; p < mesh.parts.size(); p++) {
qCDebug(modelformat) << "mesh.parts[" << p <<"] is " << mesh.parts[p].materialID;
}
qCDebug(modelformat) << "partShapes is not the same size as materialIDPerMeshPart ?";
}*/
} }
// find the clusters with which the mesh is associated // find the clusters with which the mesh is associated

View file

@ -492,9 +492,15 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me
int& partIndexPlusOne = materialTextureParts[materialTexture]; int& partIndexPlusOne = materialTextureParts[materialTexture];
if (partIndexPlusOne == 0) { if (partIndexPlusOne == 0) {
data.extracted.mesh.parts.resize(data.extracted.mesh.parts.size() + 1); data.extracted.mesh.parts.resize(data.extracted.mesh.parts.size() + 1);
HFMMeshPart& part = data.extracted.mesh.parts.back();
// Figure out if this is the older way of defining the per-part material for baked FBX // Figure out if this is the older way of defining the per-part material for baked FBX
if (dracoMeshNodeVersion < 2) { if (dracoMeshNodeVersion >= 2) {
// Define the materialID now
if (materialID < dracoMaterialList.size()) {
part.materialID = QString(dracoMaterialList[materialID].c_str());
}
} else {
// Define the materialID later, based on the order of first appearance of the materials in the _connectionChildMap // Define the materialID later, based on the order of first appearance of the materials in the _connectionChildMap
data.extracted.partMaterialTextures.append(materialTexture); data.extracted.partMaterialTextures.append(materialTexture);
} }

View file

@ -120,6 +120,7 @@ public:
glm::vec3 geometricScaling; glm::vec3 geometricScaling;
// globalTransform is the transform of the joint with all parent transforms applied, plus the geometric offset // globalTransform is the transform of the joint with all parent transforms applied, plus the geometric offset
glm::mat4 localTransform;
glm::mat4 globalTransform; glm::mat4 globalTransform;
}; };

View file

@ -50,7 +50,7 @@ public:
Textures getTextures() { return _textures; } Textures getTextures() { return _textures; }
protected: protected:
friend class Geometry; friend class NetworkModel;
Textures _textures; Textures _textures;

View file

@ -203,23 +203,23 @@ QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) {
return textureBaseUrl.isValid() ? textureBaseUrl : url; return textureBaseUrl.isValid() ? textureBaseUrl : url;
} }
GeometryResource::GeometryResource(const GeometryResource& other) : ModelResource::ModelResource(const ModelResource& other) :
Resource(other), Resource(other),
Geometry(other), NetworkModel(other),
_modelLoader(other._modelLoader), _modelLoader(other._modelLoader),
_mappingPair(other._mappingPair), _mappingPair(other._mappingPair),
_textureBaseURL(other._textureBaseURL), _textureBaseURL(other._textureBaseURL),
_combineParts(other._combineParts), _combineParts(other._combineParts),
_isCacheable(other._isCacheable) _isCacheable(other._isCacheable)
{ {
if (other._geometryResource) { if (other._modelResource) {
_startedLoading = false; _startedLoading = false;
} }
} }
void GeometryResource::downloadFinished(const QByteArray& data) { void ModelResource::downloadFinished(const QByteArray& data) {
if (_effectiveBaseURL.fileName().toLower().endsWith(".fst")) { if (_effectiveBaseURL.fileName().toLower().endsWith(".fst")) {
PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString(), { { "url", _url.toString() } }); PROFILE_ASYNC_BEGIN(resource_parse_geometry, "ModelResource::downloadFinished", _url.toString(), { { "url", _url.toString() } });
// store parsed contents of FST file // store parsed contents of FST file
_mapping = FSTReader::readMapping(data); _mapping = FSTReader::readMapping(data);
@ -267,19 +267,19 @@ void GeometryResource::downloadFinished(const QByteArray& data) {
auto modelCache = DependencyManager::get<ModelCache>(); auto modelCache = DependencyManager::get<ModelCache>();
GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false }; GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false };
// Get the raw GeometryResource // Get the raw ModelResource
_geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash<GeometryExtra>()(extra)).staticCast<GeometryResource>(); _modelResource = modelCache->getResource(url, QUrl(), &extra, std::hash<GeometryExtra>()(extra)).staticCast<ModelResource>();
// Avoid caching nested resources - their references will be held by the parent // Avoid caching nested resources - their references will be held by the parent
_geometryResource->_isCacheable = false; _modelResource->_isCacheable = false;
if (_geometryResource->isLoaded()) { if (_modelResource->isLoaded()) {
onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty()); onGeometryMappingLoaded(!_modelResource->getURL().isEmpty());
} else { } else {
if (_connection) { if (_connection) {
disconnect(_connection); disconnect(_connection);
} }
_connection = connect(_geometryResource.data(), &Resource::finished, this, &GeometryResource::onGeometryMappingLoaded); _connection = connect(_modelResource.data(), &Resource::finished, this, &ModelResource::onGeometryMappingLoaded);
} }
} }
} else { } else {
@ -291,32 +291,32 @@ void GeometryResource::downloadFinished(const QByteArray& data) {
} }
} }
void GeometryResource::onGeometryMappingLoaded(bool success) { void ModelResource::onGeometryMappingLoaded(bool success) {
if (success && _geometryResource) { if (success && _modelResource) {
_hfmModel = _geometryResource->_hfmModel; _hfmModel = _modelResource->_hfmModel;
_materialMapping = _geometryResource->_materialMapping; _materialMapping = _modelResource->_materialMapping;
_meshParts = _geometryResource->_meshParts; // _meshParts = _modelResource->_meshParts;
_meshes = _geometryResource->_meshes; _meshes = _modelResource->_meshes;
_materials = _geometryResource->_materials; _materials = _modelResource->_materials;
// Avoid holding onto extra references // Avoid holding onto extra references
_geometryResource.reset(); _modelResource.reset();
// Make sure connection will not trigger again // Make sure connection will not trigger again
disconnect(_connection); // FIXME Should not have to do this disconnect(_connection); // FIXME Should not have to do this
} }
PROFILE_ASYNC_END(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString()); PROFILE_ASYNC_END(resource_parse_geometry, "ModelResource::downloadFinished", _url.toString());
finishedLoading(success); finishedLoading(success);
} }
void GeometryResource::setExtra(void* extra) { void ModelResource::setExtra(void* extra) {
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra); const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
_mappingPair = geometryExtra ? geometryExtra->mapping : GeometryMappingPair(QUrl(), QVariantHash()); _mappingPair = geometryExtra ? geometryExtra->mapping : GeometryMappingPair(QUrl(), QVariantHash());
_textureBaseURL = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); _textureBaseURL = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl();
_combineParts = geometryExtra ? geometryExtra->combineParts : true; _combineParts = geometryExtra ? geometryExtra->combineParts : true;
} }
void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) { void ModelResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) {
// Assume ownership of the processed HFMModel // Assume ownership of the processed HFMModel
_hfmModel = hfmModel; _hfmModel = hfmModel;
_materialMapping = materialMapping; _materialMapping = materialMapping;
@ -329,31 +329,23 @@ void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const M
} }
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>(); std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
int meshID = 0; int meshID = 0;
for (const HFMMesh& mesh : _hfmModel->meshes) { for (const HFMMesh& mesh : _hfmModel->meshes) {
// Copy mesh pointers // Copy mesh pointers
meshes->emplace_back(mesh._mesh); meshes->emplace_back(mesh._mesh);
int partID = 0;
for (const HFMMeshPart& part : mesh.parts) {
// Construct local parts
parts->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
partID++;
}
meshID++; meshID++;
} }
_meshes = meshes; _meshes = meshes;
_meshParts = parts;
finishedLoading(true); finishedLoading(true);
} }
void GeometryResource::deleter() { void ModelResource::deleter() {
resetTextures(); resetTextures();
Resource::deleter(); Resource::deleter();
} }
void GeometryResource::setTextures() { void ModelResource::setTextures() {
if (_hfmModel) { if (_hfmModel) {
for (const HFMMaterial& material : _hfmModel->materials) { for (const HFMMaterial& material : _hfmModel->materials) {
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseURL)); _materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseURL));
@ -361,7 +353,7 @@ void GeometryResource::setTextures() {
} }
} }
void GeometryResource::resetTextures() { void ModelResource::resetTextures() {
_materials.clear(); _materials.clear();
} }
@ -377,17 +369,17 @@ ModelCache::ModelCache() {
} }
QSharedPointer<Resource> ModelCache::createResource(const QUrl& url) { QSharedPointer<Resource> ModelCache::createResource(const QUrl& url) {
return QSharedPointer<Resource>(new GeometryResource(url, _modelLoader), &GeometryResource::deleter); return QSharedPointer<Resource>(new ModelResource(url, _modelLoader), &ModelResource::deleter);
} }
QSharedPointer<Resource> ModelCache::createResourceCopy(const QSharedPointer<Resource>& resource) { QSharedPointer<Resource> ModelCache::createResourceCopy(const QSharedPointer<Resource>& resource) {
return QSharedPointer<Resource>(new GeometryResource(*resource.staticCast<GeometryResource>()), &GeometryResource::deleter); return QSharedPointer<Resource>(new ModelResource(*resource.staticCast<ModelResource>()), &ModelResource::deleter);
} }
GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { ModelResource::Pointer ModelCache::getModelResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) {
bool combineParts = true; bool combineParts = true;
GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts };
GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash<GeometryExtra>()(geometryExtra)).staticCast<GeometryResource>(); ModelResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash<GeometryExtra>()(geometryExtra)).staticCast<ModelResource>();
if (resource) { if (resource) {
if (resource->isLoaded() && resource->shouldSetTextures()) { if (resource->isLoaded() && resource->shouldSetTextures()) {
resource->setTextures(); resource->setTextures();
@ -396,12 +388,12 @@ GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const
return resource; return resource;
} }
GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& url, ModelResource::Pointer ModelCache::getCollisionModelResource(const QUrl& url,
const GeometryMappingPair& mapping, const GeometryMappingPair& mapping,
const QUrl& textureBaseUrl) { const QUrl& textureBaseUrl) {
bool combineParts = false; bool combineParts = false;
GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts };
GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash<GeometryExtra>()(geometryExtra)).staticCast<GeometryResource>(); ModelResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash<GeometryExtra>()(geometryExtra)).staticCast<ModelResource>();
if (resource) { if (resource) {
if (resource->isLoaded() && resource->shouldSetTextures()) { if (resource->isLoaded() && resource->shouldSetTextures()) {
resource->setTextures(); resource->setTextures();
@ -410,7 +402,7 @@ GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& u
return resource; return resource;
} }
const QVariantMap Geometry::getTextures() const { const QVariantMap NetworkModel::getTextures() const {
QVariantMap textures; QVariantMap textures;
for (const auto& material : _materials) { for (const auto& material : _materials) {
for (const auto& texture : material->_textures) { for (const auto& texture : material->_textures) {
@ -424,22 +416,21 @@ const QVariantMap Geometry::getTextures() const {
} }
// FIXME: The materials should only be copied when modified, but the Model currently caches the original // FIXME: The materials should only be copied when modified, but the Model currently caches the original
Geometry::Geometry(const Geometry& geometry) { NetworkModel::NetworkModel(const NetworkModel& networkModel) {
_hfmModel = geometry._hfmModel; _hfmModel = networkModel._hfmModel;
_materialMapping = geometry._materialMapping; _materialMapping = networkModel._materialMapping;
_meshes = geometry._meshes; _meshes = networkModel._meshes;
_meshParts = geometry._meshParts;
_materials.reserve(geometry._materials.size()); _materials.reserve(networkModel._materials.size());
for (const auto& material : geometry._materials) { for (const auto& material : networkModel._materials) {
_materials.push_back(std::make_shared<NetworkMaterial>(*material)); _materials.push_back(std::make_shared<NetworkMaterial>(*material));
} }
_animGraphOverrideUrl = geometry._animGraphOverrideUrl; _animGraphOverrideUrl = networkModel._animGraphOverrideUrl;
_mapping = geometry._mapping; _mapping = networkModel._mapping;
} }
void Geometry::setTextures(const QVariantMap& textureMap) { void NetworkModel::setTextures(const QVariantMap& textureMap) {
if (_meshes->size() > 0) { if (_meshes->size() > 0) {
for (auto& material : _materials) { for (auto& material : _materials) {
// Check if any material textures actually changed // Check if any material textures actually changed
@ -447,7 +438,7 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
[&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.second.texture && textureMap.contains(it.second.name); })) { [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.second.texture && textureMap.contains(it.second.name); })) {
// FIXME: The Model currently caches the materials (waste of space!) // FIXME: The Model currently caches the materials (waste of space!)
// so they must be copied in the Geometry copy-ctor // so they must be copied in the NetworkModel copy-ctor
// if (material->isOriginal()) { // if (material->isOriginal()) {
// // Copy the material to avoid mutating the cached version // // Copy the material to avoid mutating the cached version
// material = std::make_shared<NetworkMaterial>(*material); // material = std::make_shared<NetworkMaterial>(*material);
@ -461,11 +452,11 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
// If we only use cached textures, they should all be loaded // If we only use cached textures, they should all be loaded
areTexturesLoaded(); areTexturesLoaded();
} else { } else {
qCWarning(modelnetworking) << "Ignoring setTextures(); geometry not ready"; qCWarning(modelnetworking) << "Ignoring setTextures(); NetworkModel not ready";
} }
} }
bool Geometry::areTexturesLoaded() const { bool NetworkModel::areTexturesLoaded() const {
if (!_areTexturesLoaded) { if (!_areTexturesLoaded) {
for (auto& material : _materials) { for (auto& material : _materials) {
if (material->isMissingTexture()) { if (material->isMissingTexture()) {
@ -500,30 +491,28 @@ bool Geometry::areTexturesLoaded() const {
return true; return true;
} }
const std::shared_ptr<NetworkMaterial> Geometry::getShapeMaterial(int partID) const { const std::shared_ptr<NetworkMaterial> NetworkModel::getShapeMaterial(int shapeID) const {
if ((partID >= 0) && (partID < (int)_meshParts->size())) { auto materialID = getHFMModel().shapes[shapeID].material;
int materialID = _meshParts->at(partID)->materialID;
if ((materialID >= 0) && (materialID < (int)_materials.size())) { if ((materialID >= 0) && (materialID < (int)_materials.size())) {
return _materials[materialID]; return _materials[materialID];
} }
}
return nullptr; return nullptr;
} }
void GeometryResourceWatcher::startWatching() { void ModelResourceWatcher::startWatching() {
connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); connect(_resource.data(), &Resource::finished, this, &ModelResourceWatcher::resourceFinished);
connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); connect(_resource.data(), &Resource::onRefresh, this, &ModelResourceWatcher::resourceRefreshed);
if (_resource->isLoaded()) { if (_resource->isLoaded()) {
resourceFinished(!_resource->getURL().isEmpty()); resourceFinished(!_resource->getURL().isEmpty());
} }
} }
void GeometryResourceWatcher::stopWatching() { void ModelResourceWatcher::stopWatching() {
disconnect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); disconnect(_resource.data(), &Resource::finished, this, &ModelResourceWatcher::resourceFinished);
disconnect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); disconnect(_resource.data(), &Resource::onRefresh, this, &ModelResourceWatcher::resourceRefreshed);
} }
void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { void ModelResourceWatcher::setResource(ModelResource::Pointer resource) {
if (_resource) { if (_resource) {
stopWatching(); stopWatching();
} }
@ -537,14 +526,14 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) {
} }
} }
void GeometryResourceWatcher::resourceFinished(bool success) { void ModelResourceWatcher::resourceFinished(bool success) {
if (success) { if (success) {
_geometryRef = std::make_shared<Geometry>(*_resource); _networkModelRef = std::make_shared<NetworkModel>(*_resource);
} }
emit finished(success); emit finished(success);
} }
void GeometryResourceWatcher::resourceRefreshed() { void ModelResourceWatcher::resourceRefreshed() {
// FIXME: Model is not set up to handle a refresh // FIXME: Model is not set up to handle a refresh
// _instance.reset(); // _instance.reset();
} }

View file

@ -22,23 +22,20 @@
#include <material-networking/TextureCache.h> #include <material-networking/TextureCache.h>
#include "ModelLoader.h" #include "ModelLoader.h"
class MeshPart;
using GeometryMappingPair = std::pair<QUrl, QVariantHash>; using GeometryMappingPair = std::pair<QUrl, QVariantHash>;
Q_DECLARE_METATYPE(GeometryMappingPair) Q_DECLARE_METATYPE(GeometryMappingPair)
class Geometry { class NetworkModel {
public: public:
using Pointer = std::shared_ptr<Geometry>; using Pointer = std::shared_ptr<NetworkModel>;
using WeakPointer = std::weak_ptr<Geometry>; using WeakPointer = std::weak_ptr<NetworkModel>;
Geometry() = default; NetworkModel() = default;
Geometry(const Geometry& geometry); NetworkModel(const NetworkModel& geometry);
virtual ~Geometry() = default; virtual ~NetworkModel() = default;
// Immutable over lifetime // Immutable over lifetime
using GeometryMeshes = std::vector<std::shared_ptr<const graphics::Mesh>>; using GeometryMeshes = std::vector<std::shared_ptr<const graphics::Mesh>>;
using GeometryMeshParts = std::vector<std::shared_ptr<const MeshPart>>;
// Mutable, but must retain structure of vector // Mutable, but must retain structure of vector
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>; using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
@ -63,7 +60,6 @@ protected:
HFMModel::ConstPointer _hfmModel; HFMModel::ConstPointer _hfmModel;
MaterialMapping _materialMapping; MaterialMapping _materialMapping;
std::shared_ptr<const GeometryMeshes> _meshes; std::shared_ptr<const GeometryMeshes> _meshes;
std::shared_ptr<const GeometryMeshParts> _meshParts;
// Copied to each geometry, mutable throughout lifetime via setTextures // Copied to each geometry, mutable throughout lifetime via setTextures
NetworkMaterials _materials; NetworkMaterials _materials;
@ -76,22 +72,22 @@ private:
}; };
/// A geometry loaded from the network. /// A geometry loaded from the network.
class GeometryResource : public Resource, public Geometry { class ModelResource : public Resource, public NetworkModel {
Q_OBJECT Q_OBJECT
public: public:
using Pointer = QSharedPointer<GeometryResource>; using Pointer = QSharedPointer<ModelResource>;
GeometryResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) {} ModelResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) {}
GeometryResource(const GeometryResource& other); ModelResource(const ModelResource& other);
QString getType() const override { return "Geometry"; } QString getType() const override { return "Model"; }
virtual void deleter() override; virtual void deleter() override;
virtual void downloadFinished(const QByteArray& data) override; virtual void downloadFinished(const QByteArray& data) override;
void setExtra(void* extra) override; void setExtra(void* extra) override;
virtual bool areTexturesLoaded() const override { return isLoaded() && Geometry::areTexturesLoaded(); } virtual bool areTexturesLoaded() const override { return isLoaded() && NetworkModel::areTexturesLoaded(); }
private slots: private slots:
void onGeometryMappingLoaded(bool success); void onGeometryMappingLoaded(bool success);
@ -115,21 +111,21 @@ private:
QUrl _textureBaseURL; QUrl _textureBaseURL;
bool _combineParts; bool _combineParts;
GeometryResource::Pointer _geometryResource; ModelResource::Pointer _modelResource;
QMetaObject::Connection _connection; QMetaObject::Connection _connection;
bool _isCacheable{ true }; bool _isCacheable{ true };
}; };
class GeometryResourceWatcher : public QObject { class ModelResourceWatcher : public QObject {
Q_OBJECT Q_OBJECT
public: public:
using Pointer = std::shared_ptr<GeometryResourceWatcher>; using Pointer = std::shared_ptr<ModelResourceWatcher>;
GeometryResourceWatcher() = delete; ModelResourceWatcher() = delete;
GeometryResourceWatcher(Geometry::Pointer& geometryPtr) : _geometryRef(geometryPtr) {} ModelResourceWatcher(NetworkModel::Pointer& geometryPtr) : _networkModelRef(geometryPtr) {}
void setResource(GeometryResource::Pointer resource); void setResource(ModelResource::Pointer resource);
QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
int getResourceDownloadAttempts() { return _resource ? _resource->getDownloadAttempts() : 0; } int getResourceDownloadAttempts() { return _resource ? _resource->getDownloadAttempts() : 0; }
@ -147,8 +143,8 @@ private slots:
void resourceRefreshed(); void resourceRefreshed();
private: private:
GeometryResource::Pointer _resource; ModelResource::Pointer _resource;
Geometry::Pointer& _geometryRef; NetworkModel::Pointer& _networkModelRef;
}; };
/// Stores cached model geometries. /// Stores cached model geometries.
@ -158,18 +154,18 @@ class ModelCache : public ResourceCache, public Dependency {
public: public:
GeometryResource::Pointer getGeometryResource(const QUrl& url, ModelResource::Pointer getModelResource(const QUrl& url,
const GeometryMappingPair& mapping = const GeometryMappingPair& mapping =
GeometryMappingPair(QUrl(), QVariantHash()), GeometryMappingPair(QUrl(), QVariantHash()),
const QUrl& textureBaseUrl = QUrl()); const QUrl& textureBaseUrl = QUrl());
GeometryResource::Pointer getCollisionGeometryResource(const QUrl& url, ModelResource::Pointer getCollisionModelResource(const QUrl& url,
const GeometryMappingPair& mapping = const GeometryMappingPair& mapping =
GeometryMappingPair(QUrl(), QVariantHash()), GeometryMappingPair(QUrl(), QVariantHash()),
const QUrl& textureBaseUrl = QUrl()); const QUrl& textureBaseUrl = QUrl());
protected: protected:
friend class GeometryResource; friend class ModelResource;
virtual QSharedPointer<Resource> createResource(const QUrl& url) override; virtual QSharedPointer<Resource> createResource(const QUrl& url) override;
QSharedPointer<Resource> createResourceCopy(const QSharedPointer<Resource>& resource) override; QSharedPointer<Resource> createResourceCopy(const QSharedPointer<Resource>& resource) override;
@ -180,12 +176,4 @@ private:
ModelLoader _modelLoader; ModelLoader _modelLoader;
}; };
class MeshPart {
public:
MeshPart(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {}
int meshID { -1 };
int partID { -1 };
int materialID { -1 };
};
#endif // hifi_ModelCache_h #endif // hifi_ModelCache_h

View file

@ -87,7 +87,7 @@ void CauterizedModel::createRenderItemSet() {
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr); _modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
auto material = getGeometry()->getShapeMaterial(shapeID); auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
@ -104,9 +104,11 @@ void CauterizedModel::updateClusterMatrices() {
if (!_needsUpdateClusterMatrices || !isLoaded()) { if (!_needsUpdateClusterMatrices || !isLoaded()) {
return; return;
} }
updateShapeStatesFromRig();
_needsUpdateClusterMatrices = false; _needsUpdateClusterMatrices = false;
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
for (int i = 0; i < (int)_meshStates.size(); i++) { for (int i = 0; i < (int)_meshStates.size(); i++) {
Model::MeshState& state = _meshStates[i]; Model::MeshState& state = _meshStates[i];
const HFMMesh& mesh = hfmModel.meshes.at(i); const HFMMesh& mesh = hfmModel.meshes.at(i);
@ -221,13 +223,14 @@ void CauterizedModel::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i]; auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
const auto& shapeState = self->getShapeState(i);
const auto& meshState = self->getMeshState(meshIndex); const auto& meshState = self->getMeshState(meshIndex);
const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData); CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
if (useDualQuaternionSkinning) { if (useDualQuaternionSkinning) {
@ -241,7 +244,7 @@ void CauterizedModel::updateRenderItems() {
} }
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) { /*if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0]; const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(), Transform transform(dq.getRotation(),
@ -253,6 +256,9 @@ void CauterizedModel::updateRenderItems() {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
} }
}*/
if (meshState.clusterMatrices.size() <= 1) {
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);

View file

@ -202,9 +202,13 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
assert(model && model->isLoaded()); assert(model && model->isLoaded());
auto shape = model->getHFMModel().shapes[shapeIndex];
assert(shape.mesh == meshIndex);
assert(shape.meshPart == partIndex);
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex);
_meshNumVertices = (int)modelMesh->getNumVertices(); _meshNumVertices = (int)modelMesh->getNumVertices();
const Model::MeshState& state = model->getMeshState(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex);
@ -217,8 +221,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
} }
updateTransform(transform, offsetTransform); updateTransform(transform, offsetTransform);
Transform renderTransform = transform; Transform renderTransform = transform;
if (useDualQuaternionSkinning) {
/* if (useDualQuaternionSkinning) {
if (state.clusterDualQuaternions.size() == 1) { if (state.clusterDualQuaternions.size() == 1) {
const auto& dq = state.clusterDualQuaternions[0]; const auto& dq = state.clusterDualQuaternions[0];
Transform transform(dq.getRotation(), Transform transform(dq.getRotation(),
@ -231,6 +237,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
} }
} }
*/
const Model::ShapeState& shapeState = model->getShapeState(shapeIndex);
renderTransform = transform.worldTransform(shapeState._rootFromJointTransform);
updateTransformForSkinnedMesh(renderTransform, transform); updateTransformForSkinnedMesh(renderTransform, transform);
initCache(model); initCache(model);
@ -263,7 +273,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
_hasTangents = !mesh.tangents.isEmpty(); _hasTangents = !mesh.tangents.isEmpty();
} }
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); auto networkMaterial = model->getNetworkModel()->getShapeMaterial(_shapeID);
if (networkMaterial) { if (networkMaterial) {
addMaterial(graphics::MaterialLayer(networkMaterial, 0)); addMaterial(graphics::MaterialLayer(networkMaterial, 0));
} }
@ -316,7 +326,8 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::Transfor
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) { void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
_transform = renderTransform; _transform = renderTransform;
_worldBound = _adjustedLocalBound; _worldBound = _adjustedLocalBound;
_worldBound.transform(boundTransform); // _worldBound.transform(boundTransform);
_worldBound.transform(renderTransform);
} }
// Note that this method is called for models but not for shapes // Note that this method is called for models but not for shapes

View file

@ -42,7 +42,7 @@
using namespace std; using namespace std;
int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>(); int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>(); int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<NetworkModel::WeakPointer>();
int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>(); int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>();
int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>"); int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>");
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
@ -71,7 +71,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); setSnapModelToRegistrationPoint(true, glm::vec3(0.5f));
connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); connect(&_renderWatcher, &ModelResourceWatcher::finished, this, &Model::loadURLFinished);
} }
Model::~Model() { Model::~Model() {
@ -151,7 +151,7 @@ void Model::setOffset(const glm::vec3& offset) {
} }
void Model::calculateTextureInfo() { void Model::calculateTextureInfo() {
if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) { if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) {
size_t textureSize = 0; size_t textureSize = 0;
int textureCount = 0; int textureCount = 0;
bool allTexturesLoaded = true; bool allTexturesLoaded = true;
@ -178,12 +178,12 @@ int Model::getRenderInfoTextureCount() {
} }
bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
if (!getGeometry()) { if (!getNetworkModel()) {
return true; return true;
} }
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
const auto& networkMeshes = getGeometry()->getMeshes(); const auto& networkMeshes = getNetworkModel()->getMeshes();
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups. // to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) { if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) {
@ -232,12 +232,13 @@ void Model::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i]; auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
const auto& shapeState = self->getShapeState(i);
const auto& meshState = self->getMeshState(meshIndex); const auto& meshState = self->getMeshState(meshIndex);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) { if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions); data.updateClusterBuffer(meshState.clusterDualQuaternions);
@ -249,7 +250,7 @@ void Model::updateRenderItems() {
Transform renderTransform = modelTransform; Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) { /*if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0]; const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(), Transform transform(dq.getRotation(),
@ -261,6 +262,9 @@ void Model::updateRenderItems() {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
} }
}*/
if (meshState.clusterMatrices.size() <= 1) {
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
@ -293,6 +297,21 @@ void Model::reset() {
} }
} }
void Model::updateShapeStatesFromRig() {
const HFMModel& hfmModel = getHFMModel();
// TODO: should all Models have a valid _rig?
{ // Shapes state:
const auto& shapes = hfmModel.shapes;
_shapeStates.resize(shapes.size());
for (int s = 0; s < shapes.size(); ++s) {
uint32_t jointId = shapes[s].transform;
if (jointId < _rig.getJointStateCount()) {
_shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(shapes[s].transform);
}
}
}
}
bool Model::updateGeometry() { bool Model::updateGeometry() {
bool needFullUpdate = false; bool needFullUpdate = false;
@ -307,6 +326,8 @@ bool Model::updateGeometry() {
initJointStates(); initJointStates();
assert(_meshStates.empty()); assert(_meshStates.empty());
updateShapeStatesFromRig();
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
int i = 0; int i = 0;
foreach (const HFMMesh& mesh, hfmModel.meshes) { foreach (const HFMMesh& mesh, hfmModel.meshes) {
@ -643,8 +664,8 @@ glm::mat4 Model::getWorldToHFMMatrix() const {
// TODO: deprecate and remove // TODO: deprecate and remove
MeshProxyList Model::getMeshes() const { MeshProxyList Model::getMeshes() const {
MeshProxyList result; MeshProxyList result;
const Geometry::Pointer& renderGeometry = getGeometry(); const NetworkModel::Pointer& renderGeometry = getNetworkModel();
const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes(); const NetworkModel::GeometryMeshes& meshes = renderGeometry->getMeshes();
if (!isLoaded()) { if (!isLoaded()) {
return result; return result;
@ -772,7 +793,7 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto& materialName = _modelMeshMaterialNames[shapeID]; auto& materialName = _modelMeshMaterialNames[shapeID];
result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, materialName); result.appendMaterial(graphics::MaterialLayer(getNetworkModel()->getShapeMaterial(shapeID), 0), shapeID, materialName);
{ {
std::unique_lock<std::mutex> lock(_materialMappingMutex); std::unique_lock<std::mutex> lock(_materialMappingMutex);
@ -1196,7 +1217,7 @@ void Model::setURL(const QUrl& url) {
invalidCalculatedMeshBoxes(); invalidCalculatedMeshBoxes();
deleteGeometry(); deleteGeometry();
auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(url); auto resource = DependencyManager::get<ModelCache>()->getModelResource(url);
if (resource) { if (resource) {
resource->setLoadPriority(this, _loadingPriority); resource->setLoadPriority(this, _loadingPriority);
_renderWatcher.setResource(resource); _renderWatcher.setResource(resource);
@ -1385,6 +1406,8 @@ void Model::updateClusterMatrices() {
return; return;
} }
updateShapeStatesFromRig();
_needsUpdateClusterMatrices = false; _needsUpdateClusterMatrices = false;
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
for (int i = 0; i < (int) _meshStates.size(); i++) { for (int i = 0; i < (int) _meshStates.size(); i++) {
@ -1418,6 +1441,7 @@ void Model::updateClusterMatrices() {
void Model::deleteGeometry() { void Model::deleteGeometry() {
_deleteGeometryCounter++; _deleteGeometryCounter++;
_shapeStates.clear();
_meshStates.clear(); _meshStates.clear();
_rig.destroyAnimGraph(); _rig.destroyAnimGraph();
_blendedBlendshapeCoefficients.clear(); _blendedBlendshapeCoefficients.clear();
@ -1487,7 +1511,7 @@ void Model::createRenderItemSet() {
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
auto material = getGeometry()->getShapeMaterial(shapeID); auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
@ -1496,7 +1520,7 @@ void Model::createRenderItemSet() {
} }
bool Model::isRenderable() const { bool Model::isRenderable() const {
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); return (!_shapeStates.empty() && !_meshStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty());
} }
std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) { std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
@ -1680,14 +1704,13 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
} }
class CollisionRenderGeometry : public Geometry { class CollisionRenderGeometry : public NetworkModel {
public: public:
CollisionRenderGeometry(graphics::MeshPointer mesh) { CollisionRenderGeometry(graphics::MeshPointer mesh) {
_hfmModel = std::make_shared<HFMModel>(); _hfmModel = std::make_shared<HFMModel>();
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>(); std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
meshes->push_back(mesh); meshes->push_back(mesh);
_meshes = meshes; _meshes = meshes;
_meshParts = std::shared_ptr<const GeometryMeshParts>();
} }
}; };
@ -1838,7 +1861,7 @@ void Blender::run() {
bool Model::maybeStartBlender() { bool Model::maybeStartBlender() {
if (isLoaded()) { if (isLoaded()) {
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getGeometry()->getConstHFMModelPointer(), QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getNetworkModel()->getConstHFMModelPointer(),
++_blendNumber, _blendshapeCoefficients)); ++_blendNumber, _blendshapeCoefficients));
return true; return true;
} }

View file

@ -178,7 +178,7 @@ public:
virtual void updateClusterMatrices(); virtual void updateClusterMatrices();
/// Returns a reference to the shared geometry. /// Returns a reference to the shared geometry.
const Geometry::Pointer& getGeometry() const { return _renderGeometry; } const NetworkModel::Pointer& getNetworkModel() const { return _renderGeometry; }
const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); } const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
Q_INVOKABLE virtual void setTextures(const QVariantMap& textures); Q_INVOKABLE virtual void setTextures(const QVariantMap& textures);
@ -343,6 +343,12 @@ public:
const MeshState& getMeshState(int index) { return _meshStates.at(index); } const MeshState& getMeshState(int index) { return _meshStates.at(index); }
class ShapeState {
public:
glm::mat4 _rootFromJointTransform;
};
const ShapeState& getShapeState(int index) { return _shapeStates.at(index); }
uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } uint32_t getGeometryCounter() const { return _deleteGeometryCounter; }
const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItemsMap; } const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItemsMap; }
BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; } BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; }
@ -391,9 +397,9 @@ protected:
/// \return true if joint exists /// \return true if joint exists
bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointPosition(int jointIndex, glm::vec3& position) const;
Geometry::Pointer _renderGeometry; // only ever set by its watcher NetworkModel::Pointer _renderGeometry; // only ever set by its watcher
GeometryResourceWatcher _renderWatcher; ModelResourceWatcher _renderWatcher;
SpatiallyNestable* _spatiallyNestableOverride; SpatiallyNestable* _spatiallyNestableOverride;
@ -420,6 +426,8 @@ protected:
glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to
std::vector<MeshState> _meshStates; std::vector<MeshState> _meshStates;
std::vector<ShapeState> _shapeStates;
void updateShapeStatesFromRig();
virtual void initJointStates(); virtual void initJointStates();
@ -515,7 +523,7 @@ private:
}; };
Q_DECLARE_METATYPE(ModelPointer) Q_DECLARE_METATYPE(ModelPointer)
Q_DECLARE_METATYPE(Geometry::WeakPointer) Q_DECLARE_METATYPE(NetworkModel::WeakPointer)
Q_DECLARE_METATYPE(BlendshapeOffset) Q_DECLARE_METATYPE(BlendshapeOffset)
/// Handle management of pending models that need blending /// Handle management of pending models that need blending