====== LAB2: Applying Math ======
This lab is to some extent based on Chapter 4 in the textbook, in particular sections 4.2.1 "Points and Cartesian Coordinates" and 4.2.4 "Vector Operations".
===== Discussion =====
Discussion thread for this lab is here: [[http://ruclasses.proboards.com/index.cgi?board=gedespring2013&action=display&thread=113|Lab 2 Discussion Thread]]
===== Goal ======
There are two main parts to this lab. In the first part, which has you thinking about coordinate systems, you create an animation effect that spins an object along a cylindrical path. In the second part, which focuses on vector operations, you use a simple dot product to find which direction you are facing relative to another object.
===== Preparation =====
Make sure you have the following:
- The completed [[Lab1]] project (the optional steps are not necessary)
- ''OgreMath.h'' included in your source file to access the ''Ogre::Math::Cos()'' and ''Ogre::Math::Sin()'' functions
===== Lab Project =====
Follow these steps to complete the lab project:
- **Create a New Project** Create a new empty project called "Lab2" in the same solution as the previous lab project and copy your source files over there (make sure you copy them in the file system and don't just drag them around in the solutions browser, because by default the browser creates a symbolic link to the original file instead of copying). Rename source files as necessary. Unfortunately you'll have to review the configuration properties again for this project (see the instructions for [[Lab1]]), it is quite silly that those can't easily be copied between projects. After this step is done, you should have a new project that compiles and runs (and does the same thing as the previous lab). **Make this new project the ACTIVE PROJECT my right clicking on it in the solutions browser and selecting Set as StartUp Project**
- **Attach an Object to the Ogre** You should create a new movable entity that will be attached to the Ogre entity (from Lab1) wherever it goes. Essentially this new entity, that we will call "The Cube", will exist in the coordinate system of the Ogre model. To do this, you need to create a new ''SceneNode'' as a child of the Ogre's scene node, and attach the Cube to that node. This means that all transformations applied to the Ogre's scene node will be passed down into the Cube's scene node as well. So, do the following:
- Add a member variable to your application class to hold the old Ogre entity (e.g. "_myOgre") and assign the entity to it when you create it in ''createScene''
- Add a member variable to your application class to hold the new Cube entity (e.g. "_myCube").
- In the ''createScene'' method, add the following (after you create the Ogre entity):
_myCube = _sceneManager->createEntity("Cube.mesh");
Ogre::SceneNode* cubenode =_myOgre->getParentSceneNode()->createChildSceneNode();
cubenode->attachObject(_myCube);''
- You need to scale and then translate (position) the new Cube so that you can see it next to the Ogre:''\\
cubenode->scale(0.01, 0.01, 0.01); //Try different values \\
cubenode->setPosition(2.0, 0.0, 0.0); //Notice that this is relative to the Ogre's model origin''
- **Attach a Light to the Cube** You can make it look like the Cube is a source of light that lights up the Ogre and casts a shadow on the ground. Simply attach a point light source to the Cube's scene node:''\\
Ogre::Light* plight = _sceneManager->createLight("Light2");\\
plight->setType(Ogre::Light::LT_POINT);\\
cubenode->attachObject(plight);''
- **Create a Cylindrical Effect Class** This is the meat of the project. You should create a new class called ''CylindricalEffect'' that moves an entity along a cylindric path at a given velocity. The class has the following constructor: \\ ''
CylindricalEffect(Ogre::Entity* entity, Ogre::Vector3 position, Ogre::Vector3 velocity)''\\ You should store each of the arguments as a private member variable in the class. The first argument ''entity'' is any movable entity in the scene that you want to apply the animation effect to. The second argument ''position'' is that entity's position (relative to it's parent) in **Cylindrical Coordinates**, that is, the vector consists of three numbers:
- First number is the **height** of the cylindrical position
- Second number is the **radius** of the cylindrical position
- Third is the **angle** (in radians) of the cylindrical position \\ The third argument ''velocity'' is the velocity of the object along the three axes of the cylindrical coordinates, i.e. along the height axis, along the radius and the angular velocity along the circle.
- **Add a GetCartesian() Method** If the class operates on cylindrical coordinates, you will always want to retrieve the corresponding cartesian coordinates for updating positions in the Ogre3D default cartesian coordinate system. Therefore you should add the following method which should return the class's position member variable converted to cartesian coordinates (you can use the formula given on [[http://www.math.montana.edu/frankw/ccp/multiworld/multipleIVP/cylindrical/learn.htm|these helpful pages]]: \\ ''
Ogre::Vector3 getCartesian() ''
- **Add an Update Method** The heart of this effect is a calculation of a new position for the entity based on linear movement along the three axes of the cylindrical coordinate system (height, radius and angle). Since we are already representing the position cylindrically, all we have to do is to update the position by adding the velocity vector times the time that has passed since the last update: '' \\ void update(float dt) { \\
_position = _position + dt*_velocity; \\
_entity->getParentSceneNode()->setPosition(getCartesian()); \\
} \\ ''
- **Instantiate Effect and Update from FrameListener** Now you have to create an instance of your effect, passing the Cube entity into it's constructor, giving it initial position and velocity values, and finally make sure to call this effect's update function in every frame, e.g. inside the FrameListener's ''frameStarted'' method (note that you'll have to pass a pointer to this effect into the FrameListener constructor so that it knows about it). Don't forget to delete your effect instance in the destructor of your application!
- **OPTIONAL: Activate Only when Facing Ogre** To know if an object is in front of the camera, you can apply a simple dot product test. Take the vector between the camera and the object (use vector subtraction) and call that **V**. Now take the dot product between **V** and the facing vector **F** of the camera (''Ogre::Vector3 F = _Cam->getDirection();''). If this dot product is greater than 0, you know the object is in front of the camera. Finally, why don't you also check to see if the object is relatively close to the camera (you can use the Ogre::Vector3::length() method). Now you can add this to your project such that the special effect only gets updated when these two checks are passed! :-)
- This is optional
===== When You Are Finished =====
Upload your **commented source files** into Lab2 in MySchool (zip them up if more than one). The lab projects will not be graded, but their completion counts towards your participation grade.