Ray tracer objects To reduce the complexity of the ray tracer we will try to avoid duplicating code as much as possible. We will find many cases where.

Slides:



Advertisements
Similar presentations
CS 11 C track: lecture 7 Last week: structs, typedef, linked lists This week: hash tables more on the C preprocessor extern const.
Advertisements

Python Programming Chapter 5: Fruitful Functions Saad Bani Mohammad Department of Computer Science Al al-Bayt University 1 st 2011/2012.
Coordinatate systems are used to assign numeric values to locations with respect to a particular frame of reference commonly referred to as the origin.
C Structures and Memory Allocation There is no class in C, but we may still want non- homogenous structures –So, we use the struct construct struct for.
Introduction to Linked Lists In your previous programming course, you saw how data is organized and processed sequentially using an array. You probably.
SUMMARY: abstract classes and interfaces 1 Make a class abstract so instances of it cannot be created. Make a method abstract so it must be overridden.
Ray tracing. New Concepts The recursive ray tracing algorithm Generating eye rays Non Real-time rendering.
CSE 332: C++ exceptions Overview of C++ Exceptions Normal program control flow is halted –At the point where an exception is thrown The program call stack.
Diffuse Illumination Diffuse illumination is associated with specific light sources but is reflected uniformly in all directions. A white sheet of paper.
. Virtual Classes & Polymorphism. Example (revisited) u We want to implement a graphics system u We plan to have lists of shape. Each shape should be.
CS 106 Introduction to Computer Science I 11 / 09 / 2007 Instructor: Michael Eckmann.
Ten debugging techniques. The execution process Execution proceeds in a standard series of steps Compute values of subexpressions first Then call value.
Copyright © 2008 Pearson Addison-Wesley. All rights reserved. Chapter 9 Pointers and Dynamic Arrays.
CS 106 Introduction to Computer Science I 03 / 30 / 2007 Instructor: Michael Eckmann.
CS 201 Functions Debzani Deb.
28-Jun-15 Recognizers. 2 Parsers and recognizers Given a grammar (say, in BNF) and a string, A recognizer will tell whether the string belongs to the.
1 CSC 1401 S1 Computer Programming I Hamid Harroud School of Science and Engineering, Akhawayn University
Even More C Programming Pointers. Names and Addresses every variable has a location in memory. This memory location is uniquely determined by a memory.
Adapted from Dr. Craig Chase, The University of Texas at Austin.
Guide To UNIX Using Linux Third Edition
Functions and Conditionals in Alice 1 Stephen Cooper Wanda Dann Barb Ericson September 2009.
OBJECT ORIENTED PROGRAMMING IN C++ LECTURE
Cornell CS465 Fall 2004 Lecture 3© 2004 Steve Marschner 1 Ray Tracing CS 465 Lecture 3.
Cornell CS465 Fall 2004 Lecture 3© 2004 Steve Marschner 1 Ray Tracing CS 465 Lecture 3.
11 Values and References Chapter Objectives You will be able to: Describe and compare value types and reference types. Write programs that use variables.
1 Using Classes Object-Oriented Programming Using C++ Second Edition 5.
Using Classes Object-Oriented Programming Using C++ Second Edition 5.
C++ Object Oriented 1. Class and Object The main purpose of C++ programming is to add object orientation to the C programming language and classes are.
COMP 175: Computer Graphics March 24, 2015
Chapter 6.7 Determinants. In this chapter all matrices are square; for example: 1x1 (what is a 1x1 matrix, in fact?), 2x2, 3x3 Our goal is to introduce.
Inheritance. Recall the plant that we defined earlier… class Plant { public: Plant( double theHeight ) : hasLeaves( true ), height (theHeight) { } Plant(
CS 11 C track: lecture 5 Last week: pointers This week: Pointer arithmetic Arrays and pointers Dynamic memory allocation The stack and the heap.
Inheritance in Classes tMyn1 Inheritance in Classes We have used the Box class to describe a rectangular box – our definition of a Box object consisted.
Stack and Heap Memory Stack resident variables include:
Copyright © 2002, Systems and Computer Engineering, Carleton University a-JavaReview.ppt * Object-Oriented Software Development Unit.
Lecture 21 Multiple Inheritance. What is Multiple Inheritance? We defined inheritance earlier in the semester as a relationship between classes. If class.
Shadows. Shadows is important in scenes, consolidating spatial relationships “Geometric shadows”: the shape of an area in shadow Early days, just pasted.
Current Assignments Homework 2 is available and is due in three days (June 19th). Project 1 due in 6 days (June 23 rd ) Write a binomial root solver using.
CSC1401 Classes - 1. Learning Goals Computing concepts Identifying objects and classes Declaring a class Declaring fields Default field values.
11 Making a Sprite Session 4.2. Session Overview  Describe the principle of a game sprite, and see how to create a sprite in an XNA game  Learn more.
Pointers. What is pointer l Everything stored in a computer program has a memory address. This is especially true of variables. char c=‘y’; int i=2; According.
Pointers: Basics. 2 What is a pointer? First of all, it is a variable, just like other variables you studied  So it has type, storage etc. Difference:
CSCI-383 Object-Oriented Programming & Design Lecture 18.
Ray Tracer Spring 2008 Help Session. Outline Project Web Resources What do you have to do for this project? Ray Class Isect Class Requirements Tricks.
Introduction to Raytracing Raytracing Introduction (from Wikipedia) In computer graphics, ray tracing is a technique for generating an image by tracing.
09/16/03CS679 - Fall Copyright Univ. of Wisconsin Last Time Environment mapping Light mapping Project Goals for Stage 1.
Basic Ray Tracing CMSC 435/634.
Intro to Planning Or, how to represent the planning problem in logic.
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
1 Project 2: Using Variables and Expressions. 222 Project 2 Overview For this project you will work with three programs Circle Paint Ideal_Weight What.
Copyright © 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Chapter 9 Pointers and Dynamic Arrays.
Introduction to Computers and Programming Class 24 Structures (structs) Professor Avi Rosenfeld.
Copyright © 2014 Pearson Addison-Wesley. All rights reserved. Chapter 9 Pointers and Dynamic Arrays.
Variables in C Topics  Naming Variables  Declaring Variables  Using Variables  The Assignment Statement Reading  Sections
Variables in C Topics  Naming Variables  Declaring Variables  Using Variables  The Assignment Statement Reading  Sections
M1G Introduction to Programming 2 2. Creating Classes: Game and Player.
CMSC 104, Version 8/061L09VariablesInC.ppt Variables in C Topics Naming Variables Declaring Variables Using Variables The Assignment Statement Reading.
More on Ray Tracing Glenn G. Chappell U. of Alaska Fairbanks CS 481/681 Lecture Notes Wednesday, April 14, 2004.
Announcements Assignment 2 Out Today Quiz today - so I need to shut up at 4:25 1.
Module 9: Operator overloading #1 2000/01Scientific Computing in OOCourse code 3C59 Module 9: Operator Overloading In this module we will cover Overloading.
Coordinatate systems are used to assign numeric values to locations with respect to a particular frame of reference commonly referred to as the origin.
Windows Programming Lecture 06. Data Types Classification Data types are classified in two categories that is, – those data types which stores decimal.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
DYNAMIC MEMORY ALLOCATION. Disadvantages of ARRAYS MEMORY ALLOCATION OF ARRAY IS STATIC: Less resource utilization. For example: If the maximum elements.
Function Parameters and Overloading Version 1.0. Topics Call-by-value Call-by-reference Call-by-address Constant parameters Function overloading Default.
Winter 2009 Tutorial #6 Arrays Part 2, Structures, Debugger
User-Written Functions
Introduction to Linked Lists
Introduction to Linked Lists
Variables in C Topics Naming Variables Declaring Variables
Presentation transcript:

Ray tracer objects To reduce the complexity of the ray tracer we will try to avoid duplicating code as much as possible. We will find many cases where we do essentially the same thing no matter what type of “object” we are working with. Underlying our code we need data structures that can accommodate the data that we need to retain, and that can be easily accessed.

The entity_t structure Whether we are working with a sphere, plane, light or “window” we will find that certain fields are common to all of these types. We will find that every entity has a “name”, a “type” and a “type code”. So we will define a base type called an entity_t. The typedef for an entity_t is: typedef struct entity { int magic; /* magic number */ char *name; /* left_wall, center_sphere */ char *type; /* plane, sphere,... */ int code; /* Code for object type */ void *entDerived; /* Pointer to object derived from an entity_t */ } entity_t;

Ray tracer objects The name pointer will point to the unique name of this object, the type field will point to a C-string containing the type of the object (e.g. “plane”, “sphere”, “window”, etc.), and the code field contains the unique integer code for an object type (e.g. a “plane” is code 1, a “sphere” code 2 and a “window” code 0. The code field is convenient to use with a switch statement. The use of the magic field will be described later – each object type will have a unique magic number that we will use for error checking (don’t get your hopes up – it’s really not magic).

The entity_t structure Obviously, objects as diverse as planes, spheres, lights and windows differ in the type of data we need to know about each. Defining the possible fields that would be needed for every possible object type in entity_t would be difficult to do, wasteful of space, and difficult to maintain when we try to add new types (like rectangles or triangles). Rather than adding fields to the entity_t for new types, we will instead use a pointer to point to another structure that contains data that is unique for that object type. That is where the void pointer, entDerived, comes in. This pointer points to data that is unique to this particular type.

Scene objects A scene object is an object that may be visible in the image, such as a sphere or a plane. Once again we find that spheres and planes share certain common data – so rather than immediately defining sphere and plane objects, we instead define an intermediate object from which plane and sphere objects can be derived. Every shape object has a color, a value that indicates how much light it reflects if illuminated by a light source (other than the ambient light) and how reflective its surface is.

Scene objects We will define a sobj_t as: typedef struct sceneobj { int magic; /* "Magic" number*/ /* Surface data */ pixel_t color; /* surface color */ intensity_t diffuse; /* light reflection */ intensity_t reflective; /* ray reflection */ void *sobjDerived; /* Pointer to derived scene object data */ } sobj_t;

Scene objects the color, diffuse (reflected light), and reflective fields describe the characteristics of the surface of the shape object, whether it is a plane, sphere, rectangle, etc. The interpretation of these fields will be given later. Also note the pointer field, sobjDerived –This pointer will point to yet another structure that will contain data that is unique to the object type, such as the radius of a sphere or the orientation (normal) of a plane.

The plane object Next we will define an infinite plane (as opposed to a plane with dimensions like a rectangle or triangle). An infinite plane’s position and orientation in 3-D space can be described in several ways, e.g. 3 points on the plane, or one point and a vector that is perpendicular to the plane (this is called the normal). This semester we will use: 1.point – the coordinates of any point on the plane, 2.orient1 – a vector that is parallel to the plane, 3.orient2 – a second vector that is also parallel to the plane but not parallel to orient1. We will use orient1 and orient2 to compute the plane’s normal, which establishes the orientation of the plane. The point establishes the plane’s location in 3-D space.

The plane object We will define a plane_t object that will be pointed to by the derived field of a shape_t as: typedef struct plane_type { int magic; /* magic number*/ vector_t orient1;/* Orientation 1 of plane*/ vector_t orient2;/* Orientation 2 of plane*/ point_t point; /* Any point on surface*/ vector_t normal;/* Computed normal to plane */ void *planeDerived; /* Pointer to derived object data */ } plane_t;

The plane object Note the fields to hold the plane’s orientation and point values. We also include a field to hold the normal vector, which will be computed. We don’t need to worry about a plane_t’s derivedPlane field right now, but later, if we implement rectangles and triangles, we will derive them from a plane_t.

The plane object So, if we create a plane object, we actually create a sobj_t and a plane_t. Consider the following example. Individual plane, sphere and other visible objects will be added to the sobjList list pointed to in the scene_t structure.

The sphere object In a like manner, we will also derive a sphere from the sobj_t object. For a sphere we need two pieces of information: 1. center – the coordinates of the center of the sphere, 2. radius – the radius of the sphere. We will define a sphere_t that has the following format: typedef struct sphere_type { int magic; /* magic number */ point_t center; /* Location of the */ double radius; /* distance from center to surface */ void *sphereDerived; /* Pointer to derived object data */ } sphere_t;

The sphere object A sphere object could be illustrated by the following example Spheres and planes will be added to the sobjList in the scene_t structure.

The scene_t object We need to maintain a LOT of data about the virtual scene and the environment it lives in. This data needs to be readily accessible to code in various parts of the ray tracer. We will find that it is convenient for all data about the scene and all objects to be accessible from one central data structure, which we will call the scene. The scene is described in the scene_t structure: typedef struct scene { int magic; /* magic number */ entity_t *window;/* Window data */ image_t *picture;/* output image */ /** Lists of objects in the virtual world **/ list_t *sobjList; / * scene objects list */ list_t *lightList; /* "Lights" list */ } scene_t;

The scene_t object The window contains information about the window that we are rendering. This is further described in the next section. The picture field is a pointer to an image_t that will hold data about the output image we are creating, including the pixel data. Recall that image_t includes the pixel dimensions of the image (columns and rows), brightness and a pointer to the pixel data. The sobjList points to a linked list of scene objects (e.g. planes, spheres, etc.) and the lightList points to a linked list of light sources in the virtual world. An illustration of a scene object and the entities it point to is:

The scene_t object An illustration of a scene object and the entities it points to: sobj_t * scene struct scene { window_t *window; image_t *picture; list_t *sobjList; list_t *lightsList; struct window { char *name; double windowWidth; double windowHeight; point_t viewpoint; int pixelColumns; … struct image_type { int columns; int rows; int brightness; pixel_t *image; "myimage" list of virtual world visible scene objects list of lights

The window_t object The window_t object keeps track of window dimensions, global lighting, viewpoint coordinates, etc. related to the particular image we are trying to generate. A window_t has the following format: typedef struct windowType { int magic; /* Magic number */ double windowWidth; /* Window width in world units */ double windowHeight; /* Window height in world units */ int pixelColumns; /* Window width in pixels */ intensity_t ambient; /* Ambient lighting on scene */ point_t viewPoint; /* Viewpoint coordinates */ } window_t;

The window_t object The fields windowWidth and windowHeight are the dimensions of the window (image) that we are creating in “world” coordinate units. More on this later. These two values give us the relationship between the width and height of the image, e.g. worldWidth = 6 and worldHeight = 6 would be a square image, and worldWidth = 8 and worldHeight=4 would give us a rectangular window that was twice as wide as high. We will relate this to pixels later. The viewpoint is the coordinates from which the virtual world is being viewed.

The window_t object The ambient field is the intensity of the general “wash” of light that is hitting all objects in the scene with the same intensity level. –Ambient light is why we can see something that is totally blocked from a direct light source. The pixelColumns field holds the number of pixel columns in the image. We will find that this value is duplicated in the image_t – but for reasons that will become apparent later, we need a “holding” area for the value of the number of pixel columns until the image_t is created.

The image_t object We will use the same image_t data type that we used in homework 2, i.e.: typedef struct imageType { int magic; /* magic number */ pixel_t *image; /* pointer to pixel data */ int columns; /* number of pixel columns */ int rows; /* number of pixel rows */ int brightness; /* image brightness */ } image_t;

The image_t object As in homework 2, the image_t contains data about an image, including its dimensions, (columns and rows), brightness and a pointer to the pixel data of the image. We will use the getimage() procedure from homework 2 to create a new image_t.

Summary Overview of Data Structures The following illustrates the relationship between the various structures.

Examples of Accessing Object fields Here are several examples of how we might access fields from the structures pointed to by the scene_t. Assume scene is pointing to an instance of a scene_t. Suppose we want to set imageRows to the number of pixel rows in the image. We can get this value from the image_t and could say: imageRows = scene -> picture -> rows; That’s fairly straight-forward.

Examples of Accessing Object fields Now suppose we want to set the windowWidth to 5. The statement: scene->window->entDerived->worldWidth = 5; would generate compile errors because the compiler can’t figure out what type of data “entDerived” is pointing to. We could use type-casting to keep the compiler happy: ((window_t *)(scene->window->entDerived))->worldWidth = 5; Or we could break this up into several statements: window_t *window; window = scene->window->entDerived; window->worldWidth = 5;

Examples of Accessing Object fields We didn’t need typecasting in this case because both “window” and “scene->derived->entDerived” are of type pointer – they just differ in the type of data they point to. You can always assign a pointer to a pointer.

Examples of Accessing Object fields Now let’s assume the first shape object in the sobjList list is a plane, and we want to set the x coordinate of the plane object’s point to 5. We want to make use of the list functions that we previously developed. So to get access to the first entry of the sobjList list we would first create an iterator and then use a l_next() call. So to fetch the first object from the list we could do: interator_t *iter; entity_t *ent; iter = createIterator(scene->sobjList); sobj = l_next(iter); So ent should now be pointing to the first scene object. So assuming that object is a plane object, we could set the x coordinate of the plane object’s point to 5 with: ((plane_t *)((sobj_t *)(ent->entDerived))->sobjDerived)->point.x = 5;

Examples of Accessing Object fields First let me explain, and then offer an alternative. The l_next() function returned a pointer to the entity_t of the first object in the objects list, so ent is pointing to the entity_t. The entDerived field points to the associated sobj_t, but it is a void pointer, so we have to type cast the pointer telling the compiler that this is a pointer to something of type sobj_t. In the sobj_t the sobjDerived pointer is pointing to the plane specific information that contains the point data. But again this pointer is also declared as being of type void – we don’t specify what type of object it is pointing to. Without additional information the C compiler would have no way of knowing that sobjDerived was pointing to a plane_t. So we must use typecasting in this case, which is the reason for the (plane_t *). We also have to be careful with parentheses to make it clear what is being modified by the typecast. Finally x is a field in the vector_t structure, hence the point.x.

Examples of Accessing Object fields I personally find writing a line like this confusing and prone to errors, and something that makes me want to throw my laptop out of the window. An alternative is to break it up. Consider the following alternative: sobj_t *sobj = ent->entDerived; plane_t *planePtr = sobj->sobjDerived; planePtr->point.x = 5; So first we set the pointer sobj to point to the scene object’s sobj_t. Then we set planePtr to the derived field. Note this time we did not need to use typecasting. In this case we are just assigning a pointer value to a pointer value, so there is no ambiguity. Now that we have planePtr pointing to the plane_t structure, we can access fields within the plane_t directly.

Examples of Accessing Object fields Another advantage of this approach is that if we are going to be writing additional code that also accesses fields in the plane_t (or for that matter the sobj_t), we already have pointers set. We could, for example, now write additional statements like: planePtr->normal.z = 1; sobj->color.y = 100; fscanf(inFile, “%lf %lf %lf”, &planePtr->point.x, &planePtr->point.y, &planePtr->point.z);

"magic" Numbers Notice that each object type (typedef) we have defined has included a field called “magic”. This is a common debugging technique. A very common programming error is to think a pointer is pointing to one type of object, but in fact the pointer is pointing at a totally different type of object For example we might think that “ptr” is pointing to a plane_t, but in fact it is pointing to a sphere_t. This would clearly cause problems that, at best, will result in broken images, at worse, seg faults.

"magic" Numbers So the idea of an “magic” number is to assign this field a value that is unique for this type of object. The value of the number is not important as long as it isn’t a value that might happen by accident (e.g. 0 would be a terrible choice for a magic number, as would 1). But something like is not a number that is likely to be in the magic field by accident. So let’s say we define magic numbers as follows: #define ENTITY_T #define IMAGE_T #define PLANE_T #define SCENE_T #define SCENEOBJ_T #define SPHERE_T #define WINDOW_T

"magic" Numbers Once again, the choice of values is totally arbitrary – they just need to be unique and not a likely value to happen by accident. So how do we use these? We will see shortly that typedef’d data are allocated and initialized by create…() functions, e.g. createPlane(), createSphere(), etc. The create…() function will malloc space for the data type, and initialize its fields. So createPlane() would set the “magic” field of the plane_t to PLANE_T (i.e ), etc.

"magic" Numbers Now when we set a pointer to point to one of these data types, BEFORE we do anything else we should check the magic number to make sure the pointer is pointing to the right data type (i.e. what we think it is pointing to). An easy way to do this is to use the assert() macro, e.g. if “ptr” should be pointing to a plane_t, then: assert(ptr->magic == PLANE_T); The argument to assert() is a conditional expression that has a TRUE or FALSE value. The assert() is saying this condition MUST BE TRUE. If the condition is not TRUE, the assert() statement will abort the program. The advantage of this is that the program immediately aborts on a bad pointer, rather than at a later point because memory has been overwritten.

"magic" Numbers Here is an example of a program aborting because the magic number didn’t match the “expected” value: ~/cs2100/ray1:./ray1 world.txt output.ppm ray1: shape.c:65: completeShape: Assertion `obj->magic == ' failed. Aborted

"magic" Numbers Another example involving traversing multiple pointers to get to a sphere_t is: entity_t *ent; sobj_t *sobj; sphere_t *sphereptr; ent = l_next(itr); assert(ent->magic == ENTITY_T); sobj = ent->entDerived; assert(sobj == SCENEOBJ_T); if (ent->code == SPHERE) { sphereptr = sobj->sobjDerived; assert(sphereptr->magic == SPHERE_T); … }

"magic" Numbers Normally you would test the pointer variable right after it has been set in a procedure. Note: You might be concerned about the additional overhead in your program to run these tests. The assert() statements in your program can be disabled without removing them by including the definition: #define NDEBUG before the “#include ” statement in the code (note the include is in ray.h in the provided code for the raytracer). If this flag is defined the assert() statement generates no code (i.e. no overhead – but no testing either). More on this later when we talk about # compiler directives.