Computer Graphics Project, Computer Science Department, Technion

Table of Contents:

Implementation and Structure

The game was written in Java and was developed in Eclipse Ganymede environment.
The game uses JOGL to provide OpenGL support.
JOGL Stands for Java Open GL, and is a wrapper library that allows OpenGL to be used in the Java programming language.
Java's Swing was used to create the game's GUI, with some modifications in place to provide a more natural "game-like" feel instead of a simple window application.
The game is built from three main components:

  1. Game Engine: contains GUI and game logic functionality. See Game Play for more details.
  2. Graphics Engine: contains functionality that enables 3D graphics rendering, collision detection and more.
    For a full list of features see the Graphics Engine section.
  3. Audio Engine: a simple utility that enables playing MP3 files.


3D Engine

We've implemented a graphics engine with the following features:

  1. Fully Cross platform (written in Java).
  2. Capable of loading 3D Studio's 3ds files.
  3. Supports creating an hierarchical, tree-based 3d scene, with an unlimited number of children (nodes) per node.
  4. Supports an unlimited number of movable cameras in a single scene.
  5. Supports displaying as many 3D objects as desired.
  6. Renders objects using VOBs (Vertex Object Buffers) or display lists to improve preformances.
  7. Supports autonomous objects movement in the 3D world using a unique velocity vector for each object.
  8. Supports collision detection and collision response.
  9. Supports objects' deformations (like the provided movable-grain deformation).
  10. Allows exporting pre-calculated animations to a list of 'frames' to boost performances.
  11. Supports per-mesh texturing and materials.
  12. Supports configurable lighting using built-in OpenGL functionality.
  13. Supports displaying 2D images.
  14. Supports picking using Color-Picking method.
  15. Supports OpenGL's fog.
  16. Supports Auto-Mipmapping for textures.

Robot Player

We've implemented an AI which makes per-turn decisions based on the state of all players at that time.
The bot makes an effort to build as much as it can in its turn, and tries to advanced to "strategic" points in the gameboard.

Advanced Graphical Features

Fog Effect
The fog effect is achieved using OpenGL's built-in support (glFog). Parametrs such as density, rendering mode, color, location and more are configurable through the Game-Options menu.

Wheat swaying in the wind
The movement of wheat was mathematicaly modeled with Bezier curves and implemented using OpenGL's display lists.
The following is a basic description of our implementation given in three basic steps:
Step 1: define the curvature of the wheat as a Bezier curve
In this step we define a Bezier curve as our 'target' curve. The animation will actually be a linear interpolation between two curves; the first curve is a simple vertical line and the second curve is our target Bezier curve.
Consider a simple wheat stalk as a vertical line of unit length, which lies on the Y axis in the XY plane, as shown in the following diagram:
diagram #1
We define an angle α from the origin with respect to the Y axis. Given that the stalk is of unit length we get the following diagram:
diagram #2
Using simple trigonometry we derive that D = (sin α, cos α, 0) where Dz = 0 since we model movement only in the XY plane.
Point D will define our end point for the Bezier curve. Since we define a Cubic Bezier Curve (curve of degree 3) we need 3 more. The origin is obviously the starting point. The two other points define the curvature of the stalk and can be controlled (and so can the angle α) from the Game-Options menu.
For now, we assume that the points are given as: M=(0, 1/3, 0) and N=(0, cos α, 0) as shown bellow:
diagram #3
Step 2: define an interpolation between the two curves
In this step we build a linear interpolation from the first curve (noted: c1) and the target curve (noted: c2). This is done in the following manner: let P1=(0,h,0) (where h∈[0,1]) be a point on c1. Since c2 (the Bezier curve) is a function f(t) where t∈[0,1] then to conclude the transformation of P1 to a point on c2, we simply calculate P2=f(h)=(a, b, 0).
This can be viewed in the following diagram:
diagram #4
A simple linear interpolation of the form f=a*P1+(1-a)*P2 from P1 to P2 is defined so we can build a smooth looking transition between the points.
Step 3: from curves to OpenGL animation
To finalize our movement generation we need to address the following issues:

  1. The stalk model is not a actually a simple vertical line and we need some way to transform points from the model that do not lie on the line. This is done by mapping each point to its relative location on the line based on the point's "height" (its Y value).
  2. Creating the animation requires extensive computations. Calculating the transformations in each rendering iteration, for each stalk in the scene, is impossible. Our solution for this issue is to create a pre-calculated sequence of frames, where each such frame contains a "snapshot" of the stalk at some point of the transformation between the two curves. This calculation is done for each grain hexagon in the scene. Each frame in the sequence is saved as a compiled display list, thus avoiding unnecessary calculations and enhancing performance.

Sheep Movement and Basic Collision Detection
We have implemented movement of objects, which was used to create the movement of sheep, and also enabled simple collision detection between moving objects.
Basic Movement
Basic movement is handled by the Scene Manager by calling the method move() on objects that are defined as 'movable'. For a scene object to be moveable, all it needs to do is to implement this method.
Sheep Movement
Sheep movement is defined as one of the following:

  1. If the sheep is 'not turning' then the movement is simply updating the sheep position according to the current sheep's velocity vector.
  2. Otherwise: the sheep will continue to turn (in order to reach the requested orientation).

Basic Collision Detection
Basic collision detection is handled by the Scene Manager by calling the method checkOneLevelCollisons() on special objects that requested this option. This is a simple approach to avoid collision detection operations between all objects in the scene.
The special objects we define are simply the wool hexagons.
checkOneLevelCollisons() does the following:

  1. If the parent requests a 'is too far from center' test, then this test is made. This is a simple test which merely checks the object's position and verifies that it doesn't exheed the maximum distance allowed from the center (a pre-calculated value defined in the parent object).
  2. Tests collisions of that object against any objects in the same hierarchial level. This test is a bit more tricky and is elaborated in more details bellow.

Collision Detection between Objects
Collision detection is made using bounding spheres collision test. This is a simple approach that can be summarized as follows:
Step 1: Define a bounding sphere for each object: One simple way of calculating the bounding sphere can be by building the object's bounding box, finding the box' center and then finding the most distant vertex from the center. The distance of this vertex from the center is then defined as the sphere's radius.
Step 2: The collision test: Let o1 and o2 be two objects, with bounding sphere radius' r1 and r2 respectively. The collision test is simply testing if o1 and o2 are (or will be, depending on their velocity) colliding, meaning r1 + r2 < Distance(o1, o2). A tutorial for this method is provided here.

Links and Refernces

  1. Swing Homepage
  2. JOGL Binding
  3. Mixing JOGL with Swing
  4. The OpenGL Red Book
  5. APRON tutorials - advanced tutorials about cameras, textures, loading 3d models, stencil relfections and shadows, and more...
  6. Time based movements (and how to create an FPS Counter)
  7. Irrlicht Engine - a free, open source graphics engine.
  8. Bounding spheres collision detection
  9. Building a 3d camera - a great tutorial that explains much of the math involved in moving a camera in a 3d world.
  10. Reading a 3ds Model (MRI's 3ds Loader)