mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 09:17:29 +02:00
Merge pull request #3443 from ey6es/master
Allow blenders to stack up to a point in order to reduce latency with fewer avatars (but still cap work with lots of avatars).
This commit is contained in:
commit
cfc8cf0d7b
4 changed files with 91 additions and 59 deletions
|
@ -20,6 +20,10 @@
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
|
||||||
|
GeometryCache::GeometryCache() :
|
||||||
|
_pendingBlenders(0) {
|
||||||
|
}
|
||||||
|
|
||||||
GeometryCache::~GeometryCache() {
|
GeometryCache::~GeometryCache() {
|
||||||
foreach (const VerticesIndices& vbo, _hemisphereVBOs) {
|
foreach (const VerticesIndices& vbo, _hemisphereVBOs) {
|
||||||
glDeleteBuffers(1, &vbo.first);
|
glDeleteBuffers(1, &vbo.first);
|
||||||
|
@ -296,10 +300,30 @@ QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, cons
|
||||||
return getResource(url, fallback, delayLoad).staticCast<NetworkGeometry>();
|
return getResource(url, fallback, delayLoad).staticCast<NetworkGeometry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::setBlendedVertices(const QPointer<Model>& model, const QWeakPointer<NetworkGeometry>& geometry,
|
void GeometryCache::noteRequiresBlend(Model* model) {
|
||||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
if (_pendingBlenders < QThread::idealThreadCount()) {
|
||||||
|
if (model->maybeStartBlender()) {
|
||||||
|
_pendingBlenders++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_modelsRequiringBlends.contains(model)) {
|
||||||
|
_modelsRequiringBlends.append(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeometryCache::setBlendedVertices(const QPointer<Model>& model, int blendNumber,
|
||||||
|
const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||||
if (!model.isNull()) {
|
if (!model.isNull()) {
|
||||||
model->setBlendedVertices(geometry, vertices, normals);
|
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
||||||
|
}
|
||||||
|
_pendingBlenders--;
|
||||||
|
while (!_modelsRequiringBlends.isEmpty()) {
|
||||||
|
Model* nextModel = _modelsRequiringBlends.takeFirst();
|
||||||
|
if (nextModel && nextModel->maybeStartBlender()) {
|
||||||
|
_pendingBlenders++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ class GeometryCache : public ResourceCache {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
GeometryCache();
|
||||||
virtual ~GeometryCache();
|
virtual ~GeometryCache();
|
||||||
|
|
||||||
void renderHemisphere(int slices, int stacks);
|
void renderHemisphere(int slices, int stacks);
|
||||||
|
@ -47,9 +48,12 @@ public:
|
||||||
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
||||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
||||||
|
|
||||||
|
/// Adds the specified model to the list requiring vertex blends.
|
||||||
|
void noteRequiresBlend(Model* model);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void setBlendedVertices(const QPointer<Model>& model, const QWeakPointer<NetworkGeometry>& geometry,
|
void setBlendedVertices(const QPointer<Model>& model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -68,6 +72,9 @@ private:
|
||||||
QHash<IntPair, QOpenGLBuffer> _gridBuffers;
|
QHash<IntPair, QOpenGLBuffer> _gridBuffers;
|
||||||
|
|
||||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||||
|
|
||||||
|
QList<QPointer<Model> > _modelsRequiringBlends;
|
||||||
|
int _pendingBlenders;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Geometry loaded from the network.
|
/// Geometry loaded from the network.
|
||||||
|
|
|
@ -62,8 +62,8 @@ Model::Model(QObject* parent) :
|
||||||
_lodDistance(0.0f),
|
_lodDistance(0.0f),
|
||||||
_pupilDilation(0.0f),
|
_pupilDilation(0.0f),
|
||||||
_url("http://invalid.com"),
|
_url("http://invalid.com"),
|
||||||
_blenderPending(false),
|
_blendNumber(0),
|
||||||
_blendRequired(false) {
|
_appliedBlendNumber(0) {
|
||||||
|
|
||||||
// we may have been created in the network thread, but we live in the main thread
|
// we may have been created in the network thread, but we live in the main thread
|
||||||
moveToThread(Application::getInstance()->thread());
|
moveToThread(Application::getInstance()->thread());
|
||||||
|
@ -826,7 +826,7 @@ void Model::updateShapePositions() {
|
||||||
class Blender : public QRunnable {
|
class Blender : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Blender(Model* model, const QWeakPointer<NetworkGeometry>& geometry,
|
Blender(Model* model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
@ -834,55 +834,55 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QPointer<Model> _model;
|
QPointer<Model> _model;
|
||||||
|
int _blendNumber;
|
||||||
QWeakPointer<NetworkGeometry> _geometry;
|
QWeakPointer<NetworkGeometry> _geometry;
|
||||||
QVector<FBXMesh> _meshes;
|
QVector<FBXMesh> _meshes;
|
||||||
QVector<float> _blendshapeCoefficients;
|
QVector<float> _blendshapeCoefficients;
|
||||||
};
|
};
|
||||||
|
|
||||||
Blender::Blender(Model* model, const QWeakPointer<NetworkGeometry>& geometry,
|
Blender::Blender(Model* model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
||||||
_model(model),
|
_model(model),
|
||||||
|
_blendNumber(blendNumber),
|
||||||
_geometry(geometry),
|
_geometry(geometry),
|
||||||
_meshes(meshes),
|
_meshes(meshes),
|
||||||
_blendshapeCoefficients(blendshapeCoefficients) {
|
_blendshapeCoefficients(blendshapeCoefficients) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blender::run() {
|
void Blender::run() {
|
||||||
// make sure the model still exists
|
|
||||||
if (_model.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QVector<glm::vec3> vertices, normals;
|
QVector<glm::vec3> vertices, normals;
|
||||||
int offset = 0;
|
if (!_model.isNull()) {
|
||||||
foreach (const FBXMesh& mesh, _meshes) {
|
int offset = 0;
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
foreach (const FBXMesh& mesh, _meshes) {
|
||||||
continue;
|
if (mesh.blendshapes.isEmpty()) {
|
||||||
}
|
|
||||||
vertices += mesh.vertices;
|
|
||||||
normals += mesh.normals;
|
|
||||||
glm::vec3* meshVertices = vertices.data() + offset;
|
|
||||||
glm::vec3* meshNormals = normals.data() + offset;
|
|
||||||
offset += mesh.vertices.size();
|
|
||||||
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
|
||||||
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
|
|
||||||
float vertexCoefficient = _blendshapeCoefficients.at(i);
|
|
||||||
if (vertexCoefficient < EPSILON) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
|
vertices += mesh.vertices;
|
||||||
const FBXBlendshape& blendshape = mesh.blendshapes.at(i);
|
normals += mesh.normals;
|
||||||
for (int j = 0; j < blendshape.indices.size(); j++) {
|
glm::vec3* meshVertices = vertices.data() + offset;
|
||||||
int index = blendshape.indices.at(j);
|
glm::vec3* meshNormals = normals.data() + offset;
|
||||||
meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;
|
offset += mesh.vertices.size();
|
||||||
meshNormals[index] += blendshape.normals.at(j) * normalCoefficient;
|
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
||||||
|
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
|
||||||
|
float vertexCoefficient = _blendshapeCoefficients.at(i);
|
||||||
|
if (vertexCoefficient < EPSILON) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
|
||||||
|
const FBXBlendshape& blendshape = mesh.blendshapes.at(i);
|
||||||
|
for (int j = 0; j < blendshape.indices.size(); j++) {
|
||||||
|
int index = blendshape.indices.at(j);
|
||||||
|
meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;
|
||||||
|
meshNormals[index] += blendshape.normals.at(j) * normalCoefficient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// post the result to the geometry cache, which will dispatch to the model if still alive
|
// post the result to the geometry cache, which will dispatch to the model if still alive
|
||||||
QMetaObject::invokeMethod(Application::getInstance()->getGeometryCache(), "setBlendedVertices",
|
QMetaObject::invokeMethod(Application::getInstance()->getGeometryCache(), "setBlendedVertices",
|
||||||
Q_ARG(const QPointer<Model>&, _model), Q_ARG(const QWeakPointer<NetworkGeometry>&, _geometry),
|
Q_ARG(const QPointer<Model>&, _model), Q_ARG(int, _blendNumber),
|
||||||
Q_ARG(const QVector<glm::vec3>&, vertices), Q_ARG(const QVector<glm::vec3>&, normals));
|
Q_ARG(const QWeakPointer<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
||||||
|
Q_ARG(const QVector<glm::vec3>&, normals));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) {
|
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) {
|
||||||
|
@ -1020,14 +1020,9 @@ void Model::simulateInternal(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// post the blender if we're not currently waiting for one to finish
|
// post the blender if we're not currently waiting for one to finish
|
||||||
if (geometry.hasBlendedMeshes()) {
|
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||||
if (_blenderPending) {
|
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||||
_blendRequired = true;
|
Application::getInstance()->getGeometryCache()->noteRequiresBlend(this);
|
||||||
} else {
|
|
||||||
_blendRequired = false;
|
|
||||||
_blenderPending = true;
|
|
||||||
QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1290,22 +1285,23 @@ void Model::renderJointCollisionShapes(float alpha) {
|
||||||
// implement this when we have shapes for regular models
|
// implement this when we have shapes for regular models
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setBlendedVertices(const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices,
|
bool Model::maybeStartBlender() {
|
||||||
const QVector<glm::vec3>& normals) {
|
|
||||||
_blenderPending = false;
|
|
||||||
|
|
||||||
// start the next blender if required
|
|
||||||
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
||||||
if (_blendRequired) {
|
if (fbxGeometry.hasBlendedMeshes()) {
|
||||||
_blendRequired = false;
|
QThreadPool::globalInstance()->start(new Blender(this, ++_blendNumber, _geometry,
|
||||||
if (fbxGeometry.hasBlendedMeshes()) {
|
fbxGeometry.meshes, _blendshapeCoefficients));
|
||||||
_blenderPending = true;
|
return true;
|
||||||
QThreadPool::globalInstance()->start(new Blender(this, _geometry, fbxGeometry.meshes, _blendshapeCoefficients));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (_geometry != geometry || _blendedVertexBuffers.isEmpty()) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
|
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||||
|
if (_geometry != geometry || _blendedVertexBuffers.isEmpty() || blendNumber < _appliedBlendNumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_appliedBlendNumber = blendNumber;
|
||||||
|
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
|
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
|
||||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||||
|
@ -1358,6 +1354,8 @@ void Model::deleteGeometry() {
|
||||||
if (_geometry) {
|
if (_geometry) {
|
||||||
_geometry->clearLoadPriority(this);
|
_geometry->clearLoadPriority(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_blendedBlendshapeCoefficients.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows) {
|
void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows) {
|
||||||
|
|
|
@ -165,9 +165,11 @@ public:
|
||||||
|
|
||||||
virtual void renderJointCollisionShapes(float alpha);
|
virtual void renderJointCollisionShapes(float alpha);
|
||||||
|
|
||||||
|
bool maybeStartBlender();
|
||||||
|
|
||||||
/// Sets blended vertices computed in a separate thread.
|
/// Sets blended vertices computed in a separate thread.
|
||||||
void setBlendedVertices(const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices,
|
void setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<glm::vec3>& normals);
|
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
class LocalLight {
|
class LocalLight {
|
||||||
public:
|
public:
|
||||||
|
@ -285,8 +287,9 @@ private:
|
||||||
glm::vec4 _localLightColors[MAX_LOCAL_LIGHTS];
|
glm::vec4 _localLightColors[MAX_LOCAL_LIGHTS];
|
||||||
glm::vec4 _localLightDirections[MAX_LOCAL_LIGHTS];
|
glm::vec4 _localLightDirections[MAX_LOCAL_LIGHTS];
|
||||||
|
|
||||||
bool _blenderPending;
|
QVector<float> _blendedBlendshapeCoefficients;
|
||||||
bool _blendRequired;
|
int _blendNumber;
|
||||||
|
int _appliedBlendNumber;
|
||||||
|
|
||||||
static ProgramObject _program;
|
static ProgramObject _program;
|
||||||
static ProgramObject _normalMapProgram;
|
static ProgramObject _normalMapProgram;
|
||||||
|
|
Loading…
Reference in a new issue