Matthew Mariano Matthew Blevins Virtual Reality Our project is at it simplest, just a skiing simulator. We wanted to make something that was fun to use and to make. But deep down inside, the project was about reworking how navigation works in a VR environment, and applying as many different techniques as we could. You can navigate the virtual terrain using a mouse and a 5DT Glove. The mouse controlled where you are looking, while the glove control your vector velocity. It was a system that seemed awkward at first, but after a few runs, you begin to adapt to it. We keep the virtual objects that could cause collision low, to not break up the skiing too much, but just enough to give the user something to avoid. The “Yeti” in the secret passage start as a joke, in reference to the original SkyFree game, but grew as a way to display more techniques such as LOD and ambient Sound. Given time, code like randomly generated trees or endless slopes can be implemented without major changes in the original simulator. Matthew Maraino My part in this project was primarily shaping the terrain. I use 3DExcusion to create a 15 by 34 area. I then pick a set maximum and minimum height, originally 7 and 0 but later decreased the minimum to allow for a longer slope. I then computed a constant slope for my terrain from these values, which is -.28, a slight downward slope. I then went row by row, and decrement from the maximum height according to the slope to find the new overall height for each row. I increase the height of the points around the edge to at least 2 points higher allowing for a define border, while apply the same idea to create a section separate from the main slope where I later added the “Yeti”. I then random pick heights to rise, increasing the surrounding points accordingly so to create a realistic raise or, in some cases, dip in the mountain. I mapped a texture I found doing an online image search, that I found drastically improve the quality of the terrain. It gave it a snowy but rocky look, when a DirectionalLight was applied to highlight the scene. Through out the project, I came back to the terrain and played with the heights to try and improve it. While searching for the ground texture, I came across a suitable texture for the trees. It was a .jpg, so I had to use Photoshop’s background erase tool, to capture just the tree, and saved it as a .png to allow for the transparency. Since I plan to use the tree multiple times in my project, I felt it was best to Inline it. Also I created a transparent cylinder, except for the bottom which I used to help orientate with the surface, to act as a bounding box for collision detecting. I created a separate tree to be inline that did not have this bounding block to cover the path towards the “Yeti” with out blocking the user out. I mapped the trees with the bounding box at different location along the slope, trying hard to have the trees fully rooted into the ground, but not buried by the snow. Once that was done, I then added invisible boxes on the right, left, and back slope, to prevent the user from falling off the terrain. I also add one of these boxes to the slope that separates the “Yeti’s” path from the main path, to make it hard to get in. All these boxes and trees then all became children in a Collision Node. When the user avatar comes in contact with any of these children it sends a signal to the MoveAvatar Script where it set the collisiontime. Using the past and present location, along with the velocity in that direction, the set_collisiontime function calculates the direction of collision and bounces the user back .3 points according to the direction it came from. Also the function sets the velocity at zero. The trees and “Yeti” are also children of a different Collision node that plays an AudioClip. The AudioClip is in a Sound node which is bound to the Viewpoint, which allows the noise played at a collision to be the same no matter what you hit. Sound and Audio Clip nodes are also used to create a sense of 3d sound, that plays a song louder, the closer you get to its location. The song I chose was “The Yeti” by Clutch, and to lower the file size, I sampled the song at only 8 bits with a sample rate of 1000, this was I reduce a song file of 15mb to only 750kb. The location was approximately where the “Yeti” was standing. There were actually two different “Yetis”, one low quality built of just some simple cylinders and spheres, another high, which was the low quality model plus shoulders, eyes, nose, eyebrows, and hands with independent digits ( The hand was original created for the glove exercise in Lab 4). They both were given a white fur texture. The program used the LOD node, by switch between the two models at a distance of 14 points, to help keep the frame rate high. My final task, which proved to be the hardest, was configuring the 5DT Glove, so that we can translate the finger movement to onscreen movements. Basing the code off Lab 4, I wrote a Proto Script that reads in the raw_values of the four fingers, and translate it into a three dimensional array of velocity vectors. I configure it so that the index and the ring finger controls the left and right movement and the middle and ring controls the forward and back. I configure it so that a raw_value greater then 180 was need to activate the motion. I then set the maximum amount of velocity for each finger making sure it wasn’t too quick, and that the breaking velocity was less then forward so that you couldn’t come to a complete stop. I then had them tally up in the MoveAvatar node, making sure they do not exceed a certain value, before finally adding the corresponding glove velocity vector to the real velocity vector. After this my job was a debugger, helping Matt figure out his various coding errors. Matthew Blevins My role in the Ski Free 3D project was most of the scripting. This included creation of the heightArray with a C++ program the development of the movement system. The movement system that I developed works in a straightforward manner. The user can specify whatever X and Z velocities that they want using any input device that they want. The program has a variable to store the current position. The next position is then calculated by adding velocity * time to the current position. Then the program draws a line between the current position and the next position and sets the y velocity so that the avatar stays along that line. The next time the timer function is called the positions are incremented, velocities changed based on acceleration due to gravity and glove input, and the whole process is repeated. I also developed the code to have the viewing angle change based on mouse movements. To do this I inserted an invisible box in front of the camera and routed a touch sensor's hitpoint_changed field to a script node which calculated a viewing angle based on the position of the mouse. Finally I developed code to calculate the angle that the avatar is moving in each direction for gravity calculations. I also helped to debug the glove code, collision detection, and made the ending screen and ending sound. This involved a collision node to play the sound clip and a textured box to show the snowman picture. The calculations for the next position go like this, first we define two planes. y1 = a*x1 + b*z1 and y2 = a*x2 + b*z2. x1, y1, z1 is the current position and y2, x2, z2 is the next position so everything is known except for a and b, you have two equations and two unknowns so they can be solved simultaneously. Once you have a and b you can take the partial derivative of either equation to come up with the equation dy/dt = a * dx/dt + b * dz/dt. A and B are known and dx/dt and dz/dt are specified by the user so you can solve for dy/dt, the y velocity required to stay on the line. I would now like to explain how x2, y2, z2 is calculated. The next x and z are calculated by adding the x and z velocity (Multiplied by a timefraction) to the current position, then rounding. An elevation grid is simply an array of heights based on x and z values so I imported the elevation grid array into javascript and the next height is simply the heightArray[nextx][nextz]. So what the set position function does is it determines the time that has passed since the last time it was called by saving the time fraction in a SFTime field and subtracting it from the new fraction whenever it comes in, whenever the new fraction is less than the saved value the timer has started a new cycle and the time is then set to the new fraction and the new fraction stored as the saved value. X and Z input velocities are then read from the glove and the y velocity is called and set based on these values. The movement system worked perfectly except when the x velocity is positive and the z velocity is positive. The line equations themselves are sound and if they work for just positive x, and negative x and positive z, they should work for positive x and positive z. But movement is jerky and out of tune for this. I spent hours looking at the code trying to find what was wrong but I couldn't, so I just put in base statements to set the y value to the nextheight if it tries to fall through the world or fly above the world but this is an imperfect solution that leads to very jerky movement not only in the positive x and positive z case but for the other cases as well. How the camera movement system works is this: The only way to physically track mouse movement that I found reliable was a touchsensor. A touchsensor keeps track of the mouse position over any object. So I put an invisible box in front of the camera linked to a touch sensor, and linked the distance coordinates to a script node that converted them into a rotation that was routed back to the avatar viewpoint. So whenever you move the mouse around the avatar looks around in the same manner. The last part of the project that I did was helping with collision and the ending animation. When the simulation ends it just sets the avatar's position to in front of the ending screen which collides with an invisible bounding box to play a sound, when the sound is played the bounding box is moved away from the avatar so that continuous collisions and continuous sound playing does not occur. How I helped with collision detection was that I routed my get next position function to the collide function so that when a collision occurs the avatar is moved to some set distance away from the collision point. Then the avatar is able to move around again freely.