From 4deb9936ba7d89895886ca9ab0493f3a846a6d46 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 27 Jan 2014 17:44:13 -0800 Subject: [PATCH 1/3] Don't add the specular alpha in the model fragment shaders. --- interface/resources/shaders/model.frag | 2 +- interface/resources/shaders/model_normal_map.frag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/model.frag b/interface/resources/shaders/model.frag index 877cdca885..e035f9bfe9 100644 --- a/interface/resources/shaders/model.frag +++ b/interface/resources/shaders/model.frag @@ -25,5 +25,5 @@ void main(void) { // modulate texture by base color and add specular contribution gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + - pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular; + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); } diff --git a/interface/resources/shaders/model_normal_map.frag b/interface/resources/shaders/model_normal_map.frag index 9740a4d4b1..9a0e964500 100644 --- a/interface/resources/shaders/model_normal_map.frag +++ b/interface/resources/shaders/model_normal_map.frag @@ -37,5 +37,5 @@ void main(void) { // modulate texture by base color and add specular contribution gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + - pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular; + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); } From 3edb81baf451f1f15ba5ef241d995c2cb1944cb3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 28 Jan 2014 12:01:32 -0800 Subject: [PATCH 2/3] Check for texture translucency, render translucent mesh parts after opaque ones, without alpha testing, and with back face culling enabled. --- interface/src/renderer/GeometryCache.cpp | 14 + interface/src/renderer/GeometryCache.h | 4 + interface/src/renderer/Model.cpp | 378 ++++++++++++----------- interface/src/renderer/Model.h | 1 + interface/src/renderer/TextureCache.cpp | 19 +- interface/src/renderer/TextureCache.h | 5 + 6 files changed, 239 insertions(+), 182 deletions(-) diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 73248b413f..63a0c51f0b 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -508,3 +508,17 @@ void NetworkGeometry::maybeReadModelWithMapping() { _meshes.append(networkMesh); } } + +bool NetworkMeshPart::isTranslucent() const { + return diffuseTexture && diffuseTexture->isTranslucent(); +} + +int NetworkMesh::getTranslucentPartCount() const { + int count = 0; + foreach (const NetworkMeshPart& part, parts) { + if (part.isTranslucent()) { + count++; + } + } + return count; +} diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 312d8bcd91..e65aed31d4 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -93,6 +93,8 @@ public: QSharedPointer diffuseTexture; QSharedPointer normalTexture; + + bool isTranslucent() const; }; /// The state associated with a single mesh. @@ -103,6 +105,8 @@ public: GLuint vertexBufferID; QVector parts; + + int getTranslucentPartCount() const; }; #endif /* defined(__interface__GeometryCache__) */ diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c6c820a0f9..c25e513b3b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -240,7 +240,6 @@ bool Model::render(float alpha) { // set up blended buffer ids on first render after load/simulate const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const QVector& networkMeshes = _geometry->getMeshes(); if (_blendedVertexBufferIDs.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { GLuint id = 0; @@ -264,191 +263,28 @@ bool Model::render(float alpha) { glDisable(GL_COLOR_MATERIAL); + // render opaque meshes with alpha testing + glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f); - for (int i = 0; i < networkMeshes.size(); i++) { - const NetworkMesh& networkMesh = networkMeshes.at(i); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID); - - const FBXMesh& mesh = geometry.meshes.at(i); - int vertexCount = mesh.vertices.size(); - - glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); - - ProgramObject* program = &_program; - ProgramObject* skinProgram = &_skinProgram; - SkinLocations* skinLocations = &_skinLocations; - if (!mesh.tangents.isEmpty()) { - program = &_normalMapProgram; - skinProgram = &_skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; - } - - const MeshState& state = _meshStates.at(i); - ProgramObject* activeProgram = program; - int tangentLocation = _normalMapTangentLocation; - if (state.worldSpaceVertices.isEmpty()) { - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - - 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) + - mesh.texCoords.size() * sizeof(glm::vec2) + - (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); - skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); - skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, - offset + vertexCount * sizeof(glm::vec4), 4); - skinProgram->enableAttributeArray(skinLocations->clusterIndices); - skinProgram->enableAttributeArray(skinLocations->clusterWeights); - activeProgram = skinProgram; - tangentLocation = skinLocations->tangent; - - } else { - glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); - program->bind(); - } - } else { - program->bind(); - } - - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { - if (!mesh.tangents.isEmpty()) { - activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); - activeProgram->enableAttributeArray(tangentLocation); - } - glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + - mesh.tangents.size() * sizeof(glm::vec3))); - glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + - (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); - - } else { - if (!mesh.tangents.isEmpty()) { - activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3); - activeProgram->enableAttributeArray(tangentLocation); - } - glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); - glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); - glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - - if (!state.worldSpaceVertices.isEmpty()) { - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData()); - - } else { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - _blendedNormals.resize(_blendedVertices.size()); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } - } - - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); - } - } - glVertexPointer(3, GL_FLOAT, 0, 0); - glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); - - if (!mesh.colors.isEmpty()) { - glEnableClientState(GL_COLOR_ARRAY); - } else { - glColor3f(1.0f, 1.0f, 1.0f); - } - if (!mesh.texCoords.isEmpty()) { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - qint64 offset = 0; - for (int j = 0; j < networkMesh.parts.size(); j++) { - const NetworkMeshPart& networkPart = networkMesh.parts.at(j); - const FBXMeshPart& part = mesh.parts.at(j); - - // apply material properties - glm::vec4 diffuse = glm::vec4(part.diffuseColor, alpha); - glm::vec4 specular = glm::vec4(part.specularColor, alpha); - glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); - glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); - glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); - - Texture* diffuseMap = networkPart.diffuseTexture.data(); - if (mesh.isEye) { - if (diffuseMap != NULL) { - diffuseMap = (_dilatedTextures[i][j] = - static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); - } - } - glBindTexture(GL_TEXTURE_2D, diffuseMap == NULL ? - Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); - - if (!mesh.tangents.isEmpty()) { - glActiveTexture(GL_TEXTURE1); - Texture* normalMap = networkPart.normalTexture.data(); - glBindTexture(GL_TEXTURE_2D, normalMap == NULL ? - Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); - 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); - } - - if (!mesh.colors.isEmpty()) { - glDisableClientState(GL_COLOR_ARRAY); - } - if (!mesh.texCoords.isEmpty()) { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (!mesh.tangents.isEmpty()) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - - activeProgram->disableAttributeArray(tangentLocation); - } - - if (state.worldSpaceVertices.isEmpty()) { - if (state.clusterMatrices.size() > 1) { - skinProgram->disableAttributeArray(skinLocations->clusterIndices); - skinProgram->disableAttributeArray(skinLocations->clusterWeights); - } - glPopMatrix(); - } - activeProgram->release(); - } + renderMeshes(alpha, false); + + glDisable(GL_ALPHA_TEST); + + // render translucent meshes afterwards, with back face culling and no depth writes + + glEnable(GL_CULL_FACE); + + renderMeshes(alpha, true); + + glDisable(GL_CULL_FACE); // deactivate vertex arrays after drawing glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisable(GL_ALPHA_TEST); - // bind with 0 to switch back to normal operation glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -882,3 +718,191 @@ void Model::deleteGeometry() { _jointStates.clear(); _meshStates.clear(); } + +void Model::renderMeshes(float alpha, bool translucent) { + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& networkMeshes = _geometry->getMeshes(); + + for (int i = 0; i < networkMeshes.size(); i++) { + // exit early if the translucency doesn't match what we're drawing + const NetworkMesh& networkMesh = networkMeshes.at(i); + if (translucent ? (networkMesh.getTranslucentPartCount() == 0) : + (networkMesh.getTranslucentPartCount() == networkMesh.parts.size())) { + continue; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID); + + const FBXMesh& mesh = geometry.meshes.at(i); + int vertexCount = mesh.vertices.size(); + + glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); + + ProgramObject* program = &_program; + ProgramObject* skinProgram = &_skinProgram; + SkinLocations* skinLocations = &_skinLocations; + if (!mesh.tangents.isEmpty()) { + program = &_normalMapProgram; + skinProgram = &_skinNormalMapProgram; + skinLocations = &_skinNormalMapLocations; + } + + const MeshState& state = _meshStates.at(i); + ProgramObject* activeProgram = program; + int tangentLocation = _normalMapTangentLocation; + if (state.worldSpaceVertices.isEmpty()) { + glPushMatrix(); + Application::getInstance()->loadTranslatedViewMatrix(_translation); + + 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) + + mesh.texCoords.size() * sizeof(glm::vec2) + + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); + skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); + skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, + offset + vertexCount * sizeof(glm::vec4), 4); + skinProgram->enableAttributeArray(skinLocations->clusterIndices); + skinProgram->enableAttributeArray(skinLocations->clusterWeights); + activeProgram = skinProgram; + tangentLocation = skinLocations->tangent; + + } else { + glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); + program->bind(); + } + } else { + program->bind(); + } + + if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + if (!mesh.tangents.isEmpty()) { + activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); + activeProgram->enableAttributeArray(tangentLocation); + } + glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + + mesh.tangents.size() * sizeof(glm::vec3))); + glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + + (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); + + } else { + if (!mesh.tangents.isEmpty()) { + activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, 0, 3); + activeProgram->enableAttributeArray(tangentLocation); + } + glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); + glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); + glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); + + if (!state.worldSpaceVertices.isEmpty()) { + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData()); + + } else { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + _blendedNormals.resize(_blendedVertices.size()); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { + float coefficient = _blendshapeCoefficients[j]; + if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { + _blendedVertices[*index] += *vertex * coefficient; + _blendedNormals[*index] += *normal * normalCoefficient; + } + } + + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); + } + } + glVertexPointer(3, GL_FLOAT, 0, 0); + glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); + + if (!mesh.colors.isEmpty()) { + glEnableClientState(GL_COLOR_ARRAY); + } else { + glColor3f(1.0f, 1.0f, 1.0f); + } + if (!mesh.texCoords.isEmpty()) { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + qint64 offset = 0; + for (int j = 0; j < networkMesh.parts.size(); j++) { + const NetworkMeshPart& networkPart = networkMesh.parts.at(j); + if (networkPart.isTranslucent() != translucent) { + continue; + } + const FBXMeshPart& part = mesh.parts.at(j); + + // apply material properties + glm::vec4 diffuse = glm::vec4(part.diffuseColor, alpha); + glm::vec4 specular = glm::vec4(part.specularColor, alpha); + glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); + glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); + glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); + + Texture* diffuseMap = networkPart.diffuseTexture.data(); + if (mesh.isEye) { + if (diffuseMap != NULL) { + diffuseMap = (_dilatedTextures[i][j] = + static_cast(diffuseMap)->getDilatedTexture(_pupilDilation)).data(); + } + } + glBindTexture(GL_TEXTURE_2D, diffuseMap == NULL ? + Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); + + if (!mesh.tangents.isEmpty()) { + glActiveTexture(GL_TEXTURE1); + Texture* normalMap = networkPart.normalTexture.data(); + glBindTexture(GL_TEXTURE_2D, normalMap == NULL ? + Application::getInstance()->getTextureCache()->getBlueTextureID() : normalMap->getID()); + 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); + } + + if (!mesh.colors.isEmpty()) { + glDisableClientState(GL_COLOR_ARRAY); + } + if (!mesh.texCoords.isEmpty()) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (!mesh.tangents.isEmpty()) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + + activeProgram->disableAttributeArray(tangentLocation); + } + + if (state.worldSpaceVertices.isEmpty()) { + if (state.clusterMatrices.size() > 1) { + skinProgram->disableAttributeArray(skinLocations->clusterIndices); + skinProgram->disableAttributeArray(skinLocations->clusterWeights); + } + glPopMatrix(); + } + activeProgram->release(); + } +} diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 3e8cd2be9c..389020d1b1 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -214,6 +214,7 @@ protected: private: void deleteGeometry(); + void renderMeshes(float alpha, bool translucent); float _pupilDilation; std::vector _blendshapeCoefficients; diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 96fe84b305..dc6883a5d0 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -257,7 +257,8 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) : _request(url), _reply(NULL), _attempts(0), - _averageColor(1.0f, 1.0f, 1.0f, 1.0f) { + _averageColor(1.0f, 1.0f, 1.0f, 1.0f), + _translucent(false) { if (!url.isValid()) { return; @@ -300,19 +301,27 @@ void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTo QImage image = QImage::fromData(entirety).convertToFormat(QImage::Format_ARGB32); - // sum up the colors for the average + // sum up the colors for the average and check for translucency glm::vec4 accumulated; + int translucentPixels = 0; + const int EIGHT_BIT_MAXIMUM = 255; for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { QRgb pixel = image.pixel(x, y); accumulated.r += qRed(pixel); accumulated.g += qGreen(pixel); accumulated.b += qBlue(pixel); - accumulated.a += qAlpha(pixel); + + int alpha = qAlpha(pixel); + if (alpha != 0 && alpha != EIGHT_BIT_MAXIMUM) { + translucentPixels++; + } + accumulated.a += alpha; } } - const float EIGHT_BIT_MAXIMUM = 255.0f; - _averageColor = accumulated / (image.width() * image.height() * EIGHT_BIT_MAXIMUM); + int imageArea = image.width() * image.height(); + _averageColor = accumulated / (imageArea * EIGHT_BIT_MAXIMUM); + _translucent = (translucentPixels >= imageArea / 2); imageLoaded(image); glBindTexture(GL_TEXTURE_2D, getID()); diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index d3f138254f..e560acf6f7 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -121,6 +121,10 @@ public: /// Returns the average color over the entire texture. const glm::vec4& getAverageColor() const { return _averageColor; } + /// Checks whether it "looks like" this texture is translucent + /// (majority of pixels neither fully opaque or fully transparent). + bool isTranslucent() const { return _translucent; } + protected: virtual void imageLoaded(const QImage& image); @@ -137,6 +141,7 @@ private: QNetworkReply* _reply; int _attempts; glm::vec4 _averageColor; + bool _translucent; }; /// Caches derived, dilated textures. From cf05cf6178ae122fa3a6e89d023a025df7255b17 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 28 Jan 2014 12:03:41 -0800 Subject: [PATCH 3/3] Didn't need to disable depth writes after all (for now). --- interface/src/renderer/Model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c25e513b3b..6d61b2df68 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -272,7 +272,7 @@ bool Model::render(float alpha) { glDisable(GL_ALPHA_TEST); - // render translucent meshes afterwards, with back face culling and no depth writes + // render translucent meshes afterwards, with back face culling glEnable(GL_CULL_FACE);