mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 07:17:43 +02:00
Merge pull request #1723 from ey6es/master
Fixes for translucent textures (such as that used in jellyhead.fbx).
This commit is contained in:
commit
39a33b8c7d
8 changed files with 241 additions and 184 deletions
|
@ -25,5 +25,5 @@ void main(void) {
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,5 +37,5 @@ void main(void) {
|
||||||
|
|
||||||
// modulate texture by base color and add specular contribution
|
// modulate texture by base color and add specular contribution
|
||||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,3 +508,17 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
_meshes.append(networkMesh);
|
_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;
|
||||||
|
}
|
||||||
|
|
|
@ -93,6 +93,8 @@ public:
|
||||||
|
|
||||||
QSharedPointer<NetworkTexture> diffuseTexture;
|
QSharedPointer<NetworkTexture> diffuseTexture;
|
||||||
QSharedPointer<NetworkTexture> normalTexture;
|
QSharedPointer<NetworkTexture> normalTexture;
|
||||||
|
|
||||||
|
bool isTranslucent() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The state associated with a single mesh.
|
/// The state associated with a single mesh.
|
||||||
|
@ -103,6 +105,8 @@ public:
|
||||||
GLuint vertexBufferID;
|
GLuint vertexBufferID;
|
||||||
|
|
||||||
QVector<NetworkMeshPart> parts;
|
QVector<NetworkMeshPart> parts;
|
||||||
|
|
||||||
|
int getTranslucentPartCount() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__GeometryCache__) */
|
#endif /* defined(__interface__GeometryCache__) */
|
||||||
|
|
|
@ -240,7 +240,6 @@ bool Model::render(float alpha) {
|
||||||
|
|
||||||
// set up blended buffer ids on first render after load/simulate
|
// set up blended buffer ids on first render after load/simulate
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
|
||||||
if (_blendedVertexBufferIDs.isEmpty()) {
|
if (_blendedVertexBufferIDs.isEmpty()) {
|
||||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||||
GLuint id = 0;
|
GLuint id = 0;
|
||||||
|
@ -264,191 +263,28 @@ bool Model::render(float alpha) {
|
||||||
|
|
||||||
glDisable(GL_COLOR_MATERIAL);
|
glDisable(GL_COLOR_MATERIAL);
|
||||||
|
|
||||||
|
// render opaque meshes with alpha testing
|
||||||
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glAlphaFunc(GL_GREATER, 0.5f);
|
glAlphaFunc(GL_GREATER, 0.5f);
|
||||||
|
|
||||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
renderMeshes(alpha, false);
|
||||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID);
|
|
||||||
|
|
||||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
glDisable(GL_ALPHA_TEST);
|
||||||
int vertexCount = mesh.vertices.size();
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID);
|
// render translucent meshes afterwards, with back face culling
|
||||||
|
|
||||||
ProgramObject* program = &_program;
|
glEnable(GL_CULL_FACE);
|
||||||
ProgramObject* skinProgram = &_skinProgram;
|
|
||||||
SkinLocations* skinLocations = &_skinLocations;
|
|
||||||
if (!mesh.tangents.isEmpty()) {
|
|
||||||
program = &_normalMapProgram;
|
|
||||||
skinProgram = &_skinNormalMapProgram;
|
|
||||||
skinLocations = &_skinNormalMapLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MeshState& state = _meshStates.at(i);
|
renderMeshes(alpha, true);
|
||||||
ProgramObject* activeProgram = program;
|
|
||||||
int tangentLocation = _normalMapTangentLocation;
|
|
||||||
if (state.worldSpaceVertices.isEmpty()) {
|
|
||||||
glPushMatrix();
|
|
||||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
|
||||||
|
|
||||||
if (state.clusterMatrices.size() > 1) {
|
glDisable(GL_CULL_FACE);
|
||||||
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<DilatableNetworkTexture*>(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deactivate vertex arrays after drawing
|
// deactivate vertex arrays after drawing
|
||||||
glDisableClientState(GL_NORMAL_ARRAY);
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
|
|
||||||
// bind with 0 to switch back to normal operation
|
// bind with 0 to switch back to normal operation
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
@ -882,3 +718,191 @@ void Model::deleteGeometry() {
|
||||||
_jointStates.clear();
|
_jointStates.clear();
|
||||||
_meshStates.clear();
|
_meshStates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::renderMeshes(float alpha, bool translucent) {
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
const QVector<NetworkMesh>& 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<DilatableNetworkTexture*>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -214,6 +214,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void deleteGeometry();
|
void deleteGeometry();
|
||||||
|
void renderMeshes(float alpha, bool translucent);
|
||||||
|
|
||||||
float _pupilDilation;
|
float _pupilDilation;
|
||||||
std::vector<float> _blendshapeCoefficients;
|
std::vector<float> _blendshapeCoefficients;
|
||||||
|
|
|
@ -257,7 +257,8 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
||||||
_request(url),
|
_request(url),
|
||||||
_reply(NULL),
|
_reply(NULL),
|
||||||
_attempts(0),
|
_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()) {
|
if (!url.isValid()) {
|
||||||
return;
|
return;
|
||||||
|
@ -300,19 +301,27 @@ void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTo
|
||||||
|
|
||||||
QImage image = QImage::fromData(entirety).convertToFormat(QImage::Format_ARGB32);
|
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;
|
glm::vec4 accumulated;
|
||||||
|
int translucentPixels = 0;
|
||||||
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
for (int y = 0; y < image.height(); y++) {
|
for (int y = 0; y < image.height(); y++) {
|
||||||
for (int x = 0; x < image.width(); x++) {
|
for (int x = 0; x < image.width(); x++) {
|
||||||
QRgb pixel = image.pixel(x, y);
|
QRgb pixel = image.pixel(x, y);
|
||||||
accumulated.r += qRed(pixel);
|
accumulated.r += qRed(pixel);
|
||||||
accumulated.g += qGreen(pixel);
|
accumulated.g += qGreen(pixel);
|
||||||
accumulated.b += qBlue(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;
|
int imageArea = image.width() * image.height();
|
||||||
_averageColor = accumulated / (image.width() * image.height() * EIGHT_BIT_MAXIMUM);
|
_averageColor = accumulated / (imageArea * EIGHT_BIT_MAXIMUM);
|
||||||
|
_translucent = (translucentPixels >= imageArea / 2);
|
||||||
|
|
||||||
imageLoaded(image);
|
imageLoaded(image);
|
||||||
glBindTexture(GL_TEXTURE_2D, getID());
|
glBindTexture(GL_TEXTURE_2D, getID());
|
||||||
|
|
|
@ -121,6 +121,10 @@ public:
|
||||||
/// Returns the average color over the entire texture.
|
/// Returns the average color over the entire texture.
|
||||||
const glm::vec4& getAverageColor() const { return _averageColor; }
|
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:
|
protected:
|
||||||
|
|
||||||
virtual void imageLoaded(const QImage& image);
|
virtual void imageLoaded(const QImage& image);
|
||||||
|
@ -137,6 +141,7 @@ private:
|
||||||
QNetworkReply* _reply;
|
QNetworkReply* _reply;
|
||||||
int _attempts;
|
int _attempts;
|
||||||
glm::vec4 _averageColor;
|
glm::vec4 _averageColor;
|
||||||
|
bool _translucent;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Caches derived, dilated textures.
|
/// Caches derived, dilated textures.
|
||||||
|
|
Loading…
Reference in a new issue