implement mesh groups and pull out shader programs in renderMeshes() to outside the loop based on group

This commit is contained in:
ZappoMan 2014-10-15 17:08:47 -07:00
parent 952a604d77
commit 56b4d58f18
2 changed files with 245 additions and 72 deletions

View file

@ -47,7 +47,7 @@ Model::Model(QObject* parent) :
_blendNumber(0),
_appliedBlendNumber(0),
_calculatedMeshBoxesValid(false),
_translucentMeshesKnown(false) {
_meshesGroupsKnown(false) {
// we may have been created in the network thread, but we live in the main thread
moveToThread(Application::getInstance()->thread());
@ -273,7 +273,7 @@ void Model::reset() {
_jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f);
}
_translucentMeshesKnown = false;
_meshesGroupsKnown = false;
}
bool Model::updateGeometry() {
@ -323,6 +323,7 @@ bool Model::updateGeometry() {
deleteGeometry();
_dilatedTextures.clear();
_geometry = geometry;
_meshesGroupsKnown = false;
setJointStates(newJointStates);
needToRebuild = true;
} else if (_jointStates.isEmpty()) {
@ -425,8 +426,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
}
}
if (!_translucentMeshesKnown) {
calculateTranslucentMeshes();
if (!_meshesGroupsKnown) {
segregateMeshGroups();
}
glEnableClientState(GL_VERTEX_ARRAY);
@ -458,11 +459,30 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) {
mode == DEFAULT_RENDER_MODE);
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
int opaqueMeshPartsRendered = 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);
int translucentMeshPartsRendered = 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);
@ -472,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) {
translucentMeshPartsRendered += 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);
@ -1219,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();
}
@ -1250,37 +1279,210 @@ void Model::deleteGeometry() {
_blendedBlendshapeCoefficients.clear();
}
void Model::calculateTranslucentMeshes() {
_translucentMeshes.clear();
_opaqueMeshes.clear();
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();
if (translucentMesh) {
_translucentMeshes.append(i);
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 {
_opaqueMeshes.append(i);
qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???";
}
}
_translucentMeshesKnown = true;
_meshesGroupsKnown = true;
}
int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args) {
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???";
}
// if we're called in translucent mode, then use our translucent list vs opaque list
QList<int>& list = translucent ? _translucentMeshes : _opaqueMeshes;
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) {
@ -1316,52 +1518,11 @@ int 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) +
@ -1372,16 +1533,10 @@ int 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);
@ -1509,8 +1664,8 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold,
}
glPopMatrix();
activeProgram->release();
}
activeProgram->release();
return meshPartsRendered;
}

View file

@ -251,7 +251,7 @@ private:
void applyNextGeometry();
void deleteGeometry();
int 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();
@ -333,11 +333,29 @@ private:
QVector<AABox> _calculatedMeshBoxes;
bool _calculatedMeshBoxesValid;
void calculateTranslucentMeshes(); // used to calculate our list of translucent vs opaque meshes
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
bool _translucentMeshesKnown;
QList<int> _translucentMeshes; // indices of the meshes that are translucent
QList<int> _opaqueMeshes; // indices of the meshes that are opaque
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;
};