mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
Merge pull request #2179 from ey6es/master
Better frame rates on loading by reading cached data from disk in worker thread, render billboards if we haven't loaded the models yet, use voxel LOD parameter to control avatar LODs, too.
This commit is contained in:
commit
7ce427b35c
9 changed files with 35 additions and 28 deletions
|
@ -1612,6 +1612,13 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::updateLOD() {
|
||||||
|
// adjust it unless we were asked to disable this feature
|
||||||
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
|
||||||
|
Menu::getInstance()->autoAdjustLOD(_fps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::updateMouseRay() {
|
void Application::updateMouseRay() {
|
||||||
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
@ -1852,6 +1859,8 @@ void Application::update(float deltaTime) {
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::update()");
|
PerformanceWarning warn(showWarnings, "Application::update()");
|
||||||
|
|
||||||
|
updateLOD();
|
||||||
|
|
||||||
// check what's under the mouse and update the mouse voxel
|
// check what's under the mouse and update the mouse voxel
|
||||||
updateMouseRay();
|
updateMouseRay();
|
||||||
|
|
||||||
|
@ -2325,14 +2334,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"Application::displaySide() ... voxels...");
|
"Application::displaySide() ... voxels...");
|
||||||
|
|
||||||
_voxels.render();
|
_voxels.render();
|
||||||
|
|
||||||
// double check that our LOD doesn't need to be auto-adjusted
|
|
||||||
// adjust it unless we were asked to disable this feature
|
|
||||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
|
|
||||||
Menu::getInstance()->autoAdjustLOD(_fps);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// also, metavoxels
|
// also, metavoxels
|
||||||
|
|
|
@ -284,6 +284,7 @@ private:
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
// Various helper functions called during update()
|
// Various helper functions called during update()
|
||||||
|
void updateLOD();
|
||||||
void updateMouseRay();
|
void updateMouseRay();
|
||||||
void updateFaceshift();
|
void updateFaceshift();
|
||||||
void updateVisage();
|
void updateVisage();
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
void autoAdjustLOD(float currentFPS);
|
void autoAdjustLOD(float currentFPS);
|
||||||
void setVoxelSizeScale(float sizeScale);
|
void setVoxelSizeScale(float sizeScale);
|
||||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||||
|
float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; }
|
||||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,8 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
|
||||||
}
|
}
|
||||||
|
|
||||||
float Avatar::getLODDistance() const {
|
float Avatar::getLODDistance() const {
|
||||||
return glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
|
return Menu::getInstance()->getAvatarLODDistanceMultiplier() *
|
||||||
|
glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::simulate(float deltaTime) {
|
void Avatar::simulate(float deltaTime) {
|
||||||
|
@ -305,13 +306,11 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::renderBody() {
|
void Avatar::renderBody() {
|
||||||
if (_shouldRenderBillboard) {
|
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||||
|
// render the billboard until both models are loaded
|
||||||
renderBillboard();
|
renderBillboard();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
|
||||||
return; // wait until both models are loaded
|
|
||||||
}
|
|
||||||
_skeletonModel.render(1.0f);
|
_skeletonModel.render(1.0f);
|
||||||
getHead()->render(1.0f);
|
getHead()->render(1.0f);
|
||||||
getHand()->render(false);
|
getHand()->render(false);
|
||||||
|
|
|
@ -450,7 +450,7 @@ class GeometryReader : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
|
GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
|
||||||
const QByteArray& data, const QVariantHash& mapping);
|
QNetworkReply* reply, const QVariantHash& mapping);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
|
@ -458,40 +458,41 @@ private:
|
||||||
|
|
||||||
QWeakPointer<Resource> _geometry;
|
QWeakPointer<Resource> _geometry;
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
QByteArray _data;
|
QNetworkReply* _reply;
|
||||||
QVariantHash _mapping;
|
QVariantHash _mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
|
GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
|
||||||
const QByteArray& data, const QVariantHash& mapping) :
|
QNetworkReply* reply, const QVariantHash& mapping) :
|
||||||
_geometry(geometry),
|
_geometry(geometry),
|
||||||
_url(url),
|
_url(url),
|
||||||
_data(data),
|
_reply(reply),
|
||||||
_mapping(mapping) {
|
_mapping(mapping) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryReader::run() {
|
void GeometryReader::run() {
|
||||||
QSharedPointer<Resource> geometry = _geometry.toStrongRef();
|
QSharedPointer<Resource> geometry = _geometry.toStrongRef();
|
||||||
if (geometry.isNull()) {
|
if (geometry.isNull()) {
|
||||||
|
_reply->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
|
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
|
||||||
_url.path().toLower().endsWith(".svo") ? readSVO(_data) : readFBX(_data, _mapping)));
|
_url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
|
||||||
|
|
||||||
} catch (const QString& error) {
|
} catch (const QString& error) {
|
||||||
qDebug() << "Error reading " << _url << ": " << error;
|
qDebug() << "Error reading " << _url << ": " << error;
|
||||||
QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
|
QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
|
||||||
}
|
}
|
||||||
|
_reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
|
void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
|
||||||
QUrl url = reply->url();
|
QUrl url = reply->url();
|
||||||
QByteArray data = reply->readAll();
|
|
||||||
|
|
||||||
if (url.path().toLower().endsWith(".fst")) {
|
if (url.path().toLower().endsWith(".fst")) {
|
||||||
// it's a mapping file; parse it and get the mesh filename
|
// it's a mapping file; parse it and get the mesh filename
|
||||||
_mapping = readMapping(data);
|
_mapping = readMapping(reply->readAll());
|
||||||
|
reply->deleteLater();
|
||||||
QString filename = _mapping.value("filename").toString();
|
QString filename = _mapping.value("filename").toString();
|
||||||
if (filename.isNull()) {
|
if (filename.isNull()) {
|
||||||
qDebug() << "Mapping file " << url << " has no filename.";
|
qDebug() << "Mapping file " << url << " has no filename.";
|
||||||
|
@ -525,7 +526,7 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the reader off to the thread pool
|
// send the reader off to the thread pool
|
||||||
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping));
|
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
||||||
|
|
|
@ -273,27 +273,28 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
||||||
class ImageReader : public QRunnable {
|
class ImageReader : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data);
|
ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QWeakPointer<Resource> _texture;
|
QWeakPointer<Resource> _texture;
|
||||||
QByteArray _data;
|
QNetworkReply* _reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data) :
|
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply) :
|
||||||
_texture(texture),
|
_texture(texture),
|
||||||
_data(data) {
|
_reply(reply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageReader::run() {
|
void ImageReader::run() {
|
||||||
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
||||||
if (texture.isNull()) {
|
if (texture.isNull()) {
|
||||||
|
_reply->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QImage image = QImage::fromData(_data);
|
QImage image = QImage::fromData(_reply->readAll());
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
if (image.format() != QImage::Format_ARGB32) {
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
}
|
}
|
||||||
|
@ -320,11 +321,12 @@ void ImageReader::run() {
|
||||||
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
|
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
|
||||||
Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)),
|
Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)),
|
||||||
Q_ARG(bool, translucentPixels >= imageArea / 2));
|
Q_ARG(bool, translucentPixels >= imageArea / 2));
|
||||||
|
_reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkTexture::downloadFinished(QNetworkReply* reply) {
|
void NetworkTexture::downloadFinished(QNetworkReply* reply) {
|
||||||
// send the reader off to the thread pool
|
// send the reader off to the thread pool
|
||||||
QThreadPool::globalInstance()->start(new ImageReader(_self, reply->readAll()));
|
QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) {
|
void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ NetworkProgram::NetworkProgram(ScriptCache* cache, const QUrl& url) :
|
||||||
|
|
||||||
void NetworkProgram::downloadFinished(QNetworkReply* reply) {
|
void NetworkProgram::downloadFinished(QNetworkReply* reply) {
|
||||||
_program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString());
|
_program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString());
|
||||||
|
reply->deleteLater();
|
||||||
finishedLoading(true);
|
finishedLoading(true);
|
||||||
emit loaded();
|
emit loaded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,6 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_reply->disconnect(this);
|
_reply->disconnect(this);
|
||||||
_reply->deleteLater();
|
|
||||||
QNetworkReply* reply = _reply;
|
QNetworkReply* reply = _reply;
|
||||||
_reply = NULL;
|
_reply = NULL;
|
||||||
ResourceCache::requestCompleted();
|
ResourceCache::requestCompleted();
|
||||||
|
|
|
@ -99,6 +99,7 @@ protected slots:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/// Called when the download has finished. The recipient should delete the reply when done with it.
|
||||||
virtual void downloadFinished(QNetworkReply* reply) = 0;
|
virtual void downloadFinished(QNetworkReply* reply) = 0;
|
||||||
|
|
||||||
/// Should be called by subclasses when all the loading that will be done has been done.
|
/// Should be called by subclasses when all the loading that will be done has been done.
|
||||||
|
|
Loading…
Reference in a new issue