> I just had one quick question about the new ray tracing program: the > arbitrary aspect ratio is passed in on the command line by the user, > correct? That seems like the most obvious way to do it and I just wanted > to make sure before I coded that method in. You can hardcode the aspect ratio in program constants until you start reading in the scene file. That file will include the image resolution. -------------------------------------------------------------------------- > If you change the aspect ratio, will that change your origin? I've tried > 1024x768 and 1024x1024 and both times my objects went from being centered > in the scene to being located in the upper left corner. The image doesn't > seemed skewed in any way. The origin of the image will change, but only in one component (X or Y). Don't forget that once you normalize the smaller direction, you need to scale the other direction as well. Then center each direction around the center of the image plane in object space (0.0, 0.0, 1.0). For instance, if image resolution is 640x480, the size of the image plane would be (1.33, 1.0) after scaling, and the first pixel would be located at (-0.67, 0.5, 1.0). -------------------------------------------------------------------------- > Is there any particular order you'd like for the arguments (i.e. > dimensions, output file, background file, etc.)? You should only have two command line arguments for this project: first, the input scene file name; second, an optional output file name. If you decide to include additional arguments, please document those in a README.TXT file submitted with your code. -------------------------------------------------------------------------- > I understood what you were in saying in class about the normal for > intersect_box - where you keep track of which face you are intersecting > because then you will know the normal. What I don't get is how you can > tell what face you've intersected with just the two points that define the > box. I've been looking over the notes and I don't see anything in the "t" > calculations that would say which side was hit. How would you recommend I > approach the problem? As you're checking each face, use a variable that stores some type of information about the face so that you can determine the normal of tnear once all faces have been tested. (This code could be similar to the logic you used to keep track of the closest object and normal when testing for intersections with all objects in the scene.) When testing for intersection with the box, I would suggest testing the X planes first (then Y, and finally Z). For instance, if your box has points ll = (0.5, 2.0, 1.5) and ur = (1.0, 2.7, 3.0), then you would first check for intersection with t1 using 0.5, t2 using 1.0, and the X coordinates of the ray. If say, t2 is smaller, you know that it's the ur X coordinate and thus the normal is (1.0, 0.0, 0.0). I suggested in class that you simply store all of the normals in a static array and just use a variable to keep track of the index associated with tnear. If the normals in the static array were ordered (llX, urX, llY, urY, llZ, urZ), the index would be 1 for the above example. -------------------------------------------------------------------------- > I've separated my program into the multiple source files (except for > ppm.c, because I haven't finished IMG_T yet). But now, when I compile and > execute my ray tracer, the image isn't right. I'm only getting the > background. It's as if the intersect functions aren't even being called. > Could you please look at my code? I have no idea what I'm doing wrong. > I've submitted everything, including my Makefile. Thanks! The problem (which was not easy to find) is actually in vector.c -- you need to include . When you encounter such problems, you should try to debug the code either with a debugger, or with printf statement strategically placed in your code. If you had done so, you would have discovered that the ray you were passing to your intersect functions contained all 0.0's. BTW, your Makefile needs to function such that only those source files that have been modified are re-compiled. -------------------------------------------------------------------------- > ... I had a question about splitting the files up. I keep getting 2 > warnings and an error. I'm pretty sure the makefile is right so I was > wondering if you could take a look at the code and lead me in the right > direction. I've already handed in all the files. Thanks for your time. The warning errors result from the fact that you have POINT_T parameter types in your vector function prototypes in vector.h, but you didn't include ray.h in that header file. The error message results from attempting to assign the return value of do_lighting to a non-int variable. You need to place the do_lighting prototype in light.h so that the main function can see that it returns a different type (the return type is int by default). Also, please follow the standard convention and name your #define constants in uppercase. For header file constants that prohibit multiple inclusion, use the name of the file (but with a '_' instead of a '.'). That is, for light.h, use LIGHT_H. -------------------------------------------------------------------------- > I had a few questions about the second Ray Tracer. First: When you said to > hardcode the aspect ratio, do you mean just have it so you can change the > width and height variable values? If yes, I tried that and made them > doubles so my 3Dx and 3Dy would compute right, but my header print > statements for width and height screws up the image if it prints the width > and height as a double. Can I just hardcode my print statements too? Just make them constants either in ray.c or ray.h. Also, please use all caps when defining constants, e.g., #define WIDTH 640 If you need them to be doubles, you can either assign them to variables of type double (implicit casting), or perform explicit casting, e.g., junk = (float) WIDTH / 2; > Also, I'm having problems with trying to put color into my image. It's only > printing my background, which is set to blue. As was mentioned in class, if you're going to make COLOR_T a struct instead of an array, then you need to pass the struct by reference to do_lighting. -------------------------------------------------------------------------- > when you said to pass the COLOR_T structure by reference (in do_lighting) > how do I do that? Do I just use an and sign like this: COLOR_T &color No. You'll never use that particular set of tokens together in a C program (maybe in C++, but not in C). You'll need to declare color in the usual way: COLOR_T color When you pass it to do_lighting, you'll need to take the address: do_lighting (&color); The formal parameters of do_lighting will include a pointer to color: void do_lighting (COLOR_T *color); > also, i thought structures were like pointers and you didn't need to pass by > reference? No. As was stated in class, when structures are passed by value (without referencing using &), the called function gets a copy of the structure, not a pointer. Array names, on the other hand, are passed by reference by default. -------------------------------------------------------------------------- > ... My problem is with my IMG_T structure. I have my ppm function > up and working that prints the image after it has been processed and > stored in the IMG_T structure. The image prints out perfectly fine for > the sizes 640x480, 500x500, and 480x640. But when I try to make an image > that is 1024x768 I get a Segmentation Fault when I run a.out. My program > does make 1024x768 without the IMG_T, I just have the problem when I try > to store the data in an array. The problem results from stack space limitations. Just declare your IMG_T variable as static and it should work fine. -------------------------------------------------------------------------- > I have problems splitting the source files. I have already read FAQ and > checked my source files and the make file, but that doesn't seem to be my > case. I've only separated the vector functions and they definitely don't > work. Since you call vector functions in ray.c, you need to include vector.h in ray.c > Also, when I run the makefile I get > > gcc: -lm: linker input file unused because linking not done > > I don't get this mistake if I use cc... You don't need to link in the math library when you're creating .o files. So, just remove the '-lm' from any compile line in your makefile where you're using the '-c' option (but keep the link paramter in when performing the final linking). -------------------------------------------------------------------------- > Yesterday you mentioned a ppm_write function which I assume will be located in > our ppm.c file. The prototype for this function was something like: > > ppm_write_function( IMG_T *img ); > > This function would probably be called from main as the last thing that needs > to be done - writing the image data to the output file. In order to perform > these operations within this function, won't we need to pass a file pointer > parameter also? I would suggest that you open the file in the ppm write function. That way, you can just declare the file pointer locally. You will, however, need to pass the function the name of the file (determined in main as the default or as a command line parameter). -------------------------------------------------------------------------- > Do we need a distance formula for the box once we have the nearest t-values for > X, Y, and Z? The tnear variable will provides the length of the closest intersection point with the box (i.e., the distance). -------------------------------------------------------------------------- > When we change the size of the picture, from say 500x500 to 1024x768, > should the objects appear enlarged and skewed slightly, or have I just > implemented the arbitray aspect portion wrong? The objects, of course, will appear larger. There may also be a *slight* skew, but if it's pronounced, your code is probably incorrect. > Also when I put the > plane at (0,-1,0) the checker board appears to not be getting the > lighting other than ambient. Do you know what would be causing this? Check to make sure that you're passing the do_lighting function the correct normal for the plane. -------------------------------------------------------------------------- > I'm adding an array of lights to my scene. Do I have to write a separate > function to define the lights, or shall I define them in define_objs, or > shall I just define them in main? You can place the code to initialize the lights in define_objs, or when you read in the scene file. -------------------------------------------------------------------------- > I have 2 lights of the same color, process the array in the do_lighting > routing, but the shadow is not computed properly. The shadow from the first > light is much darker, the second on is very light. I guess this happens > because the second shadow is computed on the place that has already been > lighted with the first light source. What to do with it? Be sure that your call to shadow_test is not over-writing the values of ipoint and normal when it checks for intersections. -------------------------------------------------------------------------- > What should be included in sphere.h, vector.h, plane.h, box.h and others if > all the structures are defined in rtlib.h? Function prototypes for the corresponding .c file. We could put the structures in these .h files, if we didn't have the problem of the mutual dependency across them. -------------------------------------------------------------------------- > I thought I understood why, when we were working with grayscale, that the > color values went from 0.0 to 1.0 (black to white), because how many shades > of gray are there.!?! > > But when dealing w/ color in our first assignment, I thought the values in > the R, G, and B's were integers, 0 to 255. So now I don't understand why > we are setting our colors to combinations of R, G, and B using the decimal > values 0.0 to 1.0????!!?? And how can you put a decimal value in a char > (unsigned or not)????? The color components work the same way as the grayscale. They are computed to fall within the (0.0 .. 1.0) range before being written to the file (or being stored to the image array). At that time, the RGB components are converted to values between (0 .. 255) and saved as three unsigned chars (as we did with the single grayscale value). We could have used unsigned chars to store the RGB (or grayscale) values throughout the entire program; however, we would constantly have to convert the values from floats and/or doubles since we're using math operations that return these types. Also, we would have to scale the color by 255 many times since we are dealing with math functions (like cos) that return values from (0.0 .. 1.0). It's easier, therefore, just to keep the components typed as doubles in the (0.0 .. 1.0) range and convert at the end, rather than constantly performing operations to keep the components in the unsigned char (0 .. 255) range. -------------------------------------------------------------------------- > I do not have a specular "point" on my spheres. It went away when I added > my light attenuation to do_lighting. To get the specular component, don't multiply it by the object's color. Just use the dot product (raised to the 100th power) * light attenuation. -------------------------------------------------------------------------- > Does the LIGHT_T need any changes, and for the light attenuation how do I > determine the distance. In addition to having the light center in LIGHT_T, you might want to add a light color to control intensity. Set all RGB components to the same value for white lights. If you know the light center and the intersection point, you should be able to compute a vector between the two, and then find the length of that vector. -------------------------------------------------------------------------- > I know you said that when we are passing the image structure (IMG_T) to a > function, we are to pass it by reference (via a pointer). But what about > particular fields w/in the structure? I am passing img.width and > img.height to my aspect ratio function, and didn't know if those needed to > be pointers to those two fields. It's OK to pass single integers as value parameters. You just want to avoid passing large structures, like an IMG_T struct, by value. -------------------------------------------------------------------------- > I know when we are turning in our files for grading that we need to do the > transfer in ASCII format, but today I realized a problem with it that other > people might also have and not realize what the issue is. If you transfer > ppm files in ASCII the images will be distorted. You need to either put > the sftp program in binary or Auto Select when transferring the image files > or else they will be distorted. Just wanted to let you know in case other > people were having the same issue. Thanks -- this is good information for students to know. -------------------------------------------------------------------------- > I added 2 lights to my scene. However, now my picture has spots instead > of full shadows on half of the shadow. It looks like it is only the > part where the second light hits an already existing shadow from the > first light. Do you know why this would happen? Here's what's wrong: although you have temporary variables for ray, normal, and dist in shadow_test, you also need a temporary ipoint. Your current ipoint is being overwritten when you test for shadows. It didn't show up until you added multiple lights because previously you were finished with ipoint once you called shadow_test; now, you're not. -------------------------------------------------------------------------- > In my reflection, there are lots of random black/dark pixels. I thought > that this problem would go away when I moved AA to my trace function, > but its still there. Do you have any suggestions of problems I should > look for? I'm not really sure where to start to debug the problem. First, antialiasing should be performed in main, not trace. You might want to check that you're passing the correct intersection point as the origin of your reflected ray. Also, make sure that you're not checking for shadows from the same object you've intersected. -------------------------------------------------------------------------- One additional note for the above question: this problem is related to the shadow problem we had for self-intersections. Because of slight imprecisions that may occur during processing, some intersection points may occur just slightly inside the actual object surface, which could affect shadowing and reflection. For shadowing, if we tried to check for object intersections between the imprecise intersection point and the light, we may intersect the same object containing the intersection point. We avoided this by always skipping the intersection test with the object containing the intersection point. We have the same problem with reflection. If our imprecise point is inside the actual object, we may end up intersecting the interior of the current object and try to compute an intersection based on that point (which is no good). Instead, what we can do is make sure that t is above some threshold before determining a closest intersection. That is, in addition to checking t for the closest intersection, we also make sure t is > 0.001, which is our lower threshold. As long as we don't have any objects that are less than 0.001 units apart, this additional check won't affect our rendering. Alternatively, we could just pass trace a pointer to the currently intersected object and avoid intersection tests with that object, similar to the code in shadow_test. -------------------------------------------------------------------------- > I made the function "read_scene" that reads in the > information from a scene file (defaults to read from scene1.rt). I am > getting a segmentation fault when I try to run the program. I just have > the function in ray.c right now, but once I get it working i'll put it in its > own .c file with a header file as well. I've been tinkering with > it for the past few nights and I still can't figure out where the > segmentation fault could be coming from. I tried to make my scene type of > static, but that didn't do anything. I also made sure that none of my > arrays were going over their allocated space. The only thing I can think > of is that i'm possibly reading too many newlines? First of all, you don't need to worry about reading the newline character. The scanf family of functions skips all whitespace, including newlines. Second, instead of fscanf(fp, "%s", temp); while(strcmp(temp, "EOF") != 0) you should have while (fscanf (fp, "%s", temp) != EOF) since there is no literal "EOF" string in the file. -------------------------------------------------------------------------- > I have a question about the layout of the code. Do you want the reading > of the scene file to be in main or do you want that to become the new > define_objects function? I think that something as important as reading the scene file at least deserves its own function, if not its own source file. So, make it the new define_objects function. -------------------------------------------------------------------------- > In the notes I have about reflection I have a statement that says find > the reflected ray. Is the origin of this ray the intersection point on > the object and the direction the normal from the intersection function? The origin of the reflected ray is the intersection point. The direction of the reflected ray is computed by taking the incoming ray and reflecting it about the normal. We performed a similar computation in the code for the specular term. -------------------------------------------------------------------------- > The spheres are now casting separate, very light-colored shadows on the > ground plane from the separate light sources, however the box shadow still > only appears in the area where the two shadows intersect. This must be > another issue with the intersect_box function when it's being called from > shadow_test. I'll continue looking into that. > > I am using the exact same object sizes, coordinates, light sources, colors, > and image size (648x480) as your most recent example on the "Ray Tracer > Progression" web page. In a side-by-side comparison using these settings, > my specular points look too bright and large, the diffuse lighting on the > spheres and box changes too drastically, and the non-overlapping part of > the shadows on the floor either looks too light-colored or doesn't show up > at all. Perhaps do_lighting is adding too much light in one or more > calculations. When you compute attenuation, always cap it off at 1.0. I believe this will fix your problems. -------------------------------------------------------------------------- > I'm getting a segmentation fault when I try to read the input file. Your seg fault problems in scene reading are due to the non-pointer parameters you use in fscanf, e.g., fscanf (scn_file, "%d", work); This statement should be fscanf (scn_file, "%d", &work); Don't forget that fscanf works similarly to scanf, so you always need a pointer for storing the values. If you run lint *.c -lm or just change your make file to use lint instead of cc, you'll get a broader list of possible errors (BTW, about 30 cases of the above problem show up with lint). -------------------------------------------------------------------------- > I finally figured out why my program was giving me a segmentation > fault, it seems that fscanf does not like to put a string into a char *, > so after changing over to a char array it now works...well that part > anyway. I had the same problem with sprintf in the other programming > assignment and thats what made me realize that it could be doing the > same for fscanf. I just thought I would let you know in case someone > else is having the same problem and so you don't spend a whole lot of > time trying to figure it out. It's not that fscanf doesn't like char pointers; it's that the char pointer was declared as a pointer and never allocated any space. So, when you try to store a value read in by fscanf, you end up following an uninitialized pointer, which causes the seg fault. To fix this problem, you could malloc space for your temp char pointer variable, but the easier way is to just set aside space at the declaration by making temp a char array. -------------------------------------------------------------------------- > The problem I am getting now is it seems to only want to read in the > first part of the file that has the width information, and then not > read in the rest. Keep in mind that strcmp returns 0 if the two strings are equal. Your comparison, i.e., if(strcmp(temp, "width")){ is only true if strcmp returns non-zero. -------------------------------------------------------------------------- > First, I seem to be having a second set of specular > highlights on some spheres. I looked at your example in the progression > notes and am not sure if there is another highlight near the bottom of the > sphere or not. It seems like one black square that is being reflected onto > the green sphere has some white area on it in your image at about the same place > as my second highlight, but I am not sure if this is really there or if the > image is just not as clear when seeing it on my computer. Either way, the > highlights on my image are brighter than the ones that do or do not exist on > yours. I was wondering if this is a problem in my code or if there should > be a highlight at this point due to light reflected off the plane. > Image2.ppm is my picture made from the same scene as the one in the progression > notes. I believe these highlights are reflections from the floor. To make sure, try moving the light to be directly over or slightly behind the spheres. This should let you know whether you have multiple speculars appearing incorrectly, or if they're just reflections of speculars. > Another question I have which I actually know is a > problem is that my boxes seem to show a dark line at x = 0. Img.ppm shows > an example of this. Spheres do not seem to have this problem so I have > looked in the box intersect method to find a problem with the code but have not > seen anything. The reason the sphere in img.ppm shows this line is because > you are actually seeing a box reflecting a sphere that is not in the image > itself. In image3.ppm I have moved a sphere to the point where x = 0 and > there is no line. To solve this problem, you'll need an else condition for the if statment you perform to test if, when a direction is 0, the ray origin is < min or > max. This is the case when the direction is 0, but the ray does in fact hit the box. If this is true, then you need to set the X, Y, or Z component of the intersection point to the corresponding component of the ray origin. -------------------------------------------------------------------------- > I am having the problem with black/dark pixels showing up in my reflective > sphere, and the part of the reflection that I can see does not look correct > (the checkerboard is being reflected along the top of the sphere as well as > the bottom). At first, almost the entire reflection was dark. Then I added > the check for t > 0.001, and it looked a little better. Then I made sure to > normalize the reflected ray direction after I calculated it, and it looked > even better. However, the reflection still isn't quite right. > > Perhaps I am not calculating the direction of the reflected ray correctly. > I have basically done it exactly like the specular calculation. This is the > part of trace that I would like you to look at, if you get a chance, to let > me know if there is anything obvious there. First, move your ground plane to 0.9 rather than 1.0 (just change D). Right now, there's some imprecision in the intersection point of your reflected ray and the ground plane, causing it to return the wrong checkerboard color. Second, you need to use closest_normal.dir, rather than normal.dir, when calculating your reflected ray. -------------------------------------------------------------------------- > I've got the reflection pretty much working well except I am not getting any > specular dots on my sphere. Any ideas as to why this might take place? You're probably doing the color mixing right after the recursive call to trace. That is, you multiply the reflected color by reflectivity and add it to the local color times (1 - reflectivity). This works fine...almost. If you have a completely reflective sphere (reflectivity = 1), you still want specular hightlights, but if you've multiplied the local color by 0 (i.e., 1 - reflectivity), you'll lose it. To fix this, multiply only the ambient and diffuse terms by (1 - reflectivity) in do_lighting. Then, when you mix the colors after trace, you can just add the reflected color times reflectivity to it. -------------------------------------------------------------------------- > Where can I find the file discussed in class that lists the RGB values for > interesting colors? Try /usr/openwin/lib/X11/rgb.txt or /usr/openwin/lib/rgb.txt Don't forget to convert the color values to the [0..1.0] range. -------------------------------------------------------------------------- > A question about the light sources, did say that an intensity factor and/or color is not > necessary for this assignment? Just the location is space? Right. However, if you have multiple lights, your image will quickly become washed out unless you move your lights fairly far away and let the attenuation factor take care of the over-lighting. If you want to add intensity for each light source, just add a field to LIGHT_T that is of type COLOR_T. Set each component (R,G,B) of COLOR_T to the same value to get white lights. The default is (1.0, 1.0, 1.0), but you could cut the light's intensity by half by setting it to (0.5, 0.5, 0.5). And while you could also change the color of the light by setting the components to differing values, I wouldn't recommend it. Once the intensity is set, you would just multiply each of the RGB components for diffuse and specular by the corresponding RGB components of the light in do_lighting. The diffuse equation would then become col.R = dp * obj_color.R * atten * (1 - obj [num].reflectivity) * light [i].R; (Your code may vary.) --------------------------------------------------------------------------