The idea

The idea for this camera system came while I was watching The Making of Silent Hill 2, where some debug screens appeared and I was able to notice some "lines". If you've seen it, you'll understand what I'm talking about.

Well. The main idea behind this camera system is to have only one (usually) camera in the scene at the same moment. As the opposite of other 3rd/1st person camera systems, here the camera is "detached" from the whole scene (except from the root node which is crucial for it to work).

This philosophy allows us to obtain very nice effects and soft movement, giving a more friendly way to see the scene.

In general terms, the camera kernel (here called ExtendedCamera) consists of two scene nodes, which will act as the camera "handler" and the camera target. The handler is supposed to be looking always to the target. Moving the target will result in looking around; Moving the "handler", in pivoting, rolling... around the target; moving both at the same time and amount, panning...

This is a simple version of the system. Advanced enhancements would allow shaking effects, cinematic cameras (crane, rail...) through Virtual cameras.

I'll explain how the three different camera modes included in this demo work

3rd person camera - Chasing


We have a main character, who has a main node (the actor), a sight node (the point the character is supposed to be looking at), and a chase camera node (where we think the best chasing camera should be placed). There are other ways to achieve the same effect, but I will use this for simplicity.

What we will do is to use the sight node as the desired position of the camera target, and the chase camera node as the desired position of the camera itself.

Further sight nodes will mean the character will me more offseted from the center of the screen (for instance, if the character is in "investigation" mode in a 3rd person camera game, in the opposite of a "walk around" mode). This helps to keep a broad view of the scene, while keeping track of the character.

3rd person camera - Fixed

This kind of camera can be seen in many adventure games like Resident Evil, Silent Hill, Alone in the dark... The idea is that the target will follow the character sight, but it will remain fixed in a single position.

The way this camera works is similar to the chasing camera.

Variants of this are crane cameras, rail cameras... used in movie sets.

1st person camera

Instead of using the desired chase camera position, we use the character position as the desired position for the camera. For this mode, cameras with a tightness value of 1 work better (and hiding the character model too).

That's the only difference with the 3rd person cameras described above.

Look here for a how to that uses the ExampleFrameListener in Samples/Common/include - First person camera http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Creating+a+simple+first-person+camera+system

Important things to keep in mind

Coordinate system

As the camera is independent to any other object in the scene, we will work with world coordinates.

Camera movement

The camera (and the target) moves in this way. We calculate the difference between the camera position and the desired position. As a result we get a displacement vector that will be applied to the camera so it moves to the desired position.

Tightness

As the movement described above is too rigid for us to be "user-friendly", we need to find a way to make it smoother. So the concept of movement tightness appear. The thightness factor ranges from 0.0 to 1.0, and determines which proportion of the displacement vector will be actually applied.

  • Tightness factor of 1.0 results in rigid movement: Each unit the object moves, the camera will move too
  • Tightness factor of 0.0 results in no-movement: The displacement vector will have a length of 0, so no movement is done
  • Thightness factors outside of 0.0 - 1.0 results in undesired behaviors.

The source code, explained

You can find this source code ported to OgreDotNet by Alberts here or attached to this page:
 Plugin disabled
Plugin attach cannot be executed.

You can find this tutorial and source code ported to Python-Ogre by Zyzle here


First of all, we include a header to use the example framework of OGRE

/* Camera system tutorial by Kencho */
 
#include "ExampleApplication.h"


Next, we define a generic Character class. Here, the Character class is used to define every object that can be tracked and chased by a camera. Of course, in a game or application, this would have many more members ;)

// Generic Character class
 class Character {
 // Attributes ------------------------------------------------------------------------------
     protected:
         SceneNode *mMainNode; // Main character node
         SceneNode *mSightNode; // "Sight" node - The character is supposed to be looking here
         SceneNode *mCameraNode; // Node for the chase camera
         Entity *mEntity; // Character entity
         SceneManager *mSceneMgr;
     public:
 // Methods ---------------------------------------------------------------------------------
     protected:
     public:
         // Updates the character (movement...)
         virtual void update (Real elapsedTime, OIS::Keyboard *input) = 0;
         // The three methods below returns the two camera-related nodes, 
         // and the current position of the character (for the 1st person camera)
         SceneNode *getSightNode () {
             return mSightNode;
         }
         SceneNode *getCameraNode () {
             return mCameraNode;
         }
         Vector3 getWorldPosition () {
             return mMainNode->_getDerivedPosition ();
         }
 };


