//// 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 <QMetaType>#include <QRunnable>#include <QScriptEngine>#include <QThreadPool> #include <glm/gtx/transform.hpp>#include <glm/gtx/norm.hpp> #include <CapsuleShape.h>#include <GeometryUtil.h>#include <PhysicsEntity.h>#include <RegisteredMetaTypes.h>#include <ShapeCollider.h>#include <SphereShape.h> #include "Application.h"#include "Model.h" using namespace std; static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >(); static QScriptValue localLightToScriptValue(QScriptEngine* engine, const Model::LocalLight& light) { QScriptValue object = engine->newObject(); object.setProperty("direction", vec3toScriptValue(engine, light.direction)); object.setProperty("color", vec3toScriptValue(engine, light.color)); return object;} static void localLightFromScriptValue(const QScriptValue& value, Model::LocalLight& light) { vec3FromScriptValue(value.property("direction"), light.direction); vec3FromScriptValue(value.property("color"), light.color);} void Model::registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, localLightToScriptValue, localLightFromScriptValue); qScriptRegisterSequenceMetaType<QVector<Model::LocalLight> >(engine);} Model::Model(QObject* parent) : QObject(parent), _scale(1.0f, 1.0f, 1.0f), _scaleToFit(false), _scaleToFitLargestDimension(0.0f), _scaledToFit(false), _snapModelToCenter(false), _snappedToCenter(false), _showTrueJointTransforms(true), _lodDistance(0.0f), _pupilDilation(0.0f), _url("http://invalid.com") { // 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::_specularMapProgram;ProgramObject Model::_normalSpecularMapProgram; ProgramObject Model::_shadowMapProgram;ProgramObject Model::_shadowNormalMapProgram;ProgramObject Model::_shadowSpecularMapProgram;ProgramObject Model::_shadowNormalSpecularMapProgram; ProgramObject Model::_cascadedShadowMapProgram;ProgramObject Model::_cascadedShadowNormalMapProgram;ProgramObject Model::_cascadedShadowSpecularMapProgram;ProgramObject Model::_cascadedShadowNormalSpecularMapProgram; ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram;ProgramObject Model::_skinNormalMapProgram;ProgramObject Model::_skinSpecularMapProgram;ProgramObject Model::_skinNormalSpecularMapProgram; ProgramObject Model::_skinShadowMapProgram;ProgramObject Model::_skinShadowNormalMapProgram;ProgramObject Model::_skinShadowSpecularMapProgram;ProgramObject Model::_skinShadowNormalSpecularMapProgram; ProgramObject Model::_skinCascadedShadowMapProgram;ProgramObject Model::_skinCascadedShadowNormalMapProgram;ProgramObject Model::_skinCascadedShadowSpecularMapProgram;ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram; ProgramObject Model::_skinShadowProgram; Model::Locations Model::_locations;Model::Locations Model::_normalMapLocations;Model::Locations Model::_specularMapLocations;Model::Locations Model::_normalSpecularMapLocations;Model::Locations Model::_shadowMapLocations;Model::Locations Model::_shadowNormalMapLocations;Model::Locations Model::_shadowSpecularMapLocations;Model::Locations Model::_shadowNormalSpecularMapLocations;Model::Locations Model::_cascadedShadowMapLocations;Model::Locations Model::_cascadedShadowNormalMapLocations;Model::Locations Model::_cascadedShadowSpecularMapLocations;Model::Locations Model::_cascadedShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinLocations;Model::SkinLocations Model::_skinNormalMapLocations;Model::SkinLocations Model::_skinSpecularMapLocations;Model::SkinLocations Model::_skinNormalSpecularMapLocations;Model::SkinLocations Model::_skinShadowMapLocations;Model::SkinLocations Model::_skinShadowNormalMapLocations;Model::SkinLocations Model::_skinShadowSpecularMapLocations;Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations;Model::SkinLocations Model::_skinCascadedShadowMapLocations;Model::SkinLocations Model::_skinCascadedShadowNormalMapLocations;Model::SkinLocations Model::_skinCascadedShadowSpecularMapLocations;Model::SkinLocations Model::_skinCascadedShadowNormalSpecularMapLocations;Model::SkinLocations Model::_skinShadowLocations; 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 _snapModelToCenter = false; _snappedToCenter = false; } void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit, int shadowTextureUnit) { program.bind(); locations.tangent = program.attributeLocation("tangent"); locations.shadowDistances = program.uniformLocation("shadowDistances"); locations.localLightColors = program.uniformLocation("localLightColors"); locations.localLightDirections = program.uniformLocation("localLightDirections"); program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); program.release();} void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit, int shadowTextureUnit) { initProgram(program, locations, specularTextureUnit, shadowTextureUnit); 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.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _program.link(); initProgram(_program, _locations); _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); _normalMapProgram.link(); initProgram(_normalMapProgram, _normalMapLocations); _specularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _specularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); _specularMapProgram.link(); initProgram(_specularMapProgram, _specularMapLocations); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); _normalSpecularMapProgram.link(); initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations, 2); _shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_map.frag"); _shadowMapProgram.link(); initProgram(_shadowMapProgram, _shadowMapLocations); _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); _shadowNormalMapProgram.link(); initProgram(_shadowNormalMapProgram, _shadowNormalMapLocations, 1, 2); _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); _shadowSpecularMapProgram.link(); initProgram(_shadowSpecularMapProgram, _shadowSpecularMapLocations, 1, 2); _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); _shadowNormalSpecularMapProgram.link(); initProgram(_shadowNormalSpecularMapProgram, _shadowNormalSpecularMapLocations, 2, 3); _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_map.frag"); _cascadedShadowMapProgram.link(); initProgram(_cascadedShadowMapProgram, _cascadedShadowMapLocations); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); _cascadedShadowNormalMapProgram.link(); initProgram(_cascadedShadowNormalMapProgram, _cascadedShadowNormalMapLocations, 1, 2); _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); _cascadedShadowSpecularMapProgram.link(); initProgram(_cascadedShadowSpecularMapProgram, _cascadedShadowSpecularMapLocations, 1, 2); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); _cascadedShadowNormalSpecularMapProgram.link(); initProgram(_cascadedShadowNormalSpecularMapProgram, _cascadedShadowNormalSpecularMapLocations, 2, 3); _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); _shadowProgram.link(); _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _skinProgram.link(); initSkinProgram(_skinProgram, _skinLocations); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); _skinNormalMapProgram.link(); initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); _skinSpecularMapProgram.link(); initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); _skinNormalSpecularMapProgram.link(); initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_map.frag"); _skinShadowMapProgram.link(); initSkinProgram(_skinShadowMapProgram, _skinShadowMapLocations); _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); _skinShadowNormalMapProgram.link(); initSkinProgram(_skinShadowNormalMapProgram, _skinShadowNormalMapLocations, 1, 2); _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); _skinShadowSpecularMapProgram.link(); initSkinProgram(_skinShadowSpecularMapProgram, _skinShadowSpecularMapLocations, 1, 2); _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); _skinShadowNormalSpecularMapProgram.link(); initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_map.frag"); _skinCascadedShadowMapProgram.link(); initSkinProgram(_skinCascadedShadowMapProgram, _skinCascadedShadowMapLocations); _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); _skinCascadedShadowNormalMapProgram.link(); initSkinProgram(_skinCascadedShadowNormalMapProgram, _skinCascadedShadowNormalMapLocations, 1, 2); _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); _skinCascadedShadowSpecularMapProgram.link(); initSkinProgram(_skinCascadedShadowSpecularMapProgram, _skinCascadedShadowSpecularMapLocations, 1, 2); _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); _skinCascadedShadowNormalSpecularMapProgram.link(); initSkinProgram(_skinCascadedShadowNormalSpecularMapProgram, _skinCascadedShadowNormalSpecularMapLocations, 2, 3); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); _skinShadowProgram.link(); initSkinProgram(_skinShadowProgram, _skinShadowLocations); }} 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); }} 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; 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()) {Lines 1–500 of 1753. Load more
// // 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 <QMetaType> #include <QRunnable> #include <QScriptEngine> #include <QThreadPool> #include <glm/gtx/transform.hpp> #include <glm/gtx/norm.hpp> #include <CapsuleShape.h> #include <GeometryUtil.h> #include <PhysicsEntity.h> #include <RegisteredMetaTypes.h> #include <ShapeCollider.h> #include <SphereShape.h> #include "Application.h" #include "Model.h" using namespace std; static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >(); static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >(); static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >(); static QScriptValue localLightToScriptValue(QScriptEngine* engine, const Model::LocalLight& light) { QScriptValue object = engine->newObject(); object.setProperty("direction", vec3toScriptValue(engine, light.direction)); object.setProperty("color", vec3toScriptValue(engine, light.color)); return object; } static void localLightFromScriptValue(const QScriptValue& value, Model::LocalLight& light) { vec3FromScriptValue(value.property("direction"), light.direction); vec3FromScriptValue(value.property("color"), light.color); } void Model::registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, localLightToScriptValue, localLightFromScriptValue); qScriptRegisterSequenceMetaType<QVector<Model::LocalLight> >(engine); } Model::Model(QObject* parent) : QObject(parent), _scale(1.0f, 1.0f, 1.0f), _scaleToFit(false), _scaleToFitLargestDimension(0.0f), _scaledToFit(false), _snapModelToCenter(false), _snappedToCenter(false), _showTrueJointTransforms(true), _lodDistance(0.0f), _pupilDilation(0.0f), _url("http://invalid.com") { // 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::_specularMapProgram; ProgramObject Model::_normalSpecularMapProgram; ProgramObject Model::_shadowMapProgram; ProgramObject Model::_shadowNormalMapProgram; ProgramObject Model::_shadowSpecularMapProgram; ProgramObject Model::_shadowNormalSpecularMapProgram; ProgramObject Model::_cascadedShadowMapProgram; ProgramObject Model::_cascadedShadowNormalMapProgram; ProgramObject Model::_cascadedShadowSpecularMapProgram; ProgramObject Model::_cascadedShadowNormalSpecularMapProgram; ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram; ProgramObject Model::_skinNormalMapProgram; ProgramObject Model::_skinSpecularMapProgram; ProgramObject Model::_skinNormalSpecularMapProgram; ProgramObject Model::_skinShadowMapProgram; ProgramObject Model::_skinShadowNormalMapProgram; ProgramObject Model::_skinShadowSpecularMapProgram; ProgramObject Model::_skinShadowNormalSpecularMapProgram; ProgramObject Model::_skinCascadedShadowMapProgram; ProgramObject Model::_skinCascadedShadowNormalMapProgram; ProgramObject Model::_skinCascadedShadowSpecularMapProgram; ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram; ProgramObject Model::_skinShadowProgram; Model::Locations Model::_locations; Model::Locations Model::_normalMapLocations; Model::Locations Model::_specularMapLocations; Model::Locations Model::_normalSpecularMapLocations; Model::Locations Model::_shadowMapLocations; Model::Locations Model::_shadowNormalMapLocations; Model::Locations Model::_shadowSpecularMapLocations; Model::Locations Model::_shadowNormalSpecularMapLocations; Model::Locations Model::_cascadedShadowMapLocations; Model::Locations Model::_cascadedShadowNormalMapLocations; Model::Locations Model::_cascadedShadowSpecularMapLocations; Model::Locations Model::_cascadedShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinSpecularMapLocations; Model::SkinLocations Model::_skinNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowMapLocations; Model::SkinLocations Model::_skinShadowNormalMapLocations; Model::SkinLocations Model::_skinShadowSpecularMapLocations; Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinCascadedShadowMapLocations; Model::SkinLocations Model::_skinCascadedShadowNormalMapLocations; Model::SkinLocations Model::_skinCascadedShadowSpecularMapLocations; Model::SkinLocations Model::_skinCascadedShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; 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 _snapModelToCenter = false; _snappedToCenter = false; } void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit, int shadowTextureUnit) { program.bind(); locations.tangent = program.attributeLocation("tangent"); locations.shadowDistances = program.uniformLocation("shadowDistances"); locations.localLightColors = program.uniformLocation("localLightColors"); locations.localLightDirections = program.uniformLocation("localLightDirections"); program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); program.release(); } void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit, int shadowTextureUnit) { initProgram(program, locations, specularTextureUnit, shadowTextureUnit); 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.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _program.link(); initProgram(_program, _locations); _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); _normalMapProgram.link(); initProgram(_normalMapProgram, _normalMapLocations); _specularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _specularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); _specularMapProgram.link(); initProgram(_specularMapProgram, _specularMapLocations); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); _normalSpecularMapProgram.link(); initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations, 2); _shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_map.frag"); _shadowMapProgram.link(); initProgram(_shadowMapProgram, _shadowMapLocations); _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); _shadowNormalMapProgram.link(); initProgram(_shadowNormalMapProgram, _shadowNormalMapLocations, 1, 2); _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); _shadowSpecularMapProgram.link(); initProgram(_shadowSpecularMapProgram, _shadowSpecularMapLocations, 1, 2); _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); _shadowNormalSpecularMapProgram.link(); initProgram(_shadowNormalSpecularMapProgram, _shadowNormalSpecularMapLocations, 2, 3); _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_map.frag"); _cascadedShadowMapProgram.link(); initProgram(_cascadedShadowMapProgram, _cascadedShadowMapLocations); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); _cascadedShadowNormalMapProgram.link(); initProgram(_cascadedShadowNormalMapProgram, _cascadedShadowNormalMapLocations, 1, 2); _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); _cascadedShadowSpecularMapProgram.link(); initProgram(_cascadedShadowSpecularMapProgram, _cascadedShadowSpecularMapLocations, 1, 2); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); _cascadedShadowNormalSpecularMapProgram.link(); initProgram(_cascadedShadowNormalSpecularMapProgram, _cascadedShadowNormalSpecularMapLocations, 2, 3); _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); _shadowProgram.link(); _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _skinProgram.link(); initSkinProgram(_skinProgram, _skinLocations); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); _skinNormalMapProgram.link(); initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); _skinSpecularMapProgram.link(); initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); _skinNormalSpecularMapProgram.link(); initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_map.frag"); _skinShadowMapProgram.link(); initSkinProgram(_skinShadowMapProgram, _skinShadowMapLocations); _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_map.frag"); _skinShadowNormalMapProgram.link(); initSkinProgram(_skinShadowNormalMapProgram, _skinShadowNormalMapLocations, 1, 2); _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); _skinShadowSpecularMapProgram.link(); initSkinProgram(_skinShadowSpecularMapProgram, _skinShadowSpecularMapLocations, 1, 2); _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag"); _skinShadowNormalSpecularMapProgram.link(); initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_map.frag"); _skinCascadedShadowMapProgram.link(); initSkinProgram(_skinCascadedShadowMapProgram, _skinCascadedShadowMapLocations); _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); _skinCascadedShadowNormalMapProgram.link(); initSkinProgram(_skinCascadedShadowNormalMapProgram, _skinCascadedShadowNormalMapLocations, 1, 2); _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); _skinCascadedShadowSpecularMapProgram.link(); initSkinProgram(_skinCascadedShadowSpecularMapProgram, _skinCascadedShadowSpecularMapLocations, 1, 2); _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); _skinCascadedShadowNormalSpecularMapProgram.link(); initSkinProgram(_skinCascadedShadowNormalSpecularMapProgram, _skinCascadedShadowNormalSpecularMapLocations, 2, 3); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); _skinShadowProgram.link(); initSkinProgram(_skinShadowProgram, _skinShadowLocations); } } 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); } } 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; 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()) {