820 lines · 35.0 KB · C++
RawDownload
////  Model.cpp//  interface////  Created by Andrzej Kapolka on 10/18/13.//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.// #include <glm/gtx/transform.hpp> #include <GeometryUtil.h> #include "Application.h"#include "Model.h" using namespace std; Model::Model(QObject* parent) :    QObject(parent),    _pupilDilation(0.0f){    // we may have been created in the network thread, but we live in the main thread    moveToThread(Application::getInstance()->thread());} Model::~Model() {    deleteGeometry();} ProgramObject Model::_program;ProgramObject Model::_normalMapProgram;ProgramObject Model::_skinProgram;ProgramObject Model::_skinNormalMapProgram;int Model::_normalMapTangentLocation;Model::SkinLocations Model::_skinLocations;Model::SkinLocations Model::_skinNormalMapLocations; void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) {    program.bind();    locations.clusterMatrices = program.uniformLocation("clusterMatrices");    locations.clusterIndices = program.attributeLocation("clusterIndices");    locations.clusterWeights = program.attributeLocation("clusterWeights");    locations.tangent = program.attributeLocation("tangent");    program.setUniformValue("diffuseMap", 0);    program.setUniformValue("normalMap", 1);    program.release();} void Model::init() {    if (!_program.isLinked()) {        switchToResourcesParentIfRequired();        _program.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/model.vert");        _program.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model.frag");        _program.link();                _program.bind();        _program.setUniformValue("texture", 0);        _program.release();                _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/model_normal_map.vert");        _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model_normal_map.frag");        _normalMapProgram.link();                _normalMapProgram.bind();        _normalMapProgram.setUniformValue("diffuseMap", 0);        _normalMapProgram.setUniformValue("normalMap", 1);        _normalMapTangentLocation = _normalMapProgram.attributeLocation("tangent");        _normalMapProgram.release();                _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_model.vert");        _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model.frag");        _skinProgram.link();                initSkinProgram(_skinProgram, _skinLocations);                _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_model_normal_map.vert");        _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/model_normal_map.frag");        _skinNormalMapProgram.link();                initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);    }} void Model::reset() {    _resetStates = true;        foreach (Model* attachment, _attachments) {        attachment->reset();    }} void Model::simulate(float deltaTime) {    if (!isActive()) {        return;    }        // set up world vertices on first simulate after load    const FBXGeometry& geometry = _geometry->getFBXGeometry();    if (_jointStates.isEmpty()) {        foreach (const FBXJoint& joint, geometry.joints) {            JointState state;            state.rotation = joint.rotation;            _jointStates.append(state);        }        foreach (const FBXMesh& mesh, geometry.meshes) {            MeshState state;            state.clusterMatrices.resize(mesh.clusters.size());            if (mesh.springiness > 0.0f) {                state.worldSpaceVertices.resize(mesh.vertices.size());                state.vertexVelocities.resize(mesh.vertices.size());                state.worldSpaceNormals.resize(mesh.vertices.size());            }            _meshStates.append(state);            }        foreach (const FBXAttachment& attachment, geometry.attachments) {            Model* model = new Model(this);            model->init();            model->setURL(attachment.url);            _attachments.append(model);        }        _resetStates = true;    }        // update the world space transforms for all joints    for (int i = 0; i < _jointStates.size(); i++) {        updateJointState(i);    }        // update the attachment transforms and simulate them    for (int i = 0; i < _attachments.size(); i++) {        const FBXAttachment& attachment = geometry.attachments.at(i);        Model* model = _attachments.at(i);                glm::vec3 jointTranslation = _translation;        glm::quat jointRotation = _rotation;        getJointPosition(attachment.jointIndex, jointTranslation);        getJointRotation(attachment.jointIndex, jointRotation);                model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale);        model->setRotation(jointRotation * attachment.rotation);        model->setScale(_scale * attachment.scale);                model->simulate(deltaTime);    }        for (int i = 0; i < _meshStates.size(); i++) {        MeshState& state = _meshStates[i];        const FBXMesh& mesh = geometry.meshes.at(i);        for (int j = 0; j < mesh.clusters.size(); j++) {            const FBXCluster& cluster = mesh.clusters.at(j);            state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix;        }        int vertexCount = state.worldSpaceVertices.size();        if (vertexCount == 0) {            continue;        }        glm::vec3* destVertices = state.worldSpaceVertices.data();        glm::vec3* destVelocities = state.vertexVelocities.data();        glm::vec3* destNormals = state.worldSpaceNormals.data();                const glm::vec3* sourceVertices = mesh.vertices.constData();        if (!mesh.blendshapes.isEmpty()) {            _blendedVertices.resize(max(_blendedVertices.size(), vertexCount));            memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3));                        // blend in each coefficient            for (int j = 0; j < _blendshapeCoefficients.size(); j++) {                float coefficient = _blendshapeCoefficients[j];                if (coefficient == 0.0f || j >= mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) {                    continue;                }                const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData();                for (const int* index = mesh.blendshapes[j].indices.constData(),                        *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) {                    _blendedVertices[*index] += *vertex * coefficient;                }            }            sourceVertices = _blendedVertices.constData();        }        glm::mat4 transform = glm::translate(_translation);        if (mesh.clusters.size() > 1) {            _blendedVertices.resize(max(_blendedVertices.size(), vertexCount));             // skin each vertex            const glm::vec4* clusterIndices = mesh.clusterIndices.constData();            const glm::vec4* clusterWeights = mesh.clusterWeights.constData();            for (int j = 0; j < vertexCount; j++) {                _blendedVertices[j] =                    glm::vec3(state.clusterMatrices[clusterIndices[j][0]] *                        glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] +                    glm::vec3(state.clusterMatrices[clusterIndices[j][1]] *                        glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] +                    glm::vec3(state.clusterMatrices[clusterIndices[j][2]] *                        glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] +                    glm::vec3(state.clusterMatrices[clusterIndices[j][3]] *                        glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3];            }            sourceVertices = _blendedVertices.constData();                    } else {            transform = state.clusterMatrices[0];        }        if (_resetStates) {            for (int j = 0; j < vertexCount; j++) {                destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f));                        destVelocities[j] = glm::vec3();            }                } else {            const float SPRINGINESS_MULTIPLIER = 200.0f;            const float DAMPING = 5.0f;            for (int j = 0; j < vertexCount; j++) {                destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) *                    mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime;                destVertices[j] += destVelocities[j] * deltaTime;            }        }        for (int j = 0; j < vertexCount; j++) {            destNormals[j] = glm::vec3();                        const glm::vec3& middle = destVertices[j];            for (QVarLengthArray<QPair<int, int>, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin();                     connection != mesh.vertexConnections.at(j).constEnd(); connection++) {                destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle,                    destVertices[connection->first] - middle));            }        }    }    _resetStates = false;} bool Model::render(float alpha) {    // render the attachments    foreach (Model* attachment, _attachments) {        attachment->render(alpha);    }    if (_meshStates.isEmpty()) {        return false;    }        // set up blended buffer ids on first render after load/simulate    const FBXGeometry& geometry = _geometry->getFBXGeometry();    const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();    if (_blendedVertexBufferIDs.isEmpty()) {        foreach (const FBXMesh& mesh, geometry.meshes) {            GLuint id = 0;            if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) {                glGenBuffers(1, &id);                glBindBuffer(GL_ARRAY_BUFFER, id);                glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),                    NULL, GL_DYNAMIC_DRAW);                glBindBuffer(GL_ARRAY_BUFFER, 0);            }            _blendedVertexBufferIDs.append(id);                        QVector<QSharedPointer<Texture> > dilated;            dilated.resize(mesh.parts.size());            _dilatedTextures.append(dilated);        }    }     glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);        glDisable(GL_COLOR_MATERIAL);        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 (int j = 0; j < _blendshapeCoefficients.size(); j++) {                    float coefficient = _blendshapeCoefficients[j];                    if (coefficient == 0.0f || j >= 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    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);    glBindTexture(GL_TEXTURE_2D, 0);        // restore all the default material settings    Application::getInstance()->setupWorldLight();     return true;} int Model::getParentJointIndex(int jointIndex) const {    return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).parentIndex : -1;} int Model::getLastFreeJointIndex(int jointIndex) const {    return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;} bool Model::getHeadPosition(glm::vec3& headPosition) const {    return isActive() && getJointPosition(_geometry->getFBXGeometry().headJointIndex, headPosition);} bool Model::getNeckPosition(glm::vec3& neckPosition) const {    return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition);} bool Model::getNeckRotation(glm::quat& neckRotation) const {    return isActive() && getJointRotation(_geometry->getFBXGeometry().neckJointIndex, neckRotation);} bool Model::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {    if (!isActive()) {        return false;    }    const FBXGeometry& geometry = _geometry->getFBXGeometry();    return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) &&        getJointPosition(geometry.rightEyeJointIndex, secondEyePosition);} bool Model::setLeftHandPosition(const glm::vec3& position) {    return setJointPosition(getLeftHandJointIndex(), position);} bool Model::restoreLeftHandPosition(float percent) {    return restoreJointPosition(getLeftHandJointIndex(), percent);} bool Model::setLeftHandRotation(const glm::quat& rotation) {    return setJointRotation(getLeftHandJointIndex(), rotation);

Lines 1–500 of 820.