mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 19:29:47 +02:00
Render a different model when in first person view.
Currently this model is identical to the third person model, except that the head bones have been 'cauterized' by applying a zero scale transform. This allows us to set the near clip back to a reasonable value.
This commit is contained in:
parent
1cb7d0c1a5
commit
99a03bac21
11 changed files with 205 additions and 23 deletions
|
@ -3306,6 +3306,9 @@ namespace render {
|
||||||
|
|
||||||
|
|
||||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly, bool billboard) {
|
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly, bool billboard) {
|
||||||
|
|
||||||
|
_myAvatar->preRender(renderArgs);
|
||||||
|
|
||||||
activeRenderingThread = QThread::currentThread();
|
activeRenderingThread = QThread::currentThread();
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
PerformanceTimer perfTimer("display");
|
PerformanceTimer perfTimer("display");
|
||||||
|
|
|
@ -445,10 +445,10 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
|
||||||
_skeletonModel.renderJointCollisionShapes(0.7f);
|
_skeletonModel.renderJointCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderHead && shouldRenderHead(renderArgs, cameraPosition)) {
|
if (renderHead && shouldRenderHead(renderArgs)) {
|
||||||
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
if (renderBounding && shouldRenderHead(renderArgs, cameraPosition)) {
|
if (renderBounding && shouldRenderHead(renderArgs)) {
|
||||||
_skeletonModel.renderBoundingCollisionShapes(0.7f);
|
_skeletonModel.renderBoundingCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,6 +533,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::fixupModelsInScene() {
|
void Avatar::fixupModelsInScene() {
|
||||||
|
|
||||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
// 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
|
// fix them up in the scene
|
||||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,7 +237,7 @@ protected:
|
||||||
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const;
|
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const;
|
||||||
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||||
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
|
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();
|
virtual void fixupModelsInScene();
|
||||||
|
|
||||||
void simulateAttachments(float deltaTime);
|
void simulateAttachments(float deltaTime);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <GeometryUtil.h>
|
#include <GeometryUtil.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
#include <PathUtils.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <ShapeCollider.h>
|
#include <ShapeCollider.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
@ -96,8 +97,12 @@ MyAvatar::MyAvatar() :
|
||||||
_feetTouchFloor(true),
|
_feetTouchFloor(true),
|
||||||
_isLookingAtLeftEye(true),
|
_isLookingAtLeftEye(true),
|
||||||
_realWorldFieldOfView("realWorldFieldOfView",
|
_realWorldFieldOfView("realWorldFieldOfView",
|
||||||
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES)
|
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
|
||||||
|
_currentSkeletonModel(nullptr),
|
||||||
|
_firstPersonSkeletonModel(this)
|
||||||
{
|
{
|
||||||
|
_firstPersonSkeletonModel.setIsFirstPerson(true);
|
||||||
|
|
||||||
ShapeCollider::initDispatchTable();
|
ShapeCollider::initDispatchTable();
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||||
_driveKeys[i] = 0.0f;
|
_driveKeys[i] = 0.0f;
|
||||||
|
@ -131,6 +136,7 @@ QByteArray MyAvatar::toByteArray() {
|
||||||
|
|
||||||
void MyAvatar::reset() {
|
void MyAvatar::reset() {
|
||||||
_skeletonModel.reset();
|
_skeletonModel.reset();
|
||||||
|
_firstPersonSkeletonModel.reset();
|
||||||
getHead()->reset();
|
getHead()->reset();
|
||||||
|
|
||||||
_targetVelocity = glm::vec3(0.0f);
|
_targetVelocity = glm::vec3(0.0f);
|
||||||
|
@ -189,6 +195,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
_skeletonModel.simulate(deltaTime);
|
_skeletonModel.simulate(deltaTime);
|
||||||
|
_firstPersonSkeletonModel.simulate(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_skeletonModel.hasSkeleton()) {
|
if (!_skeletonModel.hasSkeleton()) {
|
||||||
|
@ -993,6 +1000,11 @@ void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||||
_billboardValid = false;
|
_billboardValid = false;
|
||||||
|
|
||||||
|
if (_useFullAvatar) {
|
||||||
|
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_body.fst");
|
||||||
|
_firstPersonSkeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL, true, !isMyAvatar());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||||
|
@ -1176,18 +1188,12 @@ 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() && _firstPersonSkeletonModel.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
|
// 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);
|
getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
|
||||||
}
|
}
|
||||||
if (postLighting) {
|
if (postLighting) {
|
||||||
|
@ -1195,12 +1201,42 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setCurrentSkeletonModel(SkeletonModel* skeletonModel) {
|
||||||
|
if (_currentSkeletonModel != skeletonModel && skeletonModel->isActive() && skeletonModel->isRenderable()) {
|
||||||
|
|
||||||
|
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||||
|
|
||||||
|
if (_currentSkeletonModel) {
|
||||||
|
_currentSkeletonModel->setVisibleInScene(false, scene);
|
||||||
|
}
|
||||||
|
skeletonModel->setVisibleInScene(true, scene);
|
||||||
|
_currentSkeletonModel = skeletonModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||||
|
|
||||||
|
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||||
|
|
||||||
|
_skeletonModel.initWhenReady(scene);
|
||||||
|
_firstPersonSkeletonModel.initWhenReady(scene);
|
||||||
|
|
||||||
|
// set visiblity on each model
|
||||||
|
if (shouldRenderHead(renderArgs)) {
|
||||||
|
setCurrentSkeletonModel(&_skeletonModel);
|
||||||
|
} else {
|
||||||
|
setCurrentSkeletonModel(&_firstPersonSkeletonModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
||||||
|
|
||||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
|
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||||
|
const glm::vec3 cameraPos = Application::getInstance()->getCamera()->getPosition();
|
||||||
const Head* head = getHead();
|
const Head* head = getHead();
|
||||||
return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
|
return ((renderArgs->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) ||
|
||||||
(glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
|
(Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
|
||||||
|
(glm::length(cameraPos - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateOrientation(float deltaTime) {
|
void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
|
@ -35,11 +35,12 @@ public:
|
||||||
void reset();
|
void reset();
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
void simulate(float deltaTime);
|
void simulate(float deltaTime);
|
||||||
|
void preRender(RenderArgs* renderArgs);
|
||||||
void updateFromTrackers(float deltaTime);
|
void updateFromTrackers(float deltaTime);
|
||||||
|
|
||||||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override;
|
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 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();
|
void renderDebugBodyPoints();
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
|
@ -210,6 +211,9 @@ private:
|
||||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||||
|
|
||||||
|
void setCurrentSkeletonModel(SkeletonModel* skeletonModel);
|
||||||
|
void initModelWhenReady(Model* model);
|
||||||
|
|
||||||
glm::vec3 _gravity;
|
glm::vec3 _gravity;
|
||||||
|
|
||||||
float _driveKeys[MAX_DRIVE_KEYS];
|
float _driveKeys[MAX_DRIVE_KEYS];
|
||||||
|
@ -265,6 +269,10 @@ private:
|
||||||
QString _headModelName;
|
QString _headModelName;
|
||||||
QString _bodyModelName;
|
QString _bodyModelName;
|
||||||
QString _fullAvatarModelName;
|
QString _fullAvatarModelName;
|
||||||
|
|
||||||
|
// used for rendering when in first person view or when in an HMD.
|
||||||
|
SkeletonModel* _currentSkeletonModel;
|
||||||
|
SkeletonModel _firstPersonSkeletonModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MyAvatar_h
|
#endif // hifi_MyAvatar_h
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "SkeletonModel.h"
|
#include "SkeletonModel.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
#include "InterfaceLogging.h"
|
||||||
|
|
||||||
enum StandingFootState {
|
enum StandingFootState {
|
||||||
LEFT_FOOT,
|
LEFT_FOOT,
|
||||||
|
@ -38,7 +39,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
||||||
_standingFoot(NO_FOOT),
|
_standingFoot(NO_FOOT),
|
||||||
_standingOffset(0.0f),
|
_standingOffset(0.0f),
|
||||||
_clampedFootPosition(0.0f),
|
_clampedFootPosition(0.0f),
|
||||||
_headClipDistance(DEFAULT_NEAR_CLIP)
|
_headClipDistance(DEFAULT_NEAR_CLIP),
|
||||||
|
_isFirstPerson(false)
|
||||||
{
|
{
|
||||||
assert(_owningAvatar);
|
assert(_owningAvatar);
|
||||||
_enableShapes = true;
|
_enableShapes = true;
|
||||||
|
@ -98,7 +100,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
setRotation(_owningAvatar->getOrientation() * refOrientation);
|
setRotation(_owningAvatar->getOrientation() * refOrientation);
|
||||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
|
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
|
||||||
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
||||||
|
|
||||||
Model::simulate(deltaTime, fullUpdate);
|
Model::simulate(deltaTime, fullUpdate);
|
||||||
|
|
||||||
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
||||||
|
@ -140,6 +142,11 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_isFirstPerson) {
|
||||||
|
cauterizeHead();
|
||||||
|
updateClusterMatrices();
|
||||||
|
}
|
||||||
|
|
||||||
_boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset);
|
_boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset);
|
||||||
_boundingShape.setRotation(_rotation);
|
_boundingShape.setRotation(_rotation);
|
||||||
}
|
}
|
||||||
|
@ -806,3 +813,57 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
|
||||||
bool SkeletonModel::hasSkeleton() {
|
bool SkeletonModel::hasSkeleton() {
|
||||||
return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;
|
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; }
|
float getHeadClipDistance() const { return _headClipDistance; }
|
||||||
|
|
||||||
|
void setIsFirstPerson(bool value) { _isFirstPerson = value; }
|
||||||
|
bool getIsFirstPerson() const { return _isFirstPerson; }
|
||||||
|
|
||||||
|
virtual void onInvalidate() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void skeletonLoaded();
|
void skeletonLoaded();
|
||||||
|
@ -132,7 +137,11 @@ protected:
|
||||||
void maybeUpdateLeanRotation(const JointState& parentState, JointState& state);
|
void maybeUpdateLeanRotation(const JointState& parentState, JointState& state);
|
||||||
void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state);
|
||||||
void maybeUpdateEyeRotation(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:
|
private:
|
||||||
|
|
||||||
void renderJointConstraints(int jointIndex);
|
void renderJointConstraints(int jointIndex);
|
||||||
|
@ -164,6 +173,9 @@ private:
|
||||||
glm::vec3 _clampedFootPosition;
|
glm::vec3 _clampedFootPosition;
|
||||||
|
|
||||||
float _headClipDistance; // Near clip distance to use if no separate head model
|
float _headClipDistance; // Near clip distance to use if no separate head model
|
||||||
|
|
||||||
|
bool _isFirstPerson;
|
||||||
|
std::vector<int> _headBones;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_SkeletonModel_h
|
#endif // hifi_SkeletonModel_h
|
||||||
|
|
|
@ -31,7 +31,7 @@ const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
||||||
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
||||||
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
||||||
//const float DEFAULT_NEAR_CLIP = 0.08f;
|
//const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||||
const float DEFAULT_NEAR_CLIP = 0.25f;
|
const float DEFAULT_NEAR_CLIP = 0.1f;
|
||||||
const float DEFAULT_FAR_CLIP = (float)TREE_SCALE;
|
const float DEFAULT_FAR_CLIP = (float)TREE_SCALE;
|
||||||
|
|
||||||
class ViewFrustum {
|
class ViewFrustum {
|
||||||
|
|
|
@ -106,6 +106,9 @@ public:
|
||||||
glm::quat computeParentRotation() const;
|
glm::quat computeParentRotation() const;
|
||||||
glm::quat computeVisibleParentRotation() const;
|
glm::quat computeVisibleParentRotation() const;
|
||||||
|
|
||||||
|
void setTransform(const glm::mat4& transform) { _transform = transform; }
|
||||||
|
void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
|
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
|
||||||
/// debug helper function
|
/// 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.
|
_readyWhenAdded = false; // reset out render items.
|
||||||
_needsReload = true;
|
_needsReload = true;
|
||||||
invalidCalculatedMeshBoxes();
|
invalidCalculatedMeshBoxes();
|
||||||
|
|
||||||
_url = url;
|
_url = url;
|
||||||
|
|
||||||
|
onInvalidate();
|
||||||
|
|
||||||
// if so instructed, keep the current geometry until the new one is loaded
|
// if so instructed, keep the current geometry until the new one is loaded
|
||||||
_nextBaseGeometry = _nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
|
_nextBaseGeometry = _nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
|
||||||
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
|
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
|
||||||
|
@ -1380,6 +1382,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) {
|
void Model::simulateInternal(float deltaTime) {
|
||||||
// update the world space transforms for all joints
|
// update the world space transforms for all joints
|
||||||
|
|
||||||
|
@ -2120,6 +2142,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() :
|
ModelBlender::ModelBlender() :
|
||||||
_pendingBlenders(0) {
|
_pendingBlenders(0) {
|
||||||
|
|
|
@ -240,6 +240,8 @@ public:
|
||||||
AABox getPartBounds(int meshIndex, int partIndex);
|
AABox getPartBounds(int meshIndex, int partIndex);
|
||||||
void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent);
|
void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent);
|
||||||
|
|
||||||
|
bool initWhenReady(render::ScenePointer scene);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
||||||
|
@ -312,6 +314,12 @@ protected:
|
||||||
_calculatedMeshTrianglesValid = false;
|
_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:
|
private:
|
||||||
|
|
||||||
friend class AnimationHandle;
|
friend class AnimationHandle;
|
||||||
|
|
Loading…
Reference in a new issue