mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
Merge pull request #3601 from ZappoMan/frustumCullModelParts
Implement "segregation" of mesh groups
This commit is contained in:
commit
01b64d78e3
5 changed files with 383 additions and 111 deletions
|
@ -46,7 +46,8 @@ Model::Model(QObject* parent) :
|
|||
_url("http://invalid.com"),
|
||||
_blendNumber(0),
|
||||
_appliedBlendNumber(0),
|
||||
_calculatedMeshBoxesValid(false) {
|
||||
_calculatedMeshBoxesValid(false),
|
||||
_meshesGroupsKnown(false) {
|
||||
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
moveToThread(Application::getInstance()->thread());
|
||||
|
@ -271,6 +272,8 @@ void Model::reset() {
|
|||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
_jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f);
|
||||
}
|
||||
|
||||
_meshesGroupsKnown = false;
|
||||
}
|
||||
|
||||
bool Model::updateGeometry() {
|
||||
|
@ -320,6 +323,7 @@ bool Model::updateGeometry() {
|
|||
deleteGeometry();
|
||||
_dilatedTextures.clear();
|
||||
_geometry = geometry;
|
||||
_meshesGroupsKnown = false;
|
||||
setJointStates(newJointStates);
|
||||
needToRebuild = true;
|
||||
} else if (_jointStates.isEmpty()) {
|
||||
|
@ -421,6 +425,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
_dilatedTextures.append(dilated);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_meshesGroupsKnown) {
|
||||
segregateMeshGroups();
|
||||
}
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
@ -451,11 +459,30 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
mode == DEFAULT_RENDER_MODE);
|
||||
|
||||
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
|
||||
renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, args);
|
||||
|
||||
//renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args);
|
||||
int opaqueMeshPartsRendered = 0;
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
|
||||
opaqueMeshPartsRendered += renderMeshes(mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
|
||||
|
||||
// render translucent meshes afterwards
|
||||
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
|
||||
renderMeshes(mode, true, 0.75f, args);
|
||||
int translucentMeshPartsRendered = 0;
|
||||
const float MOSTLY_OPAQUE_THRESHOLD = 0.75f;
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -465,7 +492,15 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
|
||||
|
||||
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
|
||||
renderMeshes(mode, true, 0.0f, args);
|
||||
const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f;
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
|
||||
translucentMeshPartsRendered += renderMeshes(mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
|
||||
}
|
||||
|
||||
glDepthMask(true);
|
||||
|
@ -488,6 +523,11 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
|
|||
|
||||
// restore all the default material settings
|
||||
Application::getInstance()->setupWorldLight();
|
||||
|
||||
if (args) {
|
||||
args->_translucentMeshPartsRendered = translucentMeshPartsRendered;
|
||||
args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1207,6 +1247,7 @@ void Model::applyNextGeometry() {
|
|||
// we retain a reference to the base geometry so that its reference count doesn't fall to zero
|
||||
_baseGeometry = _nextBaseGeometry;
|
||||
_geometry = _nextGeometry;
|
||||
_meshesGroupsKnown = false;
|
||||
_nextBaseGeometry.reset();
|
||||
_nextGeometry.reset();
|
||||
}
|
||||
|
@ -1238,21 +1279,218 @@ void Model::deleteGeometry() {
|
|||
_blendedBlendshapeCoefficients.clear();
|
||||
}
|
||||
|
||||
void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) {
|
||||
void Model::segregateMeshGroups() {
|
||||
_meshesTranslucentTangents.clear();
|
||||
_meshesTranslucent.clear();
|
||||
_meshesTranslucentTangentsSpecular.clear();
|
||||
_meshesTranslucentSpecular.clear();
|
||||
|
||||
_meshesTranslucentTangentsSkinned.clear();
|
||||
_meshesTranslucentSkinned.clear();
|
||||
_meshesTranslucentTangentsSpecularSkinned.clear();
|
||||
_meshesTranslucentSpecularSkinned.clear();
|
||||
|
||||
_meshesOpaqueTangents.clear();
|
||||
_meshesOpaque.clear();
|
||||
_meshesOpaqueTangentsSpecular.clear();
|
||||
_meshesOpaqueSpecular.clear();
|
||||
|
||||
_meshesOpaqueTangentsSkinned.clear();
|
||||
_meshesOpaqueSkinned.clear();
|
||||
_meshesOpaqueTangentsSpecularSkinned.clear();
|
||||
_meshesOpaqueSpecularSkinned.clear();
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const MeshState& state = _meshStates.at(i);
|
||||
|
||||
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
||||
bool hasTangents = !mesh.tangents.isEmpty();
|
||||
bool hasSpecular = mesh.hasSpecularTexture();
|
||||
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||
|
||||
if (translucentMesh && !hasTangents && !hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesTranslucent.append(i);
|
||||
|
||||
} else if (translucentMesh && hasTangents && !hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesTranslucentTangents.append(i);
|
||||
|
||||
} else if (translucentMesh && hasTangents && hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesTranslucentTangentsSpecular.append(i);
|
||||
|
||||
} else if (translucentMesh && !hasTangents && hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesTranslucentSpecular.append(i);
|
||||
|
||||
} else if (translucentMesh && hasTangents && !hasSpecular && isSkinned) {
|
||||
|
||||
_meshesTranslucentTangentsSkinned.append(i);
|
||||
|
||||
} else if (translucentMesh && !hasTangents && !hasSpecular && isSkinned) {
|
||||
|
||||
_meshesTranslucentSkinned.append(i);
|
||||
|
||||
} else if (translucentMesh && hasTangents && hasSpecular && isSkinned) {
|
||||
|
||||
_meshesTranslucentTangentsSpecularSkinned.append(i);
|
||||
|
||||
} else if (translucentMesh && !hasTangents && hasSpecular && isSkinned) {
|
||||
|
||||
_meshesTranslucentSpecularSkinned.append(i);
|
||||
|
||||
} else if (!translucentMesh && !hasTangents && !hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesOpaque.append(i);
|
||||
|
||||
} else if (!translucentMesh && hasTangents && !hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesOpaqueTangents.append(i);
|
||||
|
||||
} else if (!translucentMesh && hasTangents && hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesOpaqueTangentsSpecular.append(i);
|
||||
|
||||
} else if (!translucentMesh && !hasTangents && hasSpecular && !isSkinned) {
|
||||
|
||||
_meshesOpaqueSpecular.append(i);
|
||||
|
||||
} else if (!translucentMesh && hasTangents && !hasSpecular && isSkinned) {
|
||||
|
||||
_meshesOpaqueTangentsSkinned.append(i);
|
||||
|
||||
} else if (!translucentMesh && !hasTangents && !hasSpecular && isSkinned) {
|
||||
|
||||
_meshesOpaqueSkinned.append(i);
|
||||
|
||||
} else if (!translucentMesh && hasTangents && hasSpecular && isSkinned) {
|
||||
|
||||
_meshesOpaqueTangentsSpecularSkinned.append(i);
|
||||
|
||||
} else if (!translucentMesh && !hasTangents && hasSpecular && isSkinned) {
|
||||
|
||||
_meshesOpaqueSpecularSkinned.append(i);
|
||||
} else {
|
||||
qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???";
|
||||
}
|
||||
}
|
||||
_meshesGroupsKnown = true;
|
||||
}
|
||||
|
||||
int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold,
|
||||
bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) {
|
||||
int meshPartsRendered = 0;
|
||||
updateVisibleJointStates();
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts);
|
||||
|
||||
// depending on which parameters we were called with, pick the correct mesh group to render
|
||||
QList<int>* whichList = NULL;
|
||||
if (translucent && !hasTangents && !hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesTranslucent;
|
||||
} else if (translucent && hasTangents && !hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesTranslucentTangents;
|
||||
} else if (translucent && hasTangents && hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesTranslucentTangentsSpecular;
|
||||
} else if (translucent && !hasTangents && hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesTranslucentSpecular;
|
||||
} else if (translucent && hasTangents && !hasSpecular && isSkinned) {
|
||||
whichList = &_meshesTranslucentTangentsSkinned;
|
||||
} else if (translucent && !hasTangents && !hasSpecular && isSkinned) {
|
||||
whichList = &_meshesTranslucentSkinned;
|
||||
} else if (translucent && hasTangents && hasSpecular && isSkinned) {
|
||||
whichList = &_meshesTranslucentTangentsSpecularSkinned;
|
||||
} else if (translucent && !hasTangents && hasSpecular && isSkinned) {
|
||||
whichList = &_meshesTranslucentSpecularSkinned;
|
||||
} else if (!translucent && !hasTangents && !hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesOpaque;
|
||||
} else if (!translucent && hasTangents && !hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesOpaqueTangents;
|
||||
} else if (!translucent && hasTangents && hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesOpaqueTangentsSpecular;
|
||||
} else if (!translucent && !hasTangents && hasSpecular && !isSkinned) {
|
||||
whichList = &_meshesOpaqueSpecular;
|
||||
} else if (!translucent && hasTangents && !hasSpecular && isSkinned) {
|
||||
whichList = &_meshesOpaqueTangentsSkinned;
|
||||
} else if (!translucent && !hasTangents && !hasSpecular && isSkinned) {
|
||||
whichList = &_meshesOpaqueSkinned;
|
||||
} else if (!translucent && hasTangents && hasSpecular && isSkinned) {
|
||||
whichList = &_meshesOpaqueTangentsSpecularSkinned;
|
||||
} else if (!translucent && !hasTangents && hasSpecular && isSkinned) {
|
||||
whichList = &_meshesOpaqueSpecularSkinned;
|
||||
} else {
|
||||
qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???";
|
||||
}
|
||||
|
||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||
if (!whichList) {
|
||||
qDebug() << "unexpected!!! we don't know which list of meshes to render...";
|
||||
return 0;
|
||||
}
|
||||
QList<int>& list = *whichList;
|
||||
|
||||
ProgramObject* program = &_program;
|
||||
Locations* locations = &_locations;
|
||||
ProgramObject* skinProgram = &_skinProgram;
|
||||
SkinLocations* skinLocations = &_skinLocations;
|
||||
GLenum specularTextureUnit = 0;
|
||||
if (mode == SHADOW_RENDER_MODE) {
|
||||
program = &_shadowProgram;
|
||||
skinProgram = &_skinShadowProgram;
|
||||
skinLocations = &_skinShadowLocations;
|
||||
} else if (translucent && alphaThreshold == 0.0f) {
|
||||
program = &_translucentProgram;
|
||||
locations = &_translucentLocations;
|
||||
skinProgram = &_skinTranslucentProgram;
|
||||
skinLocations = &_skinTranslucentLocations;
|
||||
|
||||
} else if (hasTangents) {
|
||||
if (hasSpecular) {
|
||||
program = &_normalSpecularMapProgram;
|
||||
locations = &_normalSpecularMapLocations;
|
||||
skinProgram = &_skinNormalSpecularMapProgram;
|
||||
skinLocations = &_skinNormalSpecularMapLocations;
|
||||
specularTextureUnit = GL_TEXTURE2;
|
||||
} else {
|
||||
program = &_normalMapProgram;
|
||||
locations = &_normalMapLocations;
|
||||
skinProgram = &_skinNormalMapProgram;
|
||||
skinLocations = &_skinNormalMapLocations;
|
||||
}
|
||||
} else if (hasSpecular) {
|
||||
program = &_specularMapProgram;
|
||||
locations = &_specularMapLocations;
|
||||
skinProgram = &_skinSpecularMapProgram;
|
||||
skinLocations = &_skinSpecularMapLocations;
|
||||
specularTextureUnit = GL_TEXTURE1;
|
||||
}
|
||||
|
||||
ProgramObject* activeProgram = program;
|
||||
Locations* activeLocations = locations;
|
||||
|
||||
if (isSkinned) {
|
||||
skinProgram->bind();
|
||||
activeProgram = skinProgram;
|
||||
activeLocations = skinLocations;
|
||||
} else {
|
||||
program->bind();
|
||||
}
|
||||
activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
|
||||
|
||||
// i is the "index" from the original networkMeshes QVector...
|
||||
foreach (int i, list) {
|
||||
|
||||
// exit early if the translucency doesn't match what we're drawing
|
||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
if (translucent ? (networkMesh.getTranslucentPartCount(mesh) == 0) :
|
||||
(networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bind();
|
||||
|
||||
int vertexCount = mesh.vertices.size();
|
||||
|
@ -1280,52 +1518,11 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
|
|||
|
||||
const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind();
|
||||
|
||||
ProgramObject* program = &_program;
|
||||
Locations* locations = &_locations;
|
||||
ProgramObject* skinProgram = &_skinProgram;
|
||||
SkinLocations* skinLocations = &_skinLocations;
|
||||
GLenum specularTextureUnit = 0;
|
||||
if (mode == SHADOW_RENDER_MODE) {
|
||||
program = &_shadowProgram;
|
||||
skinProgram = &_skinShadowProgram;
|
||||
skinLocations = &_skinShadowLocations;
|
||||
|
||||
} else if (translucent && alphaThreshold == 0.0f) {
|
||||
program = &_translucentProgram;
|
||||
locations = &_translucentLocations;
|
||||
skinProgram = &_skinTranslucentProgram;
|
||||
skinLocations = &_skinTranslucentLocations;
|
||||
|
||||
} else if (!mesh.tangents.isEmpty()) {
|
||||
if (mesh.hasSpecularTexture()) {
|
||||
program = &_normalSpecularMapProgram;
|
||||
locations = &_normalSpecularMapLocations;
|
||||
skinProgram = &_skinNormalSpecularMapProgram;
|
||||
skinLocations = &_skinNormalSpecularMapLocations;
|
||||
specularTextureUnit = GL_TEXTURE2;
|
||||
|
||||
} else {
|
||||
program = &_normalMapProgram;
|
||||
locations = &_normalMapLocations;
|
||||
skinProgram = &_skinNormalMapProgram;
|
||||
skinLocations = &_skinNormalMapLocations;
|
||||
}
|
||||
} else if (mesh.hasSpecularTexture()) {
|
||||
program = &_specularMapProgram;
|
||||
locations = &_specularMapLocations;
|
||||
skinProgram = &_skinSpecularMapProgram;
|
||||
skinLocations = &_skinSpecularMapLocations;
|
||||
specularTextureUnit = GL_TEXTURE1;
|
||||
}
|
||||
|
||||
const MeshState& state = _meshStates.at(i);
|
||||
ProgramObject* activeProgram = program;
|
||||
Locations* activeLocations = locations;
|
||||
glPushMatrix();
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
|
||||
|
||||
const MeshState& state = _meshStates.at(i);
|
||||
if (state.clusterMatrices.size() > 1) {
|
||||
skinProgram->bind();
|
||||
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||
(const float*)state.clusterMatrices.constData());
|
||||
int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) +
|
||||
|
@ -1336,16 +1533,10 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
|
|||
offset + vertexCount * sizeof(glm::vec4), 4);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterIndices);
|
||||
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
|
||||
activeProgram = skinProgram;
|
||||
activeLocations = skinLocations;
|
||||
|
||||
} else {
|
||||
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
||||
program->bind();
|
||||
}
|
||||
|
||||
activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
|
||||
activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3);
|
||||
|
@ -1424,11 +1615,19 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
}
|
||||
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
|
||||
GL_UNSIGNED_INT, (void*)offset);
|
||||
offset += part.triangleIndices.size() * sizeof(int);
|
||||
|
||||
meshPartsRendered++;
|
||||
|
||||
if (part.quadIndices.size() > 0) {
|
||||
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
|
||||
offset += part.quadIndices.size() * sizeof(int);
|
||||
}
|
||||
|
||||
if (part.triangleIndices.size() > 0) {
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, part.triangleIndices.size(),
|
||||
GL_UNSIGNED_INT, (void*)offset);
|
||||
offset += part.triangleIndices.size() * sizeof(int);
|
||||
}
|
||||
|
||||
if (args) {
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
|
@ -1465,8 +1664,10 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold
|
|||
}
|
||||
glPopMatrix();
|
||||
|
||||
activeProgram->release();
|
||||
}
|
||||
activeProgram->release();
|
||||
|
||||
return meshPartsRendered;
|
||||
}
|
||||
|
||||
void AnimationHandle::setURL(const QUrl& url) {
|
||||
|
|
|
@ -251,7 +251,7 @@ private:
|
|||
|
||||
void applyNextGeometry();
|
||||
void deleteGeometry();
|
||||
void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f, RenderArgs* args = NULL);
|
||||
int renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL);
|
||||
QVector<JointState> createJointStates(const FBXGeometry& geometry);
|
||||
void initJointTransforms();
|
||||
|
||||
|
@ -332,6 +332,31 @@ private:
|
|||
|
||||
QVector<AABox> _calculatedMeshBoxes;
|
||||
bool _calculatedMeshBoxesValid;
|
||||
|
||||
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
||||
|
||||
bool _meshesGroupsKnown;
|
||||
|
||||
QList<int> _meshesTranslucent;
|
||||
QList<int> _meshesTranslucentTangents;
|
||||
QList<int> _meshesTranslucentTangentsSpecular;
|
||||
QList<int> _meshesTranslucentSpecular;
|
||||
|
||||
QList<int> _meshesTranslucentSkinned;
|
||||
QList<int> _meshesTranslucentTangentsSkinned;
|
||||
QList<int> _meshesTranslucentTangentsSpecularSkinned;
|
||||
QList<int> _meshesTranslucentSpecularSkinned;
|
||||
|
||||
QList<int> _meshesOpaque;
|
||||
QList<int> _meshesOpaqueTangents;
|
||||
QList<int> _meshesOpaqueTangentsSpecular;
|
||||
QList<int> _meshesOpaqueSpecular;
|
||||
|
||||
QList<int> _meshesOpaqueSkinned;
|
||||
QList<int> _meshesOpaqueTangentsSkinned;
|
||||
QList<int> _meshesOpaqueTangentsSpecularSkinned;
|
||||
QList<int> _meshesOpaqueSpecularSkinned;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QPointer<Model>)
|
||||
|
|
|
@ -221,8 +221,30 @@ void Stats::display(
|
|||
int totalServers = NodeList::getInstance()->size();
|
||||
|
||||
lines = _expanded ? 5 : 3;
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
int columnOneWidth = _generalStatsWidth;
|
||||
|
||||
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
|
||||
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // make it 3 columns wide...
|
||||
// we will also include room for 1 line per timing record and a header of 4 lines
|
||||
lines += 4;
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
horizontalOffset += 5;
|
||||
|
||||
int columnOneHorizontalOffset = horizontalOffset;
|
||||
|
||||
char serverNodes[30];
|
||||
sprintf(serverNodes, "Servers: %d", totalServers);
|
||||
|
@ -249,6 +271,46 @@ void Stats::display(
|
|||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond, color);
|
||||
}
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
// Timing details...
|
||||
const int TIMER_OUTPUT_LINE_LENGTH = 1000;
|
||||
char perfLine[TIMER_OUTPUT_LINE_LENGTH];
|
||||
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 4 lines to be under the other columns
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"-------------------------------------------------------- Function "
|
||||
"------------------------------------------------------- --msecs- -calls--", color);
|
||||
|
||||
// First iterate all the records, and for the ones that should be included, insert them into
|
||||
// a new Map sorted by average time...
|
||||
QMap<float, QString> sortedRecords;
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
sortedRecords.insertMulti(averageTime, i.key());
|
||||
}
|
||||
}
|
||||
|
||||
QMapIterator<float, QString> j(sortedRecords);
|
||||
j.toBack();
|
||||
while (j.hasPrevious()) {
|
||||
j.previous();
|
||||
QString functionName = j.value();
|
||||
const PerformanceTimerRecord& record = allRecords.value(functionName);
|
||||
|
||||
sprintf(perfLine, "%120s: %8.4f [%6llu]", qPrintable(functionName),
|
||||
(float)record.getMovingAverage() / (float)USECS_PER_MSEC,
|
||||
record.getCount());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine, color);
|
||||
}
|
||||
}
|
||||
|
||||
verticalOffset = 0;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth +1;
|
||||
|
@ -283,7 +345,11 @@ void Stats::display(
|
|||
}
|
||||
|
||||
lines = _expanded ? 4 : 3;
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
|
||||
// only draw our background if column one didn't draw a wide background
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
||||
|
@ -319,7 +385,9 @@ void Stats::display(
|
|||
|
||||
lines = _expanded ? 8 : 3;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, lines * STATS_PELS_PER_LINE + 10);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
char avatarPosition[200];
|
||||
|
@ -393,23 +461,9 @@ void Stats::display(
|
|||
|
||||
lines = _expanded ? 14 : 3;
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
|
||||
lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info
|
||||
lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info
|
||||
}
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
// we will also include room for 1 line per timing record and a header
|
||||
lines += 1;
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset,
|
||||
lines * STATS_PELS_PER_LINE + 10);
|
||||
horizontalOffset += 5;
|
||||
|
@ -432,6 +486,12 @@ void Stats::display(
|
|||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats << "Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered()
|
||||
<< " Translucent:" << entities->getTranslucentMeshPartsRendered();
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
|
||||
|
||||
// Local Voxel Memory Usage
|
||||
voxelStats.str("");
|
||||
|
@ -585,32 +645,6 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
PerformanceTimer::tallyAllTimerRecords();
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
// Timing details...
|
||||
const int TIMER_OUTPUT_LINE_LENGTH = 300;
|
||||
char perfLine[TIMER_OUTPUT_LINE_LENGTH];
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"--------------------- Function -------------------- --msecs- -calls--", color);
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()),
|
||||
(float)i.value().getMovingAverage() / (float)USECS_PER_MSEC,
|
||||
i.value().getCount());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
|
||||
verticalOffset += STATS_PELS_PER_LINE; // space one line...
|
||||
|
||||
|
|
|
@ -179,6 +179,9 @@ void OctreeRenderer::render(RenderMode renderMode) {
|
|||
_trianglesRendered = args._trianglesRendered;
|
||||
_quadsRendered = args._quadsRendered;
|
||||
|
||||
_translucentMeshPartsRendered = args._translucentMeshPartsRendered;
|
||||
_opaqueMeshPartsRendered = args._opaqueMeshPartsRendered;
|
||||
|
||||
}
|
||||
|
||||
void OctreeRenderer::clear() {
|
||||
|
|
|
@ -74,7 +74,10 @@ public:
|
|||
|
||||
int getTrianglesRendered() const { return _trianglesRendered; }
|
||||
int getQuadsRendered() const { return _quadsRendered; }
|
||||
|
||||
|
||||
int getTranslucentMeshPartsRendered() const { return _translucentMeshPartsRendered; }
|
||||
int getOpaqueMeshPartsRendered() const { return _opaqueMeshPartsRendered; }
|
||||
|
||||
protected:
|
||||
Octree* _tree;
|
||||
bool _managedTree;
|
||||
|
@ -90,6 +93,9 @@ protected:
|
|||
|
||||
int _trianglesRendered;
|
||||
int _quadsRendered;
|
||||
|
||||
int _translucentMeshPartsRendered;
|
||||
int _opaqueMeshPartsRendered;
|
||||
};
|
||||
|
||||
class RenderArgs {
|
||||
|
@ -110,6 +116,9 @@ public:
|
|||
|
||||
int _trianglesRendered;
|
||||
int _quadsRendered;
|
||||
|
||||
int _translucentMeshPartsRendered;
|
||||
int _opaqueMeshPartsRendered;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue