681 Lab1 Help

 

CSE 681 Lab 1 Help


To begin this lab, I suggest that you first spend some time to have a good design of  your software. Although you can use C, C++ is the recommended language for this course. In the following, I share with you my own experience implementing a ray tracer during the past summer (I have not taught this course for a few years so it was fun to me!) . It is certainly not the only way or the best way, but you might find the following information helpful if you need some help to have a quick start. Once you are more familiar with ray tracer design, you can always come back to refine the software (If I have time, I myself would).

1. You need to define a few C++ classes for the scene information as well as your main ray tracer. What I have is a camera class,  a sphere class (since you will only handle spheres for your first lab), a light class (only point light), and a ray tracer class.

2. The camera class contains the camera position, direction, view up vector (camera orientation, that is), image plane aspect ratio, field of view angle in Y. These are the information that you can read from the Open Inventor file. My camera class also contains some derived values such as the three basis vectors U, V, and N for the eye coordinate frame and the image width and height in world space (not in pixels). How to compute these derived information has been discussed in class. If you want to know how to read the camera position, direction,  view up vector, and aspect ratio from the Open Inventor scene file, here it is:

    1.    SoCamera * camera = scene->Camera;

    2.     SbVec3f camera_position = camera->position.getValue();

    3.     SbRotation camera_orientation = camera->orientation.getValue();

    4.     SbVec3f camera_rotation_axis;

    5.     float camera_rotation_angle;

    6.     camera_orientation.getValue(camera_rotation_axis, camera_rotation_angle);

    7.     float camera_aspect_ratio = camera->aspectRatio.getValue();

    8.     // calculate camera direction and camera up direction

    9.     SbVec3f camera_direction, camera_up;

    10.     camera_orientation.multVec(SbVec3f(0, 0, -1), camera_direction);

    11.     camera_orientation.multVec(SbVec3f(0, 1, 0), camera_up);


  1. 3. For lab 1, you do not actually need to use the lighting information. But I suggest that you create a simple point light class that only contains the position of the light.  You can store the light position into this class after you read the information from the Open Inventor file. But you can skip this step if you want and do it later for other labs.

4. For the sphere class, I store the position of the sphere center and its radius. The radius of the sphere you can read from the Open Inventor file. The default position of the sphere is at [0,0,0], but you need to multiply it to the sphere’s transformation matrix to get its final position. To do this,  you need to follow the steps below.

    1. a. Retrieve the transformation from the sphere object. This is done in the Open Inventor reader as:

  1.                 SoTransform *transformation = obj->transformation; //obj is the current inventor sphere

    1. b. Retrieve the transformation’s scale vector, translation vector, and rotation axis and angle. This is done as follows:

      1. SbVec3f scale_vector = transformation->scaleFactor.getValue(); 

      2. SbRotation rotation = transformation->rotation.getValue();

      3. SbVec3f rotation_axis;

      4. float rotation_angle;

      5. rotation.getValue(rotation_axis, rotation_angle);

      6. SbVec3f translation_vector = transformation->translation.getValue();



    2. c. Combine the translation, rotation, and scaling into a single matrix. This is done as:

      1.    SbMatrix T,S, R, F;

      2.     T.setTranslate(translation_vector);

      3.     R.setRotate(rotation);

      4.     S.setScale(scale_vector);

      5.     //  F = T*R*S;    changed this to  F = S*R*T below  to be consistent with what used in ivview

      6.     F = S *R*T

    3. d. Multiple the matrix F with the default sphere center position (0,0,0). This can be done as:

      1. SbVec3f pos(0,0,0);

      2. F.multVecMatrix(pos, pos);

    4. e. Finally, store the sphere center and radius into your own class object. The steps above from a-e are done immediately as I read each sphere from the Open Inventor file.

  2. I also have a method in the sphere class called Intersection(). The input to this method is the starting position and the direction of the ray, and the output is the ‘t’ where the input ray intersects the sphere. If there is no intersection, it will return -1.

If you want, you can also create a base class for all the object types and have sphere being a subclass of the base class. But you do not really need this for this lab.

5. Finally, you need to create a ray tracer class, the class that implements the main ray tracing algorithm. My ray tracer class includes the following information:

    1. a. The scene object - OSUInventorScene *scene;

    2. b. A list of objects (spheres) you read from the Inventor file. The type of the object should be the sphere class defined by you.

    3. c. A camera object of your own camera class.

    4. d. The image resolution x and y in pixels. This comes from the program arguments.

    5. e. The final image. This is defined as an array of unsigned char. For example:

    6.     unsigned char *image;

    7. You need to remember to allocate space for this pointer once you know the image resolution.

  1. My ray tracer class have the following methods:

    1. a. read_open_inventor_scene(char *iv_file);  This is the routine that takes an Open Inventor file as the input, and read out all the information in the scene (similar to the sample_read_iv.C code), and create the spheres, camera, light objects stored in the ray tracer class object.

    2. b. trace_rays(); this is the method to cast rays from all pixels into the scene and compute colors for the pixels based on how they intersect with the scene objects (spheres, that is). The main body of the method is something like:

    3. for (i=0; i<image_h; i++)

    4.     for (j=0; j<image_width; j++) {

    5.         calculate the ray origin and ray direction;

    6.         call shade() for the pixel rays; //see below about shade()

    7.         write the color returned from shade() into your image

    8. }

    9. c. shade(float* ray_origin, float* ray_direction, float *color); For each pixel in the trace_rays() routine, I call this method with the ray starting point and ray direction as the input. The color computed from tracing this ray is returned in the argument color. How to calculate the intersection for the first object the ray hits is discussed in class.

  2. That is it for now. I may add some additional information if requested so. Start early and bring your questions to class so I know what else to add here.