mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 02:53:43 +02:00
Merge pull request #5175 from hyperlogic/ajt/first-person-avatar
Render a different model when in first person view.
This commit is contained in:
commit
77bbb23a1e
11 changed files with 231 additions and 21 deletions
|
@ -3306,6 +3306,11 @@ namespace render {
|
|||
|
||||
|
||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly, bool billboard) {
|
||||
|
||||
// FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
_myAvatar->preRender(renderArgs);
|
||||
|
||||
activeRenderingThread = QThread::currentThread();
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("display");
|
||||
|
|
|
@ -445,10 +445,10 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
|||
_skeletonModel.renderJointCollisionShapes(0.7f);
|
||||
}
|
||||
|
||||
if (renderHead && shouldRenderHead(renderArgs, cameraPosition)) {
|
||||
if (renderHead && shouldRenderHead(renderArgs)) {
|
||||
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
||||
}
|
||||
if (renderBounding && shouldRenderHead(renderArgs, cameraPosition)) {
|
||||
if (renderBounding && shouldRenderHead(renderArgs)) {
|
||||
_skeletonModel.renderBoundingCollisionShapes(0.7f);
|
||||
}
|
||||
|
||||
|
@ -533,6 +533,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
}
|
||||
|
||||
void Avatar::fixupModelsInScene() {
|
||||
|
||||
// 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
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
|
@ -581,7 +582,7 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool
|
|||
getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
|
||||
}
|
||||
|
||||
bool Avatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
|
||||
bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ protected:
|
|||
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const;
|
||||
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const;
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
|
||||
virtual void fixupModelsInScene();
|
||||
|
||||
void simulateAttachments(float deltaTime);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <GeometryUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -96,8 +97,12 @@ MyAvatar::MyAvatar() :
|
|||
_feetTouchFloor(true),
|
||||
_isLookingAtLeftEye(true),
|
||||
_realWorldFieldOfView("realWorldFieldOfView",
|
||||
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES)
|
||||
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
|
||||
_firstPersonSkeletonModel(this),
|
||||
_prevShouldDrawHead(true)
|
||||
{
|
||||
_firstPersonSkeletonModel.setIsFirstPerson(true);
|
||||
|
||||
ShapeCollider::initDispatchTable();
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
@ -131,6 +136,7 @@ QByteArray MyAvatar::toByteArray() {
|
|||
|
||||
void MyAvatar::reset() {
|
||||
_skeletonModel.reset();
|
||||
_firstPersonSkeletonModel.reset();
|
||||
getHead()->reset();
|
||||
|
||||
_targetVelocity = glm::vec3(0.0f);
|
||||
|
@ -189,6 +195,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
_firstPersonSkeletonModel.simulate(deltaTime);
|
||||
}
|
||||
|
||||
if (!_skeletonModel.hasSkeleton()) {
|
||||
|
@ -986,16 +993,35 @@ QString MyAvatar::getModelDescription() const {
|
|||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
|
||||
Avatar::setFaceModelURL(faceModelURL);
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
getHead()->getFaceModel().setVisibleInScene(_prevShouldDrawHead, scene);
|
||||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
|
||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
_billboardValid = false;
|
||||
|
||||
if (_useFullAvatar) {
|
||||
_skeletonModel.setVisibleInScene(_prevShouldDrawHead, scene);
|
||||
|
||||
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst");
|
||||
_firstPersonSkeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
|
||||
_firstPersonSkeletonModel.setVisibleInScene(!_prevShouldDrawHead, scene);
|
||||
} else {
|
||||
_skeletonModel.setVisibleInScene(true, scene);
|
||||
|
||||
_firstPersonSkeletonModel.setVisibleInScene(false, scene);
|
||||
_firstPersonSkeletonModel.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(const QUrl&, fullAvatarURL),
|
||||
|
@ -1177,17 +1203,13 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
|
|||
void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) {
|
||||
|
||||
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||
return; // wait until both models are loaded
|
||||
return; // wait until all 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
|
||||
fixupModelsInScene();
|
||||
|
||||
const glm::vec3 cameraPos = Application::getInstance()->getCamera()->getPosition();
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
if (shouldRenderHead(renderArgs, cameraPos)) {
|
||||
if (shouldRenderHead(renderArgs)) {
|
||||
getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
|
||||
}
|
||||
if (postLighting) {
|
||||
|
@ -1195,12 +1217,51 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) {
|
||||
if (model->isActive() && model->isRenderable()) {
|
||||
model->setVisibleInScene(visible, scene);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
|
||||
_skeletonModel.initWhenReady(scene);
|
||||
if (_useFullAvatar) {
|
||||
_firstPersonSkeletonModel.initWhenReady(scene);
|
||||
}
|
||||
|
||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||
if (_useFullAvatar) {
|
||||
if (shouldDrawHead) {
|
||||
_skeletonModel.setVisibleInScene(true, scene);
|
||||
_firstPersonSkeletonModel.setVisibleInScene(false, scene);
|
||||
} else {
|
||||
_skeletonModel.setVisibleInScene(false, scene);
|
||||
_firstPersonSkeletonModel.setVisibleInScene(true, scene);
|
||||
}
|
||||
} else {
|
||||
getHead()->getFaceModel().setVisibleInScene(shouldDrawHead, scene);
|
||||
}
|
||||
|
||||
}
|
||||
_prevShouldDrawHead = shouldDrawHead;
|
||||
}
|
||||
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
||||
|
||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
|
||||
bool MyAvatar::cameraInsideHead() const {
|
||||
const Head* head = getHead();
|
||||
return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
|
||||
(glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
|
||||
const glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
||||
return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * _scale);
|
||||
}
|
||||
|
||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||
return ((renderArgs->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) ||
|
||||
(Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
|
||||
!cameraInsideHead());
|
||||
}
|
||||
|
||||
void MyAvatar::updateOrientation(float deltaTime) {
|
||||
|
|
|
@ -35,11 +35,12 @@ public:
|
|||
void reset();
|
||||
void update(float deltaTime);
|
||||
void simulate(float deltaTime);
|
||||
void preRender(RenderArgs* renderArgs);
|
||||
void updateFromTrackers(float deltaTime);
|
||||
|
||||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override;
|
||||
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f) override;
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const override;
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override;
|
||||
void renderDebugBodyPoints();
|
||||
|
||||
// setters
|
||||
|
@ -206,10 +207,14 @@ signals:
|
|||
|
||||
private:
|
||||
|
||||
bool cameraInsideHead() const;
|
||||
|
||||
// These are made private for MyAvatar so that you will use the "use" methods instead
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
||||
|
||||
glm::vec3 _gravity;
|
||||
|
||||
float _driveKeys[MAX_DRIVE_KEYS];
|
||||
|
@ -265,6 +270,10 @@ private:
|
|||
QString _headModelName;
|
||||
QString _bodyModelName;
|
||||
QString _fullAvatarModelName;
|
||||
|
||||
// used for rendering when in first person view or when in an HMD.
|
||||
SkeletonModel _firstPersonSkeletonModel;
|
||||
bool _prevShouldDrawHead;
|
||||
};
|
||||
|
||||
#endif // hifi_MyAvatar_h
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Menu.h"
|
||||
#include "SkeletonModel.h"
|
||||
#include "Util.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
enum StandingFootState {
|
||||
LEFT_FOOT,
|
||||
|
@ -38,7 +39,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
|||
_standingFoot(NO_FOOT),
|
||||
_standingOffset(0.0f),
|
||||
_clampedFootPosition(0.0f),
|
||||
_headClipDistance(DEFAULT_NEAR_CLIP)
|
||||
_headClipDistance(DEFAULT_NEAR_CLIP),
|
||||
_isFirstPerson(false)
|
||||
{
|
||||
assert(_owningAvatar);
|
||||
_enableShapes = true;
|
||||
|
@ -98,7 +100,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
setRotation(_owningAvatar->getOrientation() * refOrientation);
|
||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
|
||||
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
||||
|
||||
|
||||
Model::simulate(deltaTime, fullUpdate);
|
||||
|
||||
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
||||
|
@ -140,6 +142,11 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
||||
}
|
||||
|
||||
if (_isFirstPerson) {
|
||||
cauterizeHead();
|
||||
updateClusterMatrices();
|
||||
}
|
||||
|
||||
_boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset);
|
||||
_boundingShape.setRotation(_rotation);
|
||||
}
|
||||
|
@ -806,3 +813,57 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
|
|||
bool SkeletonModel::hasSkeleton() {
|
||||
return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;
|
||||
}
|
||||
|
||||
void SkeletonModel::initHeadBones() {
|
||||
_headBones.clear();
|
||||
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
||||
const int neckJointIndex = fbxGeometry.neckJointIndex;
|
||||
std::queue<int> q;
|
||||
q.push(neckJointIndex);
|
||||
_headBones.push_back(neckJointIndex);
|
||||
|
||||
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
|
||||
while (q.size() > 0) {
|
||||
int jointIndex = q.front();
|
||||
for (int i = 0; i < fbxGeometry.joints.size(); i++) {
|
||||
const FBXJoint& fbxJoint = fbxGeometry.joints[i];
|
||||
if (jointIndex == fbxJoint.parentIndex) {
|
||||
_headBones.push_back(i);
|
||||
q.push(i);
|
||||
}
|
||||
}
|
||||
q.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::invalidateHeadBones() {
|
||||
_headBones.clear();
|
||||
}
|
||||
|
||||
void SkeletonModel::cauterizeHead() {
|
||||
if (isActive()) {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const int neckJointIndex = geometry.neckJointIndex;
|
||||
if (neckJointIndex > 0 && neckJointIndex < _jointStates.size()) {
|
||||
|
||||
// lazy init of headBones
|
||||
if (_headBones.size() == 0) {
|
||||
initHeadBones();
|
||||
}
|
||||
|
||||
// preserve the translation for the neck
|
||||
glm::vec4 trans = _jointStates[neckJointIndex].getTransform()[3];
|
||||
glm::vec4 zero(0, 0, 0, 0);
|
||||
for (const int &i : _headBones) {
|
||||
JointState& joint = _jointStates[i];
|
||||
glm::mat4 newXform(zero, zero, zero, trans);
|
||||
joint.setTransform(newXform);
|
||||
joint.setVisibleTransform(newXform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonModel::onInvalidate() {
|
||||
invalidateHeadBones();
|
||||
}
|
||||
|
|
|
@ -112,6 +112,11 @@ public:
|
|||
|
||||
float getHeadClipDistance() const { return _headClipDistance; }
|
||||
|
||||
void setIsFirstPerson(bool value) { _isFirstPerson = value; }
|
||||
bool getIsFirstPerson() const { return _isFirstPerson; }
|
||||
|
||||
virtual void onInvalidate() override;
|
||||
|
||||
signals:
|
||||
|
||||
void skeletonLoaded();
|
||||
|
@ -132,7 +137,11 @@ protected:
|
|||
void maybeUpdateLeanRotation(const JointState& parentState, JointState& state);
|
||||
void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||
void maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||
|
||||
|
||||
void cauterizeHead();
|
||||
void initHeadBones();
|
||||
void invalidateHeadBones();
|
||||
|
||||
private:
|
||||
|
||||
void renderJointConstraints(int jointIndex);
|
||||
|
@ -164,6 +173,9 @@ private:
|
|||
glm::vec3 _clampedFootPosition;
|
||||
|
||||
float _headClipDistance; // Near clip distance to use if no separate head model
|
||||
|
||||
bool _isFirstPerson;
|
||||
std::vector<int> _headBones;
|
||||
};
|
||||
|
||||
#endif // hifi_SkeletonModel_h
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
||||
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
||||
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
||||
//const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||
const float DEFAULT_NEAR_CLIP = 0.25f;
|
||||
const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||
const float DEFAULT_FAR_CLIP = (float)TREE_SCALE;
|
||||
|
||||
class ViewFrustum {
|
||||
|
|
|
@ -106,6 +106,9 @@ public:
|
|||
glm::quat computeParentRotation() const;
|
||||
glm::quat computeVisibleParentRotation() const;
|
||||
|
||||
void setTransform(const glm::mat4& transform) { _transform = transform; }
|
||||
void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; }
|
||||
|
||||
private:
|
||||
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
|
||||
/// debug helper function
|
||||
|
|
|
@ -1102,9 +1102,11 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
|
|||
_readyWhenAdded = false; // reset out render items.
|
||||
_needsReload = true;
|
||||
invalidCalculatedMeshBoxes();
|
||||
|
||||
|
||||
_url = url;
|
||||
|
||||
onInvalidate();
|
||||
|
||||
// if so instructed, keep the current geometry until the new one is loaded
|
||||
_nextBaseGeometry = _nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
|
||||
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
|
||||
|
@ -1368,6 +1370,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
|||
// because ray picking needs valid boxes to work
|
||||
_calculatedMeshBoxesValid = false;
|
||||
_calculatedMeshTrianglesValid = false;
|
||||
onInvalidate();
|
||||
|
||||
// check for scale to fit
|
||||
if (_scaleToFit && !_scaledToFit) {
|
||||
|
@ -1380,6 +1383,26 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
|||
}
|
||||
}
|
||||
|
||||
void Model::updateClusterMatrices() {
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
glm::mat4 modelToWorld = glm::mat4_cast(_rotation);
|
||||
for (int i = 0; i < _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
if (_showTrueJointTransforms) {
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getVisibleTransform() * cluster.inverseBindMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::simulateInternal(float deltaTime) {
|
||||
// update the world space transforms for all joints
|
||||
|
||||
|
@ -2120,6 +2143,34 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
|
|||
}
|
||||
}
|
||||
|
||||
bool Model::initWhenReady(render::ScenePointer scene) {
|
||||
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoadedWithTextures()) {
|
||||
segregateMeshGroups();
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
foreach (auto renderItem, _transparentRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
|
||||
_renderItems.insert(item, renderPayload);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _opaqueRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
|
||||
_renderItems.insert(item, renderPayload);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
_readyWhenAdded = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelBlender::ModelBlender() :
|
||||
_pendingBlenders(0) {
|
||||
|
|
|
@ -240,6 +240,8 @@ public:
|
|||
AABox getPartBounds(int meshIndex, int partIndex);
|
||||
void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent);
|
||||
|
||||
bool initWhenReady(render::ScenePointer scene);
|
||||
|
||||
protected:
|
||||
QSharedPointer<NetworkGeometry> _geometry;
|
||||
|
||||
|
@ -312,6 +314,12 @@ protected:
|
|||
_calculatedMeshTrianglesValid = false;
|
||||
}
|
||||
|
||||
// rebuild the clusterMatrices from the current jointStates
|
||||
void updateClusterMatrices();
|
||||
|
||||
// hook for derived classes to be notified when setUrl invalidates the current model.
|
||||
virtual void onInvalidate() {};
|
||||
|
||||
private:
|
||||
|
||||
friend class AnimationHandle;
|
||||
|
|
Loading…
Reference in a new issue