Пример #1
0
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
// this current code path only addresses that in this setup case... not the changing/moving case
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
    if (!_model && renderArgs) {
        // TODO: this getModel() appears to be about 3% of model render time. We should optimize
        PerformanceTimer perfTimer("getModel");
        EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
        getModel(renderer);
    }
    if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) {
        _model->setScaleToFit(true, getDimensions());
        _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
        _model->setRotation(getRotation());
        _model->setTranslation(getPosition());
    
        // make sure to simulate so everything gets set up correctly for rendering
        {
            PerformanceTimer perfTimer("_model->simulate");
            _model->simulate(0.0f);
        }
        _needsInitialSimulation = false;

        _model->renderSetup(renderArgs);
    }
    bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
    return ready; 
}
Пример #2
0
bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                     bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 
                     void** intersectedObject, bool precisionPicking) const {
    // determine the ray in the frame of the entity transformed from a unit sphere
    glm::mat4 translation = glm::translate(getPosition());
    glm::mat4 rotation = glm::mat4_cast(getRotation());
    glm::mat4 scale = glm::scale(getDimensions());
    glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint());
    glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration;
    glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
    glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
    glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));

    float localDistance;
    // NOTE: unit sphere has center of 0,0,0 and radius of 0.5
    if (findRaySphereIntersection(entityFrameOrigin, entityFrameDirection, glm::vec3(0.0f), 0.5f, localDistance)) {
        // determine where on the unit sphere the hit point occured
        glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
        // then translate back to work coordinates
        glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
        distance = glm::distance(origin,hitAt);
        return true;
    }
    return false;                
}
Пример #3
0
void RenderableZoneEntityItem::initialSimulation() {
    _model->setScaleToFit(true, getDimensions());
    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
    _model->setRotation(getRotation());
    _model->setTranslation(getPosition());
    _model->simulate(0.0f);
    _needsInitialSimulation = false;
}
void RenderableModelEntityItem::doInitialModelSimulation() {
    // The machinery for updateModelBounds will give existing models the opportunity to fix their
    // translation/rotation/scale/registration.  The first two are straightforward, but the latter two have guards to
    // make sure they don't happen after they've already been set.  Here we reset those guards. This doesn't cause the
    // entity values to change -- it just allows the model to match once it comes in.
    _model->setScaleToFit(false, getDimensions());
    _model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());

    // now recalculate the bounds and registration
    _model->setScaleToFit(true, getDimensions());
    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
    _model->setRotation(getRotation());
    _model->setTranslation(getPosition());
    {
        PerformanceTimer perfTimer("_model->simulate");
        _model->simulate(0.0f);
    }
    _needsInitialSimulation = false;
}
Пример #5
0
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                     bool& keepSearching, OctreeElementPointer& element, float& distance, 
                     BoxFace& face, glm::vec3& surfaceNormal,
                     void** intersectedObject, bool precisionPicking) const {
    glm::vec3 dimensions = getDimensions();
    glm::vec2 xyDimensions(dimensions.x, dimensions.y);
    glm::quat rotation = getRotation();
    glm::vec3 position = getPosition() + rotation * 
            (dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
    // FIXME - should set face and surfaceNormal
    return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
}
Пример #6
0
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                     OctreeElementPointer& element, float& distance,
                     BoxFace& face, glm::vec3& surfaceNormal,
                     QVariantMap& extraInfo, bool precisionPicking) const {
    glm::vec3 dimensions = getScaledDimensions();
    glm::vec2 xyDimensions(dimensions.x, dimensions.y);
    glm::quat rotation = getWorldOrientation();
    glm::vec3 position = getWorldPosition() + rotation *
            (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));

    // FIXME - should set face and surfaceNormal
    return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
}
Пример #7
0
void RenderableZoneEntityItem::updateGeometry() {
    if (_model && !_model->isActive() && hasCompoundShapeURL()) {
        // Since we have a delayload, we need to update the geometry if it has been downloaded
        _model->setURL(getCompoundShapeURL());
    }
    if (_model && _model->isActive() && _needsInitialSimulation) {
        _model->setScaleToFit(true, getDimensions());
        _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
        _model->setRotation(getRotation());
        _model->setTranslation(getPosition());
        _model->simulate(0.0f);
        _needsInitialSimulation = false;
    }
}
void RenderableModelEntityItem::updateModelBounds() {
    if (!hasModel() || !_model) {
        return;
    }
    bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
    glm::vec3 dimensions = getDimensions();
    if ((movingOrAnimating ||
         _needsInitialSimulation ||
         _needsJointSimulation ||
         _model->getTranslation() != getPosition() ||
         _model->getScaleToFitDimensions() != dimensions ||
         _model->getRotation() != getRotation() ||
         _model->getRegistrationPoint() != getRegistrationPoint())
        && _model->isActive() && _dimensionsInitialized) {
        doInitialModelSimulation();
        _needsJointSimulation = false;
    }
}
Пример #9
0
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                     bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 
                     void** intersectedObject, bool precisionPicking) const {
                     
    RayIntersectionInfo rayInfo;
    rayInfo._rayStart = origin;
    rayInfo._rayDirection = direction;
    rayInfo._rayLength = std::numeric_limits<float>::max();

    PlaneShape plane;

    const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
    glm::vec3 normal = getRotation() * UNROTATED_NORMAL;
    plane.setNormal(normal);
    plane.setPoint(getPosition()); // the position is definitely a point on our plane

    bool intersects = plane.findRayIntersection(rayInfo);

    if (intersects) {
        glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance);
        // now we know the point the ray hit our plane

        glm::mat4 rotation = glm::mat4_cast(getRotation());
        glm::mat4 translation = glm::translate(getPosition());
        glm::mat4 entityToWorldMatrix = translation * rotation;
        glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);

        glm::vec3 dimensions = getDimensions();
        glm::vec3 registrationPoint = getRegistrationPoint();
        glm::vec3 corner = -(dimensions * registrationPoint);
        AABox entityFrameBox(corner, dimensions);

        glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f));
        
        intersects = entityFrameBox.contains(entityFrameHitAt);
    }

    if (intersects) {
        distance = rayInfo._hitDistance;
    }
    return intersects;
}
Пример #10
0
bool ZoneEntityItem::contains(const glm::vec3& point) const {
    GeometryResource::Pointer resource = _shapeResource;
    if (_shapeType == SHAPE_TYPE_COMPOUND && resource) {
        if (resource->isLoaded()) {
            const HFMModel& hfmModel = resource->getHFMModel();

            Extents meshExtents = hfmModel.getMeshExtents();
            glm::vec3 meshExtentsDiagonal = meshExtents.maximum - meshExtents.minimum;
            glm::vec3 offset = -meshExtents.minimum- (meshExtentsDiagonal * getRegistrationPoint());
            glm::vec3 scale(getScaledDimensions() / meshExtentsDiagonal);

            glm::mat4 hfmToEntityMatrix = glm::scale(scale) * glm::translate(offset);
            glm::mat4 entityToWorldMatrix = getTransform().getMatrix();
            glm::mat4 worldToHFMMatrix = glm::inverse(entityToWorldMatrix * hfmToEntityMatrix);

            return hfmModel.convexHullContains(glm::vec3(worldToHFMMatrix * glm::vec4(point, 1.0f)));
        }
    }
    return EntityItem::contains(point);
}
Пример #11
0
glm::vec3 RayPick::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) {
    auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
    return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint());
}
Пример #12
0
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
    auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
    return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);
}
Пример #13
0
OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, 
                                            EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const {
                                            
    // ALL this fits...
    //    object ID [16 bytes]
    //    ByteCountCoded(type code) [~1 byte]
    //    last edited [8 bytes]
    //    ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
    //    PropertyFlags<>( everything ) [1-2 bytes]
    // ~27-35 bytes...
    
    OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best

    // encode our ID as a byte count coded byte stream
    QByteArray encodedID = getID().toRfc4122();

    // encode our type as a byte count coded byte stream
    ByteCountCoded<quint32> typeCoder = getType();
    QByteArray encodedType = typeCoder;

    quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
    ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
    QByteArray encodedUpdateDelta = updateDeltaCoder;
    EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
    EntityPropertyFlags requestedProperties = getEntityProperties(params);
    EntityPropertyFlags propertiesDidntFit = requestedProperties;

    // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
    // then our entityTreeElementExtraEncodeData should include data about which properties we need to append.
    if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) {
        requestedProperties = entityTreeElementExtraEncodeData->entities.value(getEntityItemID());
    }

    LevelDetails entityLevel = packetData->startLevel();

    quint64 lastEdited = getLastEdited();

    const bool wantDebug = false;
    if (wantDebug) {
        float editedAgo = getEditedAgo();
        QString agoAsString = formatSecondsElapsed(editedAgo);
        qDebug() << "Writing entity " << getEntityItemID() << " to buffer, lastEdited =" << lastEdited 
                        << " ago=" << editedAgo << "seconds - " << agoAsString;
    }

    bool successIDFits = false;
    bool successTypeFits = false;
    bool successCreatedFits = false;
    bool successLastEditedFits = false;
    bool successLastUpdatedFits = false;
    bool successPropertyFlagsFits = false;
    int propertyFlagsOffset = 0;
    int oldPropertyFlagsLength = 0;
    QByteArray encodedPropertyFlags;
    int propertyCount = 0;

    successIDFits = packetData->appendValue(encodedID);
    if (successIDFits) {
        successTypeFits = packetData->appendValue(encodedType);
    }
    if (successTypeFits) {
        successCreatedFits = packetData->appendValue(_created);
    }
    if (successCreatedFits) {
        successLastEditedFits = packetData->appendValue(lastEdited);
    }
    if (successLastEditedFits) {
        successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
    }
    
    if (successLastUpdatedFits) {
        propertyFlagsOffset = packetData->getUncompressedByteOffset();
        encodedPropertyFlags = propertyFlags;
        oldPropertyFlagsLength = encodedPropertyFlags.length();
        successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
    }

    bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits 
                              && successLastUpdatedFits && successPropertyFlagsFits;

    int startOfEntityItemData = packetData->getUncompressedByteOffset();

    if (headerFits) {
        bool successPropertyFits;

        propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item

        // These items would go here once supported....
        //      PROP_PAGED_PROPERTY,
        //      PROP_CUSTOM_PROPERTIES_INCLUDED,

        APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition());
        APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete

        if (wantDebug) {
            qDebug() << "    APPEND_ENTITY_PROPERTY() PROP_DIMENSIONS:" << getDimensions();
        }

        APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation());
        APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, getMass());
        APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity());
        APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, getGravity());
        APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping());
        APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime());
        APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript());
        APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint());
        APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity());
        APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping());
        APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible());
        APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions());
        APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove());

        appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
                                requestedProperties,
                                propertyFlags,
                                propertiesDidntFit,
                                propertyCount,
                                appendState);
    }

    if (propertyCount > 0) {
        int endOfEntityItemData = packetData->getUncompressedByteOffset();
        encodedPropertyFlags = propertyFlags;
        int newPropertyFlagsLength = encodedPropertyFlags.length();
        packetData->updatePriorBytes(propertyFlagsOffset, 
                (const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
        
        // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
        if (newPropertyFlagsLength < oldPropertyFlagsLength) {
            int oldSize = packetData->getUncompressedSize();
            const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
            int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
            int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
            packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
            int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
            packetData->setUncompressedSize(newSize);

        } else {
            assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
        }
       
        packetData->endLevel(entityLevel);
    } else {
        packetData->discardLevel(entityLevel);
        appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
    }
    
    // If any part of the model items didn't fit, then the element is considered partial
    if (appendState != OctreeElement::COMPLETED) {
        // add this item into our list for the next appendElementData() pass
        entityTreeElementExtraEncodeData->entities.insert(getEntityItemID(), propertiesDidntFit);
    }

    return appendState;
}
Пример #14
0
bool WebEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
                                                     OctreeElementPointer& element, float& parabolicDistance,
                                                     BoxFace& face, glm::vec3& surfaceNormal,
                                                     QVariantMap& extraInfo, bool precisionPicking) const {
    glm::vec3 dimensions = getScaledDimensions();
    glm::vec2 xyDimensions(dimensions.x, dimensions.y);
    glm::quat rotation = getWorldOrientation();
    glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));

    glm::quat inverseRot = glm::inverse(rotation);
    glm::vec3 localOrigin = inverseRot * (origin - position);
    glm::vec3 localVelocity = inverseRot * velocity;
    glm::vec3 localAcceleration = inverseRot * acceleration;

    if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
        float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
        glm::vec3 forward = rotation * Vectors::FRONT;
        if (localIntersectionVelocityZ > 0.0f) {
            face = MIN_Z_FACE;
            surfaceNormal = forward;
        } else {
            face = MAX_Z_FACE;
            surfaceNormal = -forward;
        }
        return true;
    } else {
        return false;
    }
}
Пример #15
0
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                                                OctreeElementPointer& element, float& distance,
                                                BoxFace& face, glm::vec3& surfaceNormal,
                                                QVariantMap& extraInfo, bool precisionPicking) const {
    glm::vec3 dimensions = getScaledDimensions();
    glm::vec2 xyDimensions(dimensions.x, dimensions.y);
    glm::quat rotation = getWorldOrientation();
    glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
    rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());

    if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
        glm::vec3 forward = rotation * Vectors::FRONT;
        if (glm::dot(forward, direction) > 0.0f) {
            face = MAX_Z_FACE;
            surfaceNormal = -forward;
        } else {
            face = MIN_Z_FACE;
            surfaceNormal = forward;
        }
        return true;
    } else {
        return false;
    }
}
Пример #16
0
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles
// the per frame simulation/update that might be required if the models properties changed.
void RenderableModelEntityItem::render(RenderArgs* args) {
    PerformanceTimer perfTimer("RMEIrender");
    assert(getType() == EntityTypes::Model);

    if (hasModel()) {
        if (_model) {
            if (getModelURL() != _model->getURL().toString()) {
                qDebug() << "Updating model URL: " << getModelURL();
                _model->setURL(getModelURL());
            }

            render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();

            // check to see if when we added our models to the scene they were ready, if they were not ready, then
            // fix them up in the scene
            if (_model->needsFixupInScene()) {
                render::PendingChanges pendingChanges;

                _model->removeFromScene(scene, pendingChanges);

                render::Item::Status::Getters statusGetters;
                makeEntityItemStatusGetters(this, statusGetters);
                _model->addToScene(scene, pendingChanges, statusGetters);

                scene->enqueuePendingChanges(pendingChanges);
            }

            // FIXME: this seems like it could be optimized if we tracked our last known visible state in
            //        the renderable item. As it stands now the model checks it's visible/invisible state
            //        so most of the time we don't do anything in this function.
            _model->setVisibleInScene(getVisible(), scene);
        }


        remapTextures();
        {
            // float alpha = getLocalRenderAlpha();

            if (!_model || _needsModelReload) {
                // TODO: this getModel() appears to be about 3% of model render time. We should optimize
                PerformanceTimer perfTimer("getModel");
                EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
                getModel(renderer);
            }
            
            if (_model) {
                // handle animations..
                if (hasAnimation()) {
                    if (!jointsMapped()) {
                        QStringList modelJointNames = _model->getJointNames();
                        mapJoints(modelJointNames);
                    }

                    if (jointsMapped()) {
                        bool newFrame;
                        QVector<glm::quat> frameDataRotations;
                        QVector<glm::vec3> frameDataTranslations;
                        getAnimationFrame(newFrame, frameDataRotations, frameDataTranslations);
                        assert(frameDataRotations.size() == frameDataTranslations.size());
                        if (newFrame) {
                            for (int i = 0; i < frameDataRotations.size(); i++) {
                                _model->setJointState(i, true, frameDataRotations[i], frameDataTranslations[i], 1.0f);
                            }
                        }
                    }
                }

                bool movingOrAnimating = isMoving() || isAnimatingSomething();
                if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive() && _dimensionsInitialized) {
                    _model->setScaleToFit(true, getDimensions());
                    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
                    _model->setRotation(getRotation());
                    _model->setTranslation(getPosition());
                    
                    // make sure to simulate so everything gets set up correctly for rendering
                    {
                        PerformanceTimer perfTimer("_model->simulate");
                        _model->simulate(0.0f);
                    }
                    
                    _needsInitialSimulation = false;
                }
            }
        }
    } else {
        glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
        RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor);
    }

    RenderableDebugableEntityItem::render(this, args);
}
Пример #17
0
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles
// the per frame simulation/update that might be required if the models properties changed.
void RenderableModelEntityItem::render(RenderArgs* args) {
    PerformanceTimer perfTimer("RMEIrender");
    assert(getType() == EntityTypes::Model);

    if (hasModel()) {
        if (_model) {
            // check if the URL has changed
            auto& currentURL = getParsedModelURL();
            if (currentURL != _model->getURL()) {
                qCDebug(entitiesrenderer).noquote() << "Updating model URL: " << currentURL.toDisplayString();
                _model->setURL(currentURL);
            }

            render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();

            // check to see if when we added our models to the scene they were ready, if they were not ready, then
            // fix them up in the scene
            bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
            if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
                _showCollisionHull = shouldShowCollisionHull;
                render::PendingChanges pendingChanges;

                _model->removeFromScene(scene, pendingChanges);

                render::Item::Status::Getters statusGetters;
                makeEntityItemStatusGetters(getThisPointer(), statusGetters);
                _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);

                scene->enqueuePendingChanges(pendingChanges);
            }

            // FIXME: this seems like it could be optimized if we tracked our last known visible state in
            //        the renderable item. As it stands now the model checks it's visible/invisible state
            //        so most of the time we don't do anything in this function.
            _model->setVisibleInScene(getVisible(), scene);
        }


        remapTextures();
        {
            // float alpha = getLocalRenderAlpha();

            if (!_model || _needsModelReload) {
                // TODO: this getModel() appears to be about 3% of model render time. We should optimize
                PerformanceTimer perfTimer("getModel");
                EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
                getModel(renderer);
            }

            if (_model) {
                if (hasAnimation()) {
                    if (!jointsMapped()) {
                        QStringList modelJointNames = _model->getJointNames();
                        mapJoints(modelJointNames);
                    }
                }

                _jointDataLock.withWriteLock([&] {
                    getAnimationFrame();

                    // relay any inbound joint changes from scripts/animation/network to the model/rig
                    for (int index = 0; index < _absoluteJointRotationsInObjectFrame.size(); index++) {
                        if (_absoluteJointRotationsInObjectFrameDirty[index]) {
                            glm::quat rotation = _absoluteJointRotationsInObjectFrame[index];
                            _model->setJointRotation(index, true, rotation, 1.0f);
                            _absoluteJointRotationsInObjectFrameDirty[index] = false;
                        }
                    }
                    for (int index = 0; index < _absoluteJointTranslationsInObjectFrame.size(); index++) {
                        if (_absoluteJointTranslationsInObjectFrameDirty[index]) {
                            glm::vec3 translation = _absoluteJointTranslationsInObjectFrame[index];
                            _model->setJointTranslation(index, true, translation, 1.0f);
                            _absoluteJointTranslationsInObjectFrameDirty[index] = false;
                        }
                    }
                });

                bool movingOrAnimating = isMoving() || isAnimatingSomething();
                if ((movingOrAnimating ||
                     _needsInitialSimulation ||
                     _model->getTranslation() != getPosition() ||
                     _model->getRotation() != getRotation() ||
                     _model->getRegistrationPoint() != getRegistrationPoint())
                    && _model->isActive() && _dimensionsInitialized) {
                    _model->setScaleToFit(true, getDimensions());
                    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
                    _model->setRotation(getRotation());
                    _model->setTranslation(getPosition());

                    // make sure to simulate so everything gets set up correctly for rendering
                    {
                        PerformanceTimer perfTimer("_model->simulate");
                        _model->simulate(0.0f);
                    }

                    _needsInitialSimulation = false;
                }
            }
        }
    } else {
        static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
        gpu::Batch& batch = *args->_batch;
        bool success;
        auto shapeTransform = getTransformToCenter(success);
        if (success) {
            batch.setModelTransform(Transform()); // we want to include the scale as well
            DependencyManager::get<GeometryCache>()->renderWireCubeInstance(batch, shapeTransform, greenColor);
        }
    }
}
Пример #18
0
void RenderableModelEntityItem::render(RenderArgs* args) {
    PerformanceTimer perfTimer("RMEIrender");
    assert(getType() == EntityTypes::Model);
    
    bool drawAsModel = hasModel();

    glm::vec3 position = getPosition() * (float)TREE_SCALE;
    float size = getSize() * (float)TREE_SCALE;
    glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE;
    
    if (drawAsModel) {
        glPushMatrix();
        {
            float alpha = getLocalRenderAlpha();

            if (!_model || _needsModelReload) {
                // TODO: this getModel() appears to be about 3% of model render time. We should optimize
                PerformanceTimer perfTimer("getModel");
                EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
                getModel(renderer);
            }
            
            if (_model) {
                // handle animations..
                if (hasAnimation()) {
                    if (!jointsMapped()) {
                        QStringList modelJointNames = _model->getJointNames();
                        mapJoints(modelJointNames);
                    }

                    if (jointsMapped()) {
                        QVector<glm::quat> frameData = getAnimationFrame();
                        for (int i = 0; i < frameData.size(); i++) {
                            _model->setJointState(i, true, frameData[i]);
                        }
                    }
                }

                glm::quat rotation = getRotation();
                if (needsSimulation() && _model->isActive()) {
                    _model->setScaleToFit(true, dimensions);
                    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
                    _model->setRotation(rotation);
                    _model->setTranslation(position);
                    
                    // make sure to simulate so everything gets set up correctly for rendering
                    {
                        PerformanceTimer perfTimer("_model->simulate");
                        _model->simulate(0.0f);
                    }
                    _needsInitialSimulation = false;
                }

                // TODO: should we allow entityItems to have alpha on their models?
                Model::RenderMode modelRenderMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE 
                                                        ? Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
        
                if (_model->isActive()) {
                    // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render
                    // is significantly more expensive. Is there a way to call this that doesn't cost us as much? 
                    PerformanceTimer perfTimer("model->render");
                    _model->render(alpha, modelRenderMode, args);
                } else {
                    // if we couldn't get a model, then just draw a cube
                    glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
                    glPushMatrix();
                        glTranslatef(position.x, position.y, position.z);
                        Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
                    glPopMatrix();
                }
            } else {
                // if we couldn't get a model, then just draw a cube
                glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
                glPushMatrix();
                    glTranslatef(position.x, position.y, position.z);
                    Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
                glPopMatrix();
            }
        }
        glPopMatrix();
    } else {
        glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
        glPushMatrix();
        glTranslatef(position.x, position.y, position.z);
        Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
        glPopMatrix();
    }
}
void RenderableModelEntityItem::render(RenderArgs* args) {
    PerformanceTimer perfTimer("RMEIrender");
    assert(getType() == EntityTypes::Model);
    
    bool drawAsModel = hasModel();

    glm::vec3 position = getPosition();
    glm::vec3 dimensions = getDimensions();
    float size = glm::length(dimensions);

    bool highlightSimulationOwnership = false;
    if (args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP) {
        auto nodeList = DependencyManager::get<NodeList>();
        const QUuid& myNodeID = nodeList->getSessionUUID();
        highlightSimulationOwnership = (getSimulatorID() == myNodeID);
    }

    if (drawAsModel && !highlightSimulationOwnership) {
        remapTextures();
        glPushMatrix();
        {
            float alpha = getLocalRenderAlpha();

            if (!_model || _needsModelReload) {
                // TODO: this getModel() appears to be about 3% of model render time. We should optimize
                PerformanceTimer perfTimer("getModel");
                EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
                getModel(renderer);
            }
            
            if (_model) {
                // handle animations..
                if (hasAnimation()) {
                    if (!jointsMapped()) {
                        QStringList modelJointNames = _model->getJointNames();
                        mapJoints(modelJointNames);
                    }

                    if (jointsMapped()) {
                        QVector<glm::quat> frameData = getAnimationFrame();
                        for (int i = 0; i < frameData.size(); i++) {
                            _model->setJointState(i, true, frameData[i]);
                        }
                    }
                }

                glm::quat rotation = getRotation();
                bool movingOrAnimating = isMoving() || isAnimatingSomething();
                if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive()) {
                    _model->setScaleToFit(true, dimensions);
                    _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
                    _model->setRotation(rotation);
                    _model->setTranslation(position);
                    
                    // make sure to simulate so everything gets set up correctly for rendering
                    {
                        PerformanceTimer perfTimer("_model->simulate");
                        _model->simulate(0.0f);
                    }
                    _needsInitialSimulation = false;
                }

                if (_model->isActive()) {
                    // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render
                    // is significantly more expensive. Is there a way to call this that doesn't cost us as much? 
                    PerformanceTimer perfTimer("model->render");
                    // filter out if not needed to render
                    if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) {
                        if (movingOrAnimating) {
                            _model->renderInScene(alpha, args);
                        }
                    } else {
                        _model->renderInScene(alpha, args);
                    }
                } else {
                    // if we couldn't get a model, then just draw a cube
                    glm::vec4 color(getColor()[RED_INDEX]/255, getColor()[GREEN_INDEX]/255, getColor()[BLUE_INDEX]/255, 1.0f);
                    glPushMatrix();
                        glTranslatef(position.x, position.y, position.z);
                        DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size, color);
                    glPopMatrix();
                }
            } else {
                // if we couldn't get a model, then just draw a cube
                glm::vec4 color(getColor()[RED_INDEX]/255, getColor()[GREEN_INDEX]/255, getColor()[BLUE_INDEX]/255, 1.0f);
                glPushMatrix();
                    glTranslatef(position.x, position.y, position.z);
                    DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size, color);
                glPopMatrix();
            }
        }
        glPopMatrix();
    } else {
        glm::vec4 color(getColor()[RED_INDEX]/255, getColor()[GREEN_INDEX]/255, getColor()[BLUE_INDEX]/255, 1.0f);
        glPushMatrix();
        glTranslatef(position.x, position.y, position.z);
        DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size, color);
        glPopMatrix();
    }
}