Next: Our specialization of the Character class for this demo. I think a nice floating Ogre head is a cute character for a demo, so we define a specialization of the Character class, that will handle, it's nodes, model, and a 3D-type movement (turn left/right, advance...)

// Specialization of the Character class - Our dear Ogre :D
 class OgreCharacter : public Character {
 // Attributes ------------------------------------------------------------------------------
     protected:
         String mName;
     public:
 // Methods ---------------------------------------------------------------------------------
     protected:
     public:
         OgreCharacter (String name, SceneManager *sceneMgr) {
             // Setup basic member references
             mName = name;
             mSceneMgr = sceneMgr;
 
             // Setup basic node structure to handle 3rd person cameras
             mMainNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (mName);
             mSightNode = mMainNode->createChildSceneNode (mName + "_sight", Vector3 (0, 0, 100));
             mCameraNode = mMainNode->createChildSceneNode (mName + "_camera", Vector3 (0, 50, -100));
 
             // Give this character a shape :)
             mEntity = mSceneMgr->createEntity (mName, "OgreHead.mesh");
             mMainNode->attachObject (mEntity);
         }
         ~OgreCharacter () {
             mMainNode->detachAllObjects ();
             delete mEntity;
             mMainNode->removeAndDestroyAllChildren ();
             mSceneMgr->destroySceneNode (mName);
         }
 
         void update (Real elapsedTime, OIS::Keyboard *input) {
             // Handle movement
             if (input->isKeyDown (OIS::KC_W)) {
                 mMainNode->translate (mMainNode->getOrientation () * Vector3 (0, 0, 100 * elapsedTime));
             }
             if (input->isKeyDown (OIS::KC_S)) {
                 mMainNode->translate (mMainNode->getOrientation () * Vector3 (0, 0, -50 * elapsedTime));
             }
             if (input->isKeyDown (OIS::KC_A)) {
                 mMainNode->yaw (Radian (2 * elapsedTime));
             }
             if (input->isKeyDown (OIS::KC_D)) {
                 mMainNode->yaw (Radian (-2 * elapsedTime));
             }
         }
 
         // Change visibility - Useful for 1st person view ;)
         void setVisible (bool visible) {
             mMainNode->setVisible (visible);
         }
 };

In order to keep simplicity, I've avoided methods to change the sightness of the character, animating the model...

Now, the interesting part: The ExtendedCamera class. It follows the philosophy I described above. The code is self explanatory, so if you have questions about how this works, you can read again the previous sections :-)

// Our extended camera class
 class ExtendedCamera {
 // Attributes ------------------------------------------------------------------------------
     protected:
         SceneNode *mTargetNode; // The camera target
         SceneNode *mCameraNode; // The camera itself
         Camera *mCamera; // Ogre camera
 
         SceneManager *mSceneMgr;
         String mName;
 
         bool mOwnCamera; // To know if the ogre camera binded has been created outside or inside of this class
 
         Real mTightness; // Determines the movement of the camera - 1 means tight movement, while 0 means no movement
     public:
 // Methods ---------------------------------------------------------------------------------
     protected:
     public:
         ExtendedCamera (String name, SceneManager *sceneMgr, Camera *camera = 0) {
             // Basic member references setup
             mName = name;
             mSceneMgr = sceneMgr;
 
             // Create the camera's node structure
             mCameraNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (mName);
             mTargetNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (mName + "_target");
             mCameraNode->setAutoTracking (true, mTargetNode); // The camera will always look at the camera target
             mCameraNode->setFixedYawAxis (true); // Needed because of auto tracking
 
             // Create our camera if it wasn't passed as a parameter
             if (camera == 0) {
                 mCamera = mSceneMgr->createCamera (mName);
                 mOwnCamera = true;
             }
             else {
                 mCamera = camera;
                                 // just to make sure that mCamera is set to 'origin' (same position as the mCameraNode)
                                 mCamera->setPosition(0.0,0.0,0.0);
                 mOwnCamera = false;
             }
             // ... and attach the Ogre camera to the camera node
             mCameraNode->attachObject (mCamera);
 
             // Default tightness
             mTightness = 0.01f;
         }
         ~ExtendedCamera () {
             mCameraNode->detachAllObjects ();
             if (mOwnCamera)
                 delete mCamera;
             mSceneMgr->destroySceneNode (mName);
             mSceneMgr->destroySceneNode (mName + "_target");
         }
 
         void setTightness (Real tightness) {
             mTightness = tightness;
         }
 
         Real getTightness () {
             return mTightness;
         }
 
         Vector3 getCameraPosition () {
             return mCameraNode->getPosition ();
         }
 
         void instantUpdate (Vector3 cameraPosition, Vector3 targetPosition) {
             mCameraNode->setPosition (cameraPosition);
             mTargetNode->setPosition (targetPosition);
         }
 
         void update (Real elapsedTime, Vector3 cameraPosition, Vector3 targetPosition) {
             // Handle movement
             Vector3 displacement;
 
             displacement = (cameraPosition - mCameraNode->getPosition ()) * mTightness;
             mCameraNode->translate (displacement);
 
             displacement = (targetPosition - mTargetNode->getPosition ()) * mTightness;
             mTargetNode->translate (displacement);
         }
 };

