Example #1
0
void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
    // simple frustum check
    float boundingRadius = getBillboardSize();
    ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ?
        Application::getInstance()->getShadowViewFrustum() : Application::getInstance()->getViewFrustum();
    if (frustum->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) {
        return;
    }

    glm::vec3 toTarget = cameraPosition - Application::getInstance()->getAvatar()->getPosition();
    float distanceToTarget = glm::length(toTarget);
   
    {
        // glow when moving far away
        const float GLOW_DISTANCE = 20.0f;
        const float GLOW_MAX_LOUDNESS = 2500.0f;
        const float MAX_GLOW = 0.5f;
        
        float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar())
                                            ? 0.0f
                                            : MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
        if (!Menu::getInstance()->isOptionChecked(MenuOption::GlowWhenSpeaking)) {
            GLOW_FROM_AVERAGE_LOUDNESS = 0.0f;
        }
            
        float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE
                      ? 1.0f
                      : GLOW_FROM_AVERAGE_LOUDNESS;

        // render body
        if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
            renderBody(renderMode, glowLevel);
        }
        if (renderMode != SHADOW_RENDER_MODE && 
                Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
            _skeletonModel.updateShapePositions();
            _skeletonModel.renderJointCollisionShapes(0.7f);
        }
        if (renderMode != SHADOW_RENDER_MODE && 
                Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes)) {
            if (shouldRenderHead(cameraPosition, renderMode)) {
                getHead()->getFaceModel().updateShapePositions();
                getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
            }
        }
        if (renderMode != SHADOW_RENDER_MODE && 
                Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes)) {
            if (shouldRenderHead(cameraPosition, renderMode)) {
                getHead()->getFaceModel().updateShapePositions();
                getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f);
                _skeletonModel.updateShapePositions();
                _skeletonModel.renderBoundingCollisionShapes(0.7f);
            }
        }
        // If this is the avatar being looked at, render a little ball above their head
        if (renderMode != SHADOW_RENDER_MODE &&_isLookAtTarget) {
            const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
            const float LOOK_AT_INDICATOR_HEIGHT = 0.60f;
            const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.5f };
            glPushMatrix();
            glColor4fv(LOOK_AT_INDICATOR_COLOR);
            glTranslatef(_position.x, _position.y + (getSkeletonHeight() * LOOK_AT_INDICATOR_HEIGHT), _position.z);
            glutSolidSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15);
            glPopMatrix();
        }

        // quick check before falling into the code below:
        // (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m)
        const float MIN_VOICE_SPHERE_DISTANCE = 12.0f;
        if (distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) {
            // render voice intensity sphere for avatars that are farther away
            const float MAX_SPHERE_ANGLE = 10.0f * RADIANS_PER_DEGREE;
            const float MIN_SPHERE_ANGLE = 1.0f * RADIANS_PER_DEGREE;
            const float MIN_SPHERE_SIZE = 0.01f;
            const float SPHERE_LOUDNESS_SCALING = 0.0005f;
            const float SPHERE_COLOR[] = { 0.5f, 0.8f, 0.8f };
            float height = getSkeletonHeight();
            glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.0f;
            float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
            float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING;
            
            if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
                    (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
                glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE);
                glPushMatrix();
                glTranslatef(_position.x, _position.y, _position.z);
                glScalef(height, height, height);
                glutSolidSphere(sphereRadius, 15, 15);
                glPopMatrix();
            }
        }
    }

    const float DISPLAYNAME_DISTANCE = 10.0f;
    setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
    if (renderMode != NORMAL_RENDER_MODE || (isMyAvatar() &&
            Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
        return;
    }
    renderDisplayName();
    
    if (!_chatMessage.empty()) {
        int width = 0;
        int lastWidth = 0;
        for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) {
            width += (lastWidth = textRenderer(CHAT)->computeWidth(*it));
        }
        glPushMatrix();
        
        glm::vec3 chatPosition = getHead()->getEyePosition() + getBodyUpDirection() * CHAT_MESSAGE_HEIGHT * _scale;
        glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
        glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
        glm::vec3 chatAxis = glm::axis(chatRotation);
        glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
        
        glColor3f(0.0f, 0.8f, 0.0f);
        glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
        glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
        glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
        
        glDisable(GL_LIGHTING);
        glDepthMask(false);
        if (_keyState == NO_KEY_DOWN) {
            textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
            
        } else {
            // rather than using substr and allocating a new string, just replace the last
            // character with a null, then restore it
            int lastIndex = _chatMessage.size() - 1;
            char lastChar = _chatMessage[lastIndex];
            _chatMessage[lastIndex] = '\0';
            textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
            _chatMessage[lastIndex] = lastChar;
            glColor3f(0.0f, 1.0f, 0.0f);
            textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
        }
        glEnable(GL_LIGHTING);
        glDepthMask(true);
        
        glPopMatrix();
    }
}
Example #2
0
void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool postLighting) {
    if (_referential) {
        _referential->update();
    }

    if (postLighting && glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) {
        auto geometryCache = DependencyManager::get<GeometryCache>();

        // render pointing lasers
        glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
        float laserLength = 50.0f;
        glm::vec3 position;
        glm::quat rotation;
        bool havePosition, haveRotation;

        if (_handState & LEFT_HAND_POINTING_FLAG) {

            if (_handState & IS_FINGER_POINTING_FLAG) {
                int leftIndexTip = getJointIndex("LeftHandIndex4");
                int leftIndexTipJoint = getJointIndex("LeftHandIndex3");
                havePosition = _skeletonModel.getJointPositionInWorldFrame(leftIndexTip, position);
                haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftIndexTipJoint, rotation);
            } else {
                int leftHand = _skeletonModel.getLeftHandJointIndex();
                havePosition = _skeletonModel.getJointPositionInWorldFrame(leftHand, position);
                haveRotation = _skeletonModel.getJointRotationInWorldFrame(leftHand, rotation);
            }

            if (havePosition && haveRotation) {
                glPushMatrix();
                {
                    glTranslatef(position.x, position.y, position.z);
                    float angle = glm::degrees(glm::angle(rotation));
                    glm::vec3 axis = glm::axis(rotation);
                    glRotatef(angle, axis.x, axis.y, axis.z);

                    glColor3f(laserColor.x, laserColor.y, laserColor.z);
                    geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f));

                }
                glPopMatrix();
            }
        }

        if (_handState & RIGHT_HAND_POINTING_FLAG) {

            if (_handState & IS_FINGER_POINTING_FLAG) {
                int rightIndexTip = getJointIndex("RightHandIndex4");
                int rightIndexTipJoint = getJointIndex("RightHandIndex3");
                havePosition = _skeletonModel.getJointPositionInWorldFrame(rightIndexTip, position);
                haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightIndexTipJoint, rotation);
            } else {
                int rightHand = _skeletonModel.getRightHandJointIndex();
                havePosition = _skeletonModel.getJointPositionInWorldFrame(rightHand, position);
                haveRotation = _skeletonModel.getJointRotationInWorldFrame(rightHand, rotation);
            }

            if (havePosition && haveRotation) {
                glPushMatrix();
                {
                    glTranslatef(position.x, position.y, position.z);
                    float angle = glm::degrees(glm::angle(rotation));
                    glm::vec3 axis = glm::axis(rotation);
                    glRotatef(angle, axis.x, axis.y, axis.z);
                    glColor3f(laserColor.x, laserColor.y, laserColor.z);
                    geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f));

                }
                glPopMatrix();
            }
        }
    }

    // simple frustum check
    float boundingRadius = getBillboardSize();
    ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ?
                           Application::getInstance()->getShadowViewFrustum() : Application::getInstance()->getViewFrustum();
    if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) {
        return;
    }

    glm::vec3 toTarget = cameraPosition - getPosition();
    float distanceToTarget = glm::length(toTarget);

    {
        // glow when moving far away
        const float GLOW_DISTANCE = 20.0f;
        const float GLOW_MAX_LOUDNESS = 2500.0f;
        const float MAX_GLOW = 0.5f;

        float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar())
                                            ? 0.0f
                                            : MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
        if (!Menu::getInstance()->isOptionChecked(MenuOption::GlowWhenSpeaking)) {
            GLOW_FROM_AVERAGE_LOUDNESS = 0.0f;
        }

        float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE
                          ? 1.0f
                          : GLOW_FROM_AVERAGE_LOUDNESS;

        // render body
        if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
            renderBody(renderMode, postLighting, glowLevel);
        }

        if (!postLighting && renderMode != SHADOW_RENDER_MODE) {
            // add local lights
            const float BASE_LIGHT_DISTANCE = 2.0f;
            const float LIGHT_EXPONENT = 1.0f;
            const float LIGHT_CUTOFF = glm::radians(80.0f);
            float distance = BASE_LIGHT_DISTANCE * _scale;
            glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
            glm::quat orientation = getOrientation();
            foreach (const AvatarManager::LocalLight& light, Application::getInstance()->getAvatarManager().getLocalLights()) {
                glm::vec3 direction = orientation * light.direction;
                DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position - direction * distance,
                        distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
                        LIGHT_EXPONENT, LIGHT_CUTOFF);
            }
        }

        if (postLighting) {
            bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes);
            bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes);
            bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);

            if (renderSkeleton) {
                _skeletonModel.renderJointCollisionShapes(0.7f);
            }

            if (renderHead && shouldRenderHead(cameraPosition, renderMode)) {
                getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
            }
            if (renderBounding && shouldRenderHead(cameraPosition, renderMode)) {
                _skeletonModel.renderBoundingCollisionShapes(0.7f);
            }

            // If this is the avatar being looked at, render a little ball above their head
            if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
                const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
                const float LOOK_AT_INDICATOR_OFFSET = 0.22f;
                const float LOOK_AT_INDICATOR_COLOR[] = { 0.8f, 0.0f, 0.0f, 0.75f };
                glPushMatrix();
                glColor4fv(LOOK_AT_INDICATOR_COLOR);
                if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
                    glTranslatef(_position.x, getDisplayNamePosition().y, _position.z);
                } else {
                    glTranslatef(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
                }
                DependencyManager::get<GeometryCache>()->renderSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15);
                glPopMatrix();
            }
        }

        // quick check before falling into the code below:
        // (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m)
        const float MIN_VOICE_SPHERE_DISTANCE = 12.0f;
        if (postLighting && Menu::getInstance()->isOptionChecked(MenuOption::BlueSpeechSphere)
                && distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) {

            // render voice intensity sphere for avatars that are farther away
            const float MAX_SPHERE_ANGLE = 10.0f * RADIANS_PER_DEGREE;
            const float MIN_SPHERE_ANGLE = 0.5f * RADIANS_PER_DEGREE;
            const float MIN_SPHERE_SIZE = 0.01f;
            const float SPHERE_LOUDNESS_SCALING = 0.0005f;
            const float SPHERE_COLOR[] = { 0.5f, 0.8f, 0.8f };
            float height = getSkeletonHeight();
            glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.0f;
            float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
            float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING;

            if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
                    (angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
                glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE);
                glPushMatrix();
                glTranslatef(_position.x, _position.y, _position.z);
                glScalef(height, height, height);
                DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15);

                glPopMatrix();
            }
        }
    }

    const float DISPLAYNAME_DISTANCE = 20.0f;
    setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
    if (!postLighting || renderMode != NORMAL_RENDER_MODE || (isMyAvatar() &&
            Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
        return;
    }
    renderDisplayName();
}