diff --git a/interface/resources/shaders/model.frag b/interface/resources/shaders/model.frag index 7358c7dba9..12b81485e5 100644 --- a/interface/resources/shaders/model.frag +++ b/interface/resources/shaders/model.frag @@ -17,8 +17,8 @@ varying vec4 normal; void main(void) { // compute the base color based on OpenGL lighting model vec4 normalizedNormal = normalize(normal); - vec4 base = gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + - gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position)); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalizedNormal, gl_LightSource[0].position))); // compute the specular component (sans exponent) float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalizedNormal)); diff --git a/interface/resources/shaders/model.vert b/interface/resources/shaders/model.vert index 16893dfc0b..b9c1a35e11 100644 --- a/interface/resources/shaders/model.vert +++ b/interface/resources/shaders/model.vert @@ -16,7 +16,10 @@ void main(void) { // transform and store the normal for interpolation normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); - // pass along the texture coordinate + // pass along the vertex color + gl_FrontColor = gl_Color; + + // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; // use standard pipeline transform diff --git a/interface/resources/shaders/skin_model.vert b/interface/resources/shaders/skin_model.vert index d968d17df0..950283107f 100644 --- a/interface/resources/shaders/skin_model.vert +++ b/interface/resources/shaders/skin_model.vert @@ -31,7 +31,10 @@ void main(void) { position = gl_ModelViewProjectionMatrix * position; normal = normalize(gl_ModelViewMatrix * normal); - // pass along the texture coordinate + // pass along the vertex color + gl_FrontColor = gl_Color; + + // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = position; diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index e899d847af..fa5da82686 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -18,6 +18,10 @@ #include #include +#include + +#include + #include "FBXReader.h" #include "Util.h" @@ -1192,3 +1196,102 @@ FBXGeometry readFBX(const QByteArray& model, const QByteArray& mapping) { return extractFBXGeometry(parseFBX(&modelBuffer), parseMapping(&mappingBuffer)); } +bool addMeshVoxelsOperation(VoxelNode* node, void* extraData) { + if (!node->isLeaf()) { + return true; + } + FBXMesh& mesh = *static_cast(extraData); + FBXMeshPart& part = mesh.parts[0]; + + const int FACE_COUNT = 6; + const int VERTICES_PER_FACE = 4; + const int VERTEX_COUNT = FACE_COUNT * VERTICES_PER_FACE; + const float EIGHT_BIT_MAXIMUM = 255.0f; + glm::vec3 color = glm::vec3(node->getColor()[0], node->getColor()[1], node->getColor()[2]) / EIGHT_BIT_MAXIMUM; + for (int i = 0; i < VERTEX_COUNT; i++) { + part.quadIndices.append(part.quadIndices.size()); + mesh.colors.append(color); + } + glm::vec3 corner = node->getCorner(); + float scale = node->getScale(); + + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(-1.0f, 0.0f, 0.0f)); + } + + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(1.0f, 0.0f, 0.0f)); + } + + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(0.0f, -1.0f, 0.0f)); + } + + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(0.0f, 1.0f, 0.0f)); + } + + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z)); + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(0.0f, 0.0f, -1.0f)); + } + + mesh.vertices.append(glm::vec3(corner.x, corner.y, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x + scale, corner.y + scale, corner.z + scale)); + mesh.vertices.append(glm::vec3(corner.x, corner.y + scale, corner.z + scale)); + for (int i = 0; i < VERTICES_PER_FACE; i++) { + mesh.normals.append(glm::vec3(0.0f, 0.0f, 1.0f)); + } + + return true; +} + +FBXGeometry readSVO(const QByteArray& model) { + FBXGeometry geometry; + + // we have one joint + FBXJoint joint = { -1 }; + geometry.joints.append(joint); + + // and one mesh with one cluster and one part + FBXMesh mesh; + mesh.isEye = false; + mesh.springiness = 0.0f; + + FBXCluster cluster = { 0 }; + mesh.clusters.append(cluster); + + FBXMeshPart part; + part.diffuseColor = glm::vec3(1.0f, 1.0f, 1.0f); + part.shininess = 96.0f; + mesh.parts.append(part); + + VoxelTree tree; + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS); + tree.readBitstreamToTree((unsigned char*)model.data(), model.size(), args); + tree.recurseTreeWithOperation(addMeshVoxelsOperation, &mesh); + + geometry.meshes.append(mesh); + + return geometry; +} diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 4a16ba19b9..557574316e 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -84,6 +84,7 @@ public: QVector vertices; QVector normals; + QVector colors; QVector texCoords; QVector clusterIndices; QVector clusterWeights; @@ -137,4 +138,7 @@ public: /// \exception QString if an error occurs in parsing FBXGeometry readFBX(const QByteArray& model, const QByteArray& mapping); +/// Reads SVO geometry from the supplied model data. +FBXGeometry readSVO(const QByteArray& model); + #endif /* defined(__interface__FBXReader__) */ diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index ea3f8fa1fc..7e85c1c895 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -348,7 +348,7 @@ void NetworkGeometry::maybeReadModelWithMapping() { } try { - _geometry = readFBX(model, mapping); + _geometry = url.path().toLower().endsWith(".svo") ? readSVO(model) : readFBX(model, mapping); } catch (const QString& error) { qDebug() << "Error reading " << url << ": " << error << "\n"; @@ -395,35 +395,43 @@ void NetworkGeometry::maybeReadModelWithMapping() { // if we don't need to do any blending or springing, then the positions/normals can be static if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { - glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) + - mesh.texCoords.size() * sizeof(glm::vec2) + (mesh.clusterIndices.size() + - mesh.clusterWeights.size()) * sizeof(glm::vec4), NULL, GL_STATIC_DRAW); + int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); + int colorsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4), + NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(glm::vec3), - mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); - glBufferSubData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), - mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData()); - glBufferSubData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) + - mesh.texCoords.size() * sizeof(glm::vec2), mesh.clusterIndices.size() * sizeof(glm::vec4), + glBufferSubData(GL_ARRAY_BUFFER, normalsOffset, mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); + glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); + glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), + mesh.texCoords.constData()); + glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4), mesh.clusterIndices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) + - mesh.texCoords.size() * sizeof(glm::vec2) + mesh.clusterIndices.size() * sizeof(glm::vec4), - mesh.clusterWeights.size() * sizeof(glm::vec4), mesh.clusterWeights.constData()); + glBufferSubData(GL_ARRAY_BUFFER, clusterWeightsOffset, mesh.clusterWeights.size() * sizeof(glm::vec4), + mesh.clusterWeights.constData()); // if there's no springiness, then the cluster indices/weights can be static } else if (mesh.springiness == 0.0f) { - glBufferData(GL_ARRAY_BUFFER, mesh.texCoords.size() * sizeof(glm::vec2) + (mesh.clusterIndices.size() + - mesh.clusterWeights.size()) * sizeof(glm::vec4), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData()); - glBufferSubData(GL_ARRAY_BUFFER, mesh.texCoords.size() * sizeof(glm::vec2), - mesh.clusterIndices.size() * sizeof(glm::vec4), mesh.clusterIndices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, mesh.texCoords.size() * sizeof(glm::vec2) + - mesh.clusterIndices.size() * sizeof(glm::vec4), mesh.clusterWeights.size() * sizeof(glm::vec4), + int texCoordsOffset = mesh.colors.size() * sizeof(glm::vec3); + int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4), + NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); + glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData()); + glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4), + mesh.clusterIndices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, clusterWeightsOffset, mesh.clusterWeights.size() * sizeof(glm::vec4), mesh.clusterWeights.constData()); } else { - glBufferData(GL_ARRAY_BUFFER, mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData()); + int texCoordsOffset = mesh.colors.size() * sizeof(glm::vec3); + glBufferData(GL_ARRAY_BUFFER, texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); + glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), + mesh.texCoords.constData()); } glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c1222a8796..5bcc0520b9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -234,7 +234,6 @@ bool Model::render(float alpha) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_COLOR_MATERIAL); @@ -253,8 +252,8 @@ bool Model::render(float alpha) { _skinProgram.bind(); glUniformMatrix4fvARB(_clusterMatricesLocation, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - int offset = vertexCount * sizeof(glm::vec2) + (mesh.blendshapes.isEmpty() ? - vertexCount * 2 * sizeof(glm::vec3) : 0); + int offset = mesh.colors.size() * sizeof(glm::vec3) + mesh.texCoords.size() * sizeof(glm::vec2) + + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); _skinProgram.setAttributeBuffer(_clusterIndicesLocation, GL_FLOAT, offset, 4); _skinProgram.setAttributeBuffer(_clusterWeightsLocation, GL_FLOAT, offset + vertexCount * sizeof(glm::vec4), 4); @@ -271,10 +270,13 @@ bool Model::render(float alpha) { } if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { - glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3))); + glColorPointer(3, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3))); + glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3) + + mesh.colors.size() * sizeof(glm::vec3))); } else { - glTexCoordPointer(2, GL_FLOAT, 0, 0); + glColorPointer(3, GL_FLOAT, 0, 0); + glTexCoordPointer(2, GL_FLOAT, 0, (void*)(mesh.colors.size() * sizeof(glm::vec3))); glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); if (!state.worldSpaceVertices.isEmpty()) { @@ -313,6 +315,15 @@ bool Model::render(float alpha) { 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); @@ -343,6 +354,13 @@ bool Model::render(float alpha) { offset += part.triangleIndices.size() * sizeof(int); } + if (!mesh.colors.isEmpty()) { + glDisableClientState(GL_COLOR_ARRAY); + } + if (!mesh.texCoords.isEmpty()) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + if (state.worldSpaceVertices.isEmpty()) { if (state.clusterMatrices.size() > 1) { _skinProgram.disableAttributeArray(_clusterIndicesLocation);