A sample frame listener that will handle the update of the character and the camera, and camera mode changes. Again, self explanatory code and philosophy explained above.

class SampleListener : public ExampleFrameListener
 {
 protected:
     // References to the main character and the camera
     Character *mChar;
     ExtendedCamera *mExCamera;
 
     // Camera mode - Now supports 1st person, 3rd person (chasing) and 3rd person (fixed)
     unsigned int mMode;
 
 public:
     SampleListener(RenderWindow* win, Camera* cam)
     : ExampleFrameListener(win, cam)
     {
         mChar = 0;
         mExCamera = 0;
         mMode = 0;
     }
 
     void setCharacter (Character *character) {
         mChar = character;
     }
 
     void setExtendedCamera (ExtendedCamera *cam) {
         mExCamera = cam;
     }
 
     bool frameStarted(const FrameEvent& evt)
     {
         mKeyboard->capture();
 
         if (mChar) {
             mChar->update (evt.timeSinceLastFrame, mKeyboard);
 
             if (mExCamera) {
                 switch (mMode) {
                     case 0: // 3rd person chase
                         mExCamera->update (evt.timeSinceLastFrame, 
                                             mChar->getCameraNode ()->getWorldPosition (), 
                                             mChar->getSightNode ()->getWorldPosition ());
                         break;
                     case 1: // 3rd person fixed
                         mExCamera->update (evt.timeSinceLastFrame, 
                                             Vector3 (0, 200, 0), 
                                             mChar->getSightNode ()->getWorldPosition ());
                         break;
                     case 2: // 1st person
                         mExCamera->update (evt.timeSinceLastFrame, 
                                             mChar->getWorldPosition (), 
                                             mChar->getSightNode ()->getWorldPosition ());
                         break;
                 }
             }
         }
 
         // 3rd Person - Chase Camera
         if (mKeyboard->isKeyDown (OIS::KC_F1)) {
             mMode = 0;
             if (mChar)
                 static_cast<OgreCharacter *>(mChar)->setVisible (true);
             if (mExCamera) {
                 if (mChar)
                     mExCamera->instantUpdate (mChar->getCameraNode ()->getWorldPosition (), mChar->getSightNode ()->getWorldPosition ());
                 mExCamera->setTightness (0.01f);
             }
          }
         // 3rd Person - Fixed Camera
         if (mKeyboard->isKeyDown (OIS::KC_F2)) {
             mMode = 1;
             if (mChar)
                 static_cast<OgreCharacter *>(mChar)->setVisible (true);
             if (mExCamera) {
                 if (mChar)
                     mExCamera->instantUpdate (Vector3 (0, 200, 0), mChar->getSightNode ()->getWorldPosition ());
                 mExCamera->setTightness (0.01f);
             }
         }
         // 1st Person
         if (mKeyboard->isKeyDown (OIS::KC_F3))  {
             mMode = 2;
             if (mChar)
                 static_cast<OgreCharacter *>(mChar)->setVisible (false);
             if (mExCamera) {
                 if (mChar)
                     mExCamera->instantUpdate (mChar->getWorldPosition (), mChar->getSightNode ()->getWorldPosition ());
                 mExCamera->setTightness (1.0f);
             }
         }
 
         // Exit if we press Esc
         if(mKeyboard->isKeyDown (OIS::KC_ESCAPE))
             return false;
 
         return true;
     }
 };

A sample application. If you have doubts about this, try reading other sections of the wiki :-)

class SampleApplication : public ExampleApplication
 {
 protected:
 public:
     SampleApplication()
     {
     }
     ~SampleApplication()
     {
     }
 
 protected:
     // Just override the mandatory create scene method
     void createScene(void)
     {
         // Set ambient light
         mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
 
         // LIGHTS!!
         // Create a point light
         Light* l = mSceneMgr->createLight("MainLight");
         // Accept default settings: point light, white diffuse, just set position
         // NB I could attach the light to a SceneNode if I wanted it to move automatically with
         //  other objects, but I don't
         l->setType(Light::LT_DIRECTIONAL);
         l->setDirection(-0.5, -0.5, 0);
 
         // CAMERA!!
         mCamera->setPosition (0, 0, 0);    // Required or else the camera will have an offset
 
         // ACTION!!!
         // Fill the scene with some razors
         SceneNode *razorNode;
         Entity *razorEntity;
         for (unsigned int i = 0; i < 30; ++i) {
             razorNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (StringConverter::toString (i), Vector3 (Math::RangeRandom (-1000, 1000), 0, Math::RangeRandom (-1000, 1000)));
             razorEntity = mSceneMgr->createEntity (StringConverter::toString (i), "razor.mesh");
             razorNode->attachObject (razorEntity);
         }
 
         // Main character
         OgreCharacter *ogre = new OgreCharacter ("Ogre 1", mSceneMgr);
         ExtendedCamera *exCamera = new ExtendedCamera ("Extended Camera", mSceneMgr, mCamera);
 
         // Frame listener to manage both character and camera updating and different camera modes
         // Need to create it here as we want to change some parameters here, thus avoiding defining 
         // ogre and exCamera as member variables
         mFrameListener = new SampleListener (mWindow, mCamera);
         static_cast<SampleListener *>(mFrameListener)->setCharacter (ogre);
         static_cast<SampleListener *>(mFrameListener)->setExtendedCamera (exCamera);
     }
     void destroyScene(void)
     {
     }
     void createFrameListener(void)
     {
         // This is where we instantiate our own frame listener
 //        mFrameListener= new SampleListener(mWindow, mCamera);
         mRoot->addFrameListener(mFrameListener);
     }
 };

Note that in the method createFrameListener(), the frame listener won't be constructed as we did in the createScene() method, so there won't be two frame listeners. This is important as the second (and used) one, if we would create it in createFrameListener(), wouldn't be configured, and thus would crash the application.

To make it able to run

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
 #define WIN32_LEAN_AND_MEAN
 #include "windows.h"
 
 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
 #else
 int main(int argc, char **argv)
 #endif
 {
    // Create application object
    SampleApplication app;
 
    try {
        app.go();
    } catch( Exception& e ) {
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 
        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK |      MB_ICONERROR | MB_TASKMODAL);
 #else
        fprintf(stderr, "An exception has occured: %s\n",
                e.getFullDescription().c_str());
 #endif
    }
 
    return 0;
 }

Closing words

Hope you find this useful. I'll be updating this later, fixing some explanations and methods. Thanks for reading.
Kencho


Alias: 3rd_person_camera_system_tutorial

<HR>
Creative Commons Copyright -- Some rights reserved.


THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.

1. Definitions

  • "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
  • "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
  • "Licensor" means the individual or entity that offers the Work under the terms of this License.
  • "Original Author" means the individual or entity who created the Work.
  • "Work" means the copyrightable work of authorship offered under the terms of this License.
  • "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
  • "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.

2. Fair Use Rights

Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.

3. License Grant

Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:

  • to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
  • to create and reproduce Derivative Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
  • to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
  • For the avoidance of doubt, where the work is a musical composition:
    • Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
    • Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
    • Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).


The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.

4. Restrictions

The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:

  • You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
  • You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
  • If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability.

EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. Termination

  • This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
  • Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.

8. Miscellaneous

  • Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
  • Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
  • If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
  • No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
  • This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.