2549 lines · 104.8 KB · C++
RawDownload
////  Model.cpp//  interface/src/renderer////  Created by Andrzej Kapolka on 10/18/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <gpu/GPUConfig.h> #include <QMetaType>#include <QRunnable>#include <QThreadPool> #include <glm/gtx/transform.hpp>#include <glm/gtx/norm.hpp> #include <CapsuleShape.h>#include <GeometryUtil.h>#include <gpu/Batch.h>#include <gpu/GLBackend.h>#include <PathUtils.h>#include <PerfStat.h>#include <PhysicsEntity.h>#include <ShapeCollider.h>#include <SphereShape.h>#include <ViewFrustum.h> #include "AbstractViewStateInterface.h"#include "AnimationHandle.h"#include "DeferredLightingEffect.h"#include "GlowEffect.h"#include "Model.h" #include "model_vert.h"#include "model_shadow_vert.h"
#include "model_normal_map_vert.h"
#include "model_lightmap_vert.h"
#include "model_lightmap_normal_map_vert.h"
#include "skin_model_vert.h"
#include "skin_model_shadow_vert.h"
#include "skin_model_normal_map_vert.h"
 #include "model_frag.h"#include "model_shadow_frag.h"#include "model_normal_map_frag.h"#include "model_normal_specular_map_frag.h"#include "model_specular_map_frag.h"#include "model_lightmap_frag.h"#include "model_lightmap_normal_map_frag.h"#include "model_lightmap_normal_specular_map_frag.h"#include "model_lightmap_specular_map_frag.h"#include "model_translucent_frag.h"  #define GLBATCH( call ) batch._##call//#define GLBATCH( call ) call using namespace std; static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; Model::Model(QObject* parent) :    QObject(parent),    _scale(1.0f, 1.0f, 1.0f),    _scaleToFit(false),    _scaleToFitDimensions(0.0f),    _scaledToFit(false),    _snapModelToRegistrationPoint(false),    _snappedToRegistrationPoint(false),    _showTrueJointTransforms(true),    _lodDistance(0.0f),    _pupilDilation(0.0f),    _url("http://invalid.com"),    _blendNumber(0),    _appliedBlendNumber(0),    _calculatedMeshBoxesValid(false),    _calculatedMeshTrianglesValid(false),    _meshGroupsKnown(false) {        // we may have been created in the network thread, but we live in the main thread    if (_viewState) {        moveToThread(_viewState->getMainThread());    }} Model::~Model() {    deleteGeometry();} ProgramObject Model::_program;ProgramObject Model::_normalMapProgram;ProgramObject Model::_specularMapProgram;ProgramObject Model::_normalSpecularMapProgram;ProgramObject Model::_translucentProgram; ProgramObject Model::_lightmapProgram;ProgramObject Model::_lightmapNormalMapProgram;ProgramObject Model::_lightmapSpecularMapProgram;ProgramObject Model::_lightmapNormalSpecularMapProgram; ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram;ProgramObject Model::_skinNormalMapProgram;ProgramObject Model::_skinSpecularMapProgram;ProgramObject Model::_skinNormalSpecularMapProgram;ProgramObject Model::_skinTranslucentProgram; ProgramObject Model::_skinShadowProgram; Model::Locations Model::_locations;Model::Locations Model::_normalMapLocations;Model::Locations Model::_specularMapLocations;Model::Locations Model::_normalSpecularMapLocations;Model::Locations Model::_translucentLocations; Model::Locations Model::_lightmapLocations;Model::Locations Model::_lightmapNormalMapLocations;Model::Locations Model::_lightmapSpecularMapLocations;Model::Locations Model::_lightmapNormalSpecularMapLocations; Model::SkinLocations Model::_skinLocations;Model::SkinLocations Model::_skinNormalMapLocations;Model::SkinLocations Model::_skinSpecularMapLocations;Model::SkinLocations Model::_skinNormalSpecularMapLocations;Model::SkinLocations Model::_skinShadowLocations;Model::SkinLocations Model::_skinTranslucentLocations; AbstractViewStateInterface* Model::_viewState = NULL; void Model::setScale(const glm::vec3& scale) {    setScaleInternal(scale);    // if anyone sets scale manually, then we are no longer scaled to fit    _scaleToFit = false;    _scaledToFit = false;} void Model::setScaleInternal(const glm::vec3& scale) {    float scaleLength = glm::length(_scale);    float relativeDeltaScale = glm::length(_scale - scale) / scaleLength;     const float ONE_PERCENT = 0.01f;    if (relativeDeltaScale > ONE_PERCENT || scaleLength < EPSILON) {        _scale = scale;        initJointTransforms();        if (_shapes.size() > 0) {            clearShapes();            buildShapes();        }    }} void Model::setOffset(const glm::vec3& offset) {     _offset = offset;         // if someone manually sets our offset, then we are no longer snapped to center    _snapModelToRegistrationPoint = false;     _snappedToRegistrationPoint = false; } void Model::initProgram(ProgramObject& program, Model::Locations& locations, bool link) {    if (link) {        program.bindAttributeLocation("tangent", gpu::Stream::TANGENT);        program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1);        program.link();    }    program.bind();     locations.tangent = program.attributeLocation("tangent");     locations.alphaThreshold = program.uniformLocation("alphaThreshold");    locations.texcoordMatrices = program.uniformLocation("texcoordMatrices");    locations.emissiveParams = program.uniformLocation("emissiveParams");    locations.glowIntensity = program.uniformLocation("glowIntensity");    program.setUniformValue("diffuseMap", 0);    program.setUniformValue("normalMap", 1);     int loc = program.uniformLocation("specularMap");    if (loc >= 0) {        program.setUniformValue("specularMap", 2);        locations.specularTextureUnit = 2;    } else {        locations.specularTextureUnit = -1;    }        loc = program.uniformLocation("emissiveMap");    if (loc >= 0) {        program.setUniformValue("emissiveMap", 3);        locations.emissiveTextureUnit = 3;    } else {        locations.emissiveTextureUnit = -1;    }     // bindable uniform version
#if defined(Q_OS_MAC)
    loc = program.uniformLocation("materialBuffer");
    if (loc >= 0) {
        locations.materialBufferUnit = loc;
    } else {
        locations.materialBufferUnit = -1;
    }
#elif defined(Q_OS_WIN)
    loc = glGetUniformBlockIndex(program.programId(), "materialBuffer");
    if (loc >= 0) {
        glUniformBlockBinding(program.programId(), loc, 1);
        locations.materialBufferUnit = 1;
    } else {
        locations.materialBufferUnit = -1;
    }
#else
    loc = program.uniformLocation("materialBuffer");
    if (loc >= 0) {
        locations.materialBufferUnit = loc;
    } else {
        locations.materialBufferUnit = -1;
    }
#endif

    if (!program.isLinked()) {
        program.release();
    }
     program.release();} void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) {    program.bindAttributeLocation("tangent", gpu::Stream::TANGENT);    program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1);    program.bindAttributeLocation("clusterIndices", gpu::Stream::SKIN_CLUSTER_INDEX);    program.bindAttributeLocation("clusterWeights", gpu::Stream::SKIN_CLUSTER_WEIGHT);    program.link();        initProgram(program, locations, false);     program.bind();     locations.clusterMatrices = program.uniformLocation("clusterMatrices");        locations.clusterIndices = program.attributeLocation("clusterIndices");    locations.clusterWeights = program.attributeLocation("clusterWeights");     program.release();} QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) {    QVector<JointState> jointStates;    for (int i = 0; i < geometry.joints.size(); ++i) {        const FBXJoint& joint = geometry.joints[i];        // store a pointer to the FBXJoint in the JointState        JointState state;        state.setFBXJoint(&joint);         jointStates.append(state);    }    return jointStates;}; void Model::initJointTransforms() {    // compute model transforms    int numStates = _jointStates.size();    for (int i = 0; i < numStates; ++i) {        JointState& state = _jointStates[i];        const FBXJoint& joint = state.getFBXJoint();        int parentIndex = joint.parentIndex;        if (parentIndex == -1) {            const FBXGeometry& geometry = _geometry->getFBXGeometry();            // NOTE: in practice geometry.offset has a non-unity scale (rather than a translation)            glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset;            state.initTransform(parentTransform);        } else {            const JointState& parentState = _jointStates.at(parentIndex);            state.initTransform(parentState.getTransform());        }    }} void Model::init() {    if (!_program.isLinked()) {        _program.addShaderFromSourceCode(QGLShader::Vertex, model_vert);        _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);        initProgram(_program, _locations);                _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
        _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
        initProgram(_normalMapProgram, _normalMapLocations);
        
        _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
        _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
        initProgram(_specularMapProgram, _specularMapLocations);
        
        _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
        _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
        initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
        
        _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
        _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
        initProgram(_translucentProgram, _translucentLocations);

        // Lightmap
        _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
        _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
        initProgram(_lightmapProgram, _lightmapLocations);

        _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
        _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
        initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
        
        _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
        _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
        initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
        
        _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
        _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
        initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
        // end lightmap

        
        _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
        _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);

        _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
        _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
        initSkinProgram(_skinProgram, _skinLocations);
        
        _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
        _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
        initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
        
        _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
        _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
        initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
        
        _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
        _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
        initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
        
        _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
        _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
        initSkinProgram(_skinShadowProgram, _skinShadowLocations);
        

        _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
        _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
        initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);    }} void Model::reset() {    if (_jointStates.isEmpty()) {        return;    }    foreach (Model* attachment, _attachments) {        attachment->reset();    }    const FBXGeometry& geometry = _geometry->getFBXGeometry();    for (int i = 0; i < _jointStates.size(); i++) {        _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f);    }        _meshGroupsKnown = false;} bool Model::updateGeometry() {    // NOTE: this is a recursive call that walks all attachments, and their attachments    bool needFullUpdate = false;    for (int i = 0; i < _attachments.size(); i++) {        Model* model = _attachments.at(i);        if (model->updateGeometry()) {            needFullUpdate = true;        }    }     bool needToRebuild = false;    if (_nextGeometry) {        _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis);        _nextGeometry->setLoadPriority(this, -_lodDistance);        _nextGeometry->ensureLoading();        if (_nextGeometry->isLoaded()) {            applyNextGeometry();            needToRebuild = true;        }    }    if (!_geometry) {        // geometry is not ready        return false;    }     QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis);    if (_geometry != geometry) {        // NOTE: it is theoretically impossible to reach here after passing through the applyNextGeometry() call above.        // Which means we don't need to worry about calling deleteGeometry() below immediately after creating new geometry.         const FBXGeometry& newGeometry = geometry->getFBXGeometry();        QVector<JointState> newJointStates = createJointStates(newGeometry);        if (! _jointStates.isEmpty()) {            // copy the existing joint states            const FBXGeometry& oldGeometry = _geometry->getFBXGeometry();            for (QHash<QString, int>::const_iterator it = oldGeometry.jointIndices.constBegin();                    it != oldGeometry.jointIndices.constEnd(); it++) {                int oldIndex = it.value() - 1;                int newIndex = newGeometry.getJointIndex(it.key());                if (newIndex != -1) {                    newJointStates[newIndex].copyState(_jointStates[oldIndex]);                }            }        }         deleteGeometry();        _dilatedTextures.clear();        _geometry = geometry;        _meshGroupsKnown = false;        setJointStates(newJointStates);        needToRebuild = true;    } else if (_jointStates.isEmpty()) {        const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();        if (fbxGeometry.joints.size() > 0) {            setJointStates(createJointStates(fbxGeometry));            needToRebuild = true;        }    } else if (!geometry->isLoaded()) {        deleteGeometry();        _dilatedTextures.clear();    }    _geometry->setLoadPriority(this, -_lodDistance);    _geometry->ensureLoading();       if (needToRebuild) {        const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();        foreach (const FBXMesh& mesh, fbxGeometry.meshes) {            MeshState state;            state.clusterMatrices.resize(mesh.clusters.size());            _meshStates.append(state);                 gpu::BufferPointer buffer(new gpu::Buffer());            if (!mesh.blendshapes.isEmpty()) {                buffer->resize((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3));                buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.vertices.constData());                buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3),                    mesh.normals.size() * sizeof(glm::vec3), (gpu::Resource::Byte*) mesh.normals.constData());            }            _blendedVertexBuffers.push_back(buffer);        }        foreach (const FBXAttachment& attachment, fbxGeometry.attachments) {            Model* model = new Model(this);            model->init();            model->setURL(attachment.url);            _attachments.append(model);        }        needFullUpdate = true;    }    return needFullUpdate;} // virtualvoid Model::setJointStates(QVector<JointState> states) {    _jointStates = states;    initJointTransforms();     int numStates = _jointStates.size();    float radius = 0.0f;    for (int i = 0; i < numStates; ++i) {        float distance = glm::length(_jointStates[i].getPosition());        if (distance > radius) {            radius = distance;        }        _jointStates[i].buildConstraint();    }    for (int i = 0; i < _jointStates.size(); i++) {        _jointStates[i].slaveVisibleTransform();    }    _boundingRadius = radius;} bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,                                                     BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) {     bool intersectedSomething = false;     // if we aren't active, we can't ray pick yet...    if (!isActive()) {        return intersectedSomething;    }        // extents is the entity relative, scaled, centered extents of the entity    glm::vec3 position = _translation;    glm::mat4 rotation = glm::mat4_cast(_rotation);    glm::mat4 translation = glm::translate(position);    glm::mat4 modelToWorldMatrix = translation * rotation;    glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);     Extents modelExtents = getMeshExtents(); // NOTE: unrotated        glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum;    glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference    AABox modelFrameBox(corner, dimensions);

Lines 1–500 of 2549.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t