first cut at rendering avatars as individual model items

This commit is contained in:
ZappoMan 2015-06-02 16:54:47 -07:00
parent 507158e510
commit 4ce27f1483
7 changed files with 84 additions and 35 deletions

View file

@ -292,6 +292,20 @@ static TextRenderer* textRenderer(TextRendererType type) {
return displayNameRenderer; return displayNameRenderer;
} }
bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
auto avatarPayload = new render::Payload<AvatarData>(self);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
_renderItemID = scene->allocateID();
pendingChanges.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel.addToScene(scene, pendingChanges);
return true;
}
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
_skeletonModel.removeFromScene(scene, pendingChanges);
}
void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) {
if (_referential) { if (_referential) {
_referential->update(); _referential->update();
@ -504,6 +518,17 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
} }
void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) {
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
if (_skeletonModel.needsFixupInScene()) {
qDebug() << "Avatar::renderBody() FIXING _skeletonModel";
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
_skeletonModel.removeFromScene(scene, pendingChanges);
_skeletonModel.addToScene(scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
}
{ {
Glower glower(renderArgs, glowLevel); Glower glower(renderArgs, glowLevel);
@ -518,7 +543,8 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool
if (postLighting) { if (postLighting) {
getHand()->render(renderArgs, false); getHand()->render(renderArgs, false);
} else { } else {
_skeletonModel.render(renderArgs, 1.0f); // NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene
//_skeletonModel.render(renderArgs, 1.0f);
renderAttachments(renderArgs); renderAttachments(renderArgs);
} }
} }

View file

@ -83,6 +83,12 @@ public:
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition,
bool postLighting = false); bool postLighting = false);
bool addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges);
void removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges);
//setters //setters
void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); }
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; } void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }

View file

@ -63,13 +63,8 @@ void AvatarManager::init() {
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar); _avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::ScenePointer scene = Application::getInstance()->getMain3DScene();
auto avatarPayload = new render::Payload<AvatarData>(_myAvatar);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
static_cast<Avatar*>(_myAvatar.get())->_renderItemID = scene->allocateID();
render::PendingChanges pendingChanges; render::PendingChanges pendingChanges;
pendingChanges.resetItem(static_cast<Avatar*>(_myAvatar.get())->_renderItemID, avatarPayloadPointer); _myAvatar->addToScene(_myAvatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
} }
@ -145,18 +140,11 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
// virtual // virtual
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) { AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::ScenePointer scene = Application::getInstance()->getMain3DScene();
auto avatarPayload = new render::Payload<AvatarData>(avatar);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
static_cast<Avatar*>(avatar.get())->_renderItemID = scene->allocateID();
render::PendingChanges pendingChanges; render::PendingChanges pendingChanges;
pendingChanges.resetItem(static_cast<Avatar*>(avatar.get())->_renderItemID, avatarPayloadPointer); avatar->addToScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
return avatar; return avatar;
} }
@ -177,17 +165,19 @@ void AvatarManager::removeAvatarMotionState(Avatar* avatar) {
void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
AvatarHash::iterator avatarIterator = _avatarHash.find(sessionUUID); AvatarHash::iterator avatarIterator = _avatarHash.find(sessionUUID);
if (avatarIterator != _avatarHash.end()) { if (avatarIterator != _avatarHash.end()) {
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().get()); //Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().get());
if (avatar != _myAvatar.get() && avatar->isInitialized()) { std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
removeAvatarMotionState(avatar);
// FIX ME! Can we just say (avatar != _myAvatar)
if (avatar != _myAvatar && avatar->isInitialized()) {
removeAvatarMotionState(avatar.get());
_avatarFades.push_back(avatarIterator.value()); _avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator); _avatarHash.erase(avatarIterator);
} }
render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges; render::PendingChanges pendingChanges;
pendingChanges.removeItem(avatar->_renderItemID); avatar->removeFromScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
} }
} }

View file

@ -1168,10 +1168,21 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
} }
void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) {
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
return; // wait until both models are loaded return; // wait until both models are loaded
} }
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
if (_skeletonModel.needsFixupInScene()) {
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
_skeletonModel.removeFromScene(scene, pendingChanges);
_skeletonModel.addToScene(scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
}
Camera *camera = Application::getInstance()->getCamera(); Camera *camera = Application::getInstance()->getCamera();
const glm::vec3 cameraPos = camera->getPosition(); const glm::vec3 cameraPos = camera->getPosition();
@ -1192,7 +1203,9 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo
// Render the body's voxels and head // Render the body's voxels and head
if (!postLighting) { if (!postLighting) {
_skeletonModel.render(renderArgs, 1.0f);
// NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene
//_skeletonModel.render(renderArgs, 1.0f);
renderAttachments(renderArgs); renderAttachments(renderArgs);
} }

View file

@ -255,9 +255,12 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
} }
void SkeletonModel::updateJointState(int index) { void SkeletonModel::updateJointState(int index) {
if (index > _jointStates.size()) {
return; // bail
}
JointState& state = _jointStates[index]; JointState& state = _jointStates[index];
const FBXJoint& joint = state.getFBXJoint(); const FBXJoint& joint = state.getFBXJoint();
if (joint.parentIndex != -1) { if (joint.parentIndex != -1 && joint.parentIndex <= _jointStates.size()) {
const JointState& parentState = _jointStates.at(joint.parentIndex); const JointState& parentState = _jointStates.at(joint.parentIndex);
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (index == geometry.leanJointIndex) { if (index == geometry.leanJointIndex) {

View file

@ -406,6 +406,7 @@ void Model::reset() {
} }
_meshGroupsKnown = false; _meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
} }
bool Model::updateGeometry() { bool Model::updateGeometry() {
@ -456,6 +457,7 @@ bool Model::updateGeometry() {
_dilatedTextures.clear(); _dilatedTextures.clear();
_geometry = geometry; _geometry = geometry;
_meshGroupsKnown = false; _meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
initJointStates(newJointStates); initJointStates(newJointStates);
needToRebuild = true; needToRebuild = true;
} else if (_jointStates.isEmpty()) { } else if (_jointStates.isEmpty()) {
@ -812,7 +814,7 @@ namespace render {
template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) { template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) {
if (payload) { if (payload) {
return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); //return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
} }
return render::Item::Bound(); return render::Item::Bound();
} }
@ -857,6 +859,10 @@ namespace render {
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
if (!_meshGroupsKnown && isLoadedWithTextures()) {
segregateMeshGroups();
}
bool somethingAdded = false; bool somethingAdded = false;
// allow the attachments to add to scene // allow the attachments to add to scene
foreach (Model* attachment, _attachments) { foreach (Model* attachment, _attachments) {
@ -880,6 +886,8 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
_renderItems << item; _renderItems << item;
somethingAdded = true; somethingAdded = true;
} }
_readyWhenAdded = readyToAddToScene();
return somethingAdded; return somethingAdded;
} }
@ -894,6 +902,7 @@ void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::Pendin
pendingChanges.removeItem(item); pendingChanges.removeItem(item);
} }
_renderItems.clear(); _renderItems.clear();
_readyWhenAdded = false;
} }
bool Model::render(RenderArgs* renderArgs, float alpha) { bool Model::render(RenderArgs* renderArgs, float alpha) {
@ -1921,6 +1930,7 @@ void Model::applyNextGeometry() {
_baseGeometry = _nextBaseGeometry; _baseGeometry = _nextBaseGeometry;
_geometry = _nextGeometry; _geometry = _nextGeometry;
_meshGroupsKnown = false; _meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
_nextBaseGeometry.reset(); _nextBaseGeometry.reset();
_nextGeometry.reset(); _nextGeometry.reset();
} }
@ -2210,21 +2220,16 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) {
if (_calculatedMeshPartBoxesValid && _calculatedMeshPartBoxes.contains(QPair<int,int>(meshIndex, partIndex))) { if (_calculatedMeshPartBoxesValid && _calculatedMeshPartBoxes.contains(QPair<int,int>(meshIndex, partIndex))) {
return _calculatedMeshPartBoxes[QPair<int,int>(meshIndex, partIndex)]; return _calculatedMeshPartBoxes[QPair<int,int>(meshIndex, partIndex)];
} }
if (!_calculatedMeshBoxesValid) { if (!_calculatedMeshBoxesValid && _calculatedMeshBoxes.size() > meshIndex) {
return _calculatedMeshBoxes[meshIndex]; return _calculatedMeshBoxes[meshIndex];
} }
return AABox(); return AABox();
} }
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {
renderSetup(args); if (!_readyWhenAdded) {
return; // bail asap
/*
if (translucent) {
renderCore(args, 1.0f);
return;
} }
*/
auto textureCache = DependencyManager::get<TextureCache>(); auto textureCache = DependencyManager::get<TextureCache>();
gpu::Batch& batch = *(args->_batch); gpu::Batch& batch = *(args->_batch);
@ -2236,23 +2241,25 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
} }
_transforms[0] = _viewState->getViewTransform(); _transforms[0] = _viewState->getViewTransform();
// apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space) // apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space)
_transforms[0].preTranslate(-_translation); _transforms[0].preTranslate(-_translation);
batch.setViewTransform(_transforms[0]); batch.setViewTransform(_transforms[0]);
const float OPAQUE_ALPHA_THRESHOLD = 0.5f; const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
auto alphaThreshold = translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME auto alphaThreshold = translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes(); const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
// guard against partially loaded meshes
if (meshIndex >= networkMeshes.size() || meshIndex >= geometry.meshes.size() || meshIndex >= _meshStates.size() ) {
return;
}
const NetworkMesh& networkMesh = networkMeshes.at(meshIndex); const NetworkMesh& networkMesh = networkMeshes.at(meshIndex);
const FBXMesh& mesh = geometry.meshes.at(meshIndex); const FBXMesh& mesh = geometry.meshes.at(meshIndex);
const MeshState& state = _meshStates.at(meshIndex); const MeshState& state = _meshStates.at(meshIndex);
bool translucentMesh = translucent; // networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size(); bool translucentMesh = translucent; // networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
bool hasTangents = !mesh.tangents.isEmpty(); bool hasTangents = !mesh.tangents.isEmpty();
bool hasSpecular = mesh.hasSpecularTexture(); bool hasSpecular = mesh.hasSpecularTexture();
@ -2277,6 +2284,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) { if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) {
_meshGroupsKnown = false; // regenerate these lists next time around. _meshGroupsKnown = false; // regenerate these lists next time around.
_readyWhenAdded = false; // in case any of our users are using scenes
return; // FIXME! return; // FIXME!
} }
@ -2606,6 +2614,7 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) { if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) {
_meshGroupsKnown = false; // regenerate these lists next time around. _meshGroupsKnown = false; // regenerate these lists next time around.
_readyWhenAdded = false; // in case any of our users are using scenes
continue; continue;
} }

View file

@ -123,6 +123,7 @@ public:
static void endScene(RenderArgs* args); static void endScene(RenderArgs* args);
// new Scene/Engine rendering support // new Scene/Engine rendering support
bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); }
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return isRenderable() && isActive() && isLoadedWithTextures(); } bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return isRenderable() && isActive() && isLoadedWithTextures(); }
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges); bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges); void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
@ -542,6 +543,7 @@ private:
QSet<std::shared_ptr<TransparentMeshPart>> _transparentRenderItems; QSet<std::shared_ptr<TransparentMeshPart>> _transparentRenderItems;
QSet<std::shared_ptr<OpaqueMeshPart>> _opaqueRenderItems; QSet<std::shared_ptr<OpaqueMeshPart>> _opaqueRenderItems;
QSet<render::ItemID> _renderItems; QSet<render::ItemID> _renderItems;
bool _readyWhenAdded = false;
}; };
Q_DECLARE_METATYPE(QPointer<Model>) Q_DECLARE_METATYPE(QPointer<Model>)