CSG Ray Tracer ============== Introduction ------------ This ray-tracer based on information given in "Computer Graphics, Principles and Practice", by Foley, vanDam, Feiner and Hughes, and Byte magazine. The input file is an ASCII text file that defines surface colours and shapes etc.. Such text files may include other text files. Also, bitmaps may be supplied for 2D texture field maps, and .tex files can be supplied for 3D texture field maps. The recommended extension for ray-tracer files is .rt, and the Andys Editor language definition should have a reserved comment start of ";..." and end of "", since ";"'s are used to introduce comments. Shading Model ------------- The shading model is as given on p734. Each surface has ambient, diffuse, specular and transmissive coefficients, called ka,kd,ks and kt. It also has a diffuse colour, od and a specular colour os. The specular colour is used to compute highlights with, and is usually white-ish for plastic-like surfaces. I = Ia * ka * od Ambient + fatt * Ip * kd * od * cos_nl Diffuse (per light) + fatt * Ip * ks * os * pow(cos_rv, phong_power) Specular (per light) If no surface is hit, then I = Ib, where Ib is a background colour. Objects traceable ----------------- The objects that may be traced are half-planes (planes for short), spheres and arbitrary quadratics. The solid parts are the regions below :- Plane: ax+by+cz+d<=0 Biplane: ax+by+cz+d2<=0 and not ax+by+cz+d1<=0 2 2 2 2 Sphere: (x-a) +(y-b) +(z-c) -d <=0 2 2 2 Quadratic: ax +by +cz +dxy+eyz+fzx+gx+hy+iz+j<=0 Boolean combinations of the above are allowable too. Clearly planes and spheres are just special cases of the general quadratic case, when certain coefficents are 0. However, such primitives are implemented in the indicated faster ways. Input file format/language -------------------------- The following types are understood by the tracer :- value A numeric value xyz A 3 element vector, used for positions and directions rgb A 3 element colour intensity vector col A colour (rgb, but can vary dependant on position) surf A surface structure shape Any of the traceable shapes The following functions (rvalues) are provided. Variables are of the type value unless of the form a_xxx, in which case they are of type xxx :- radians = rad(degrees) Converts an angle in degrees to the value in radians a_xyz = xyz(x,y,z) Returns a vector with the 3 specified values a_xyz = trans_x(a_xyz,dx) Returned vector has x component dx bigger. Similar functions trans_y and trans_z also exist a_xyz = trans(a_xyz,a_xyz) Returns sum of 2 vectors. a_xyz = scale_x(a_xyz,factor) Returns a vector, scaled by factor in x direction. Similar functions scale_y and scale_z also exist a_xyz = scale(a_xyz,a_xyz_factor) Returns a vector, scaled by factor a_shape = rot_x(a_xyz,angle) Returns a vector rotated by angle around x axis Angle is specified in radians Similar functions rot_y and rot_z exist a_rgb = rgb(red,green,blue) Makes an RGB colour value out of 3 components eg: set_col shiny_red surf(0.2,0.6,0.2,0.0, rgb(1.0,0.0,0.0), rgb(1.0,1.0,1.0), 200,1) Note that reserved words trans_x, trans, scale_x, scale, rot_x and related y and z forms here operate on vectors and return vectors. Later, we will see that the same words also operate on shapes to give new shapes. Which is mean't is easily determined from the context. A colour is something that is defined to be a given RGB value for a given point in space. Since colours can be defined in terms of colours, there is conceptually a colour 'tree'. When the root colour is evaluated, it is passed 3 parameters (known as p0,p1 and p2) and these are the x,y and z of the intersection point on the surface of the shape. a_col = col(a_rgb) Makes a colour that is the same regardless of position. a_col = col_field2d(bx,by,"fn.bmp") Makes a colour that takes the passed in p0 and p1 (ignoring p2) and uses (p0+bx,p1+by) to index a bitmap specified. On its own, such a colour can only map a bitmap across the x-y plane. With this primitive (and col_remap) bitmaps may be mapped over the surfaces of objects. eg: set_col floor_col col_field2d(0,0,"tiles.bmp") a_col = col_field3d(bx,by,bz,"fn.tex") Makes a colour that takes the passed in p0,p1, and p2 and uses (p0+bx,p1+by,p2+bz) to index the texture-map file. On its own, such a colour can only map a texture-map that is parallel to the x,y and z axes. a_col = col_interp0(a_col_arg) Perform linear interpolation of p0 argument. col_interp1 and col_interp2 also exist. eg: if p0 was 2.5, then evaluates a_col_arg with p0 at 2.0 and also at 3.0 and finds the average colour. eg: set_col floor_col col_interp0( col_interp1( col_field2d(0,0,"tiles.bmp"))) a_col = col_remap(a_xyz_base, a_xyz_v0, a_xyz_v1, a_xyz_v2,a_col_arg) The (p0,p1,p2) are taken to be cartesian xyz coordinates when this colour is evaluted. New values p0',p1' and p2' are computed where a_xyz_base + p0' * a_xyz_v0 + p1' * a_xyz_v1 + p2' + a_xyz_v2 = (p0,p1,p2). ie: (p0,p1,p2) is transformed to a new coordinate space, based at a_xyz_base in the old coordinate space, with axes given by vectors a_xyz_v0, a_xyz_v1 and a_xyz_v2. The new coordinate is passed to a_col_arg when it is evaluated. When a colour is rotated/translated (when the shape it is used by is rotated/translated, this colour is (ie: these vectors are) is adjusted to move with the shape. Similarly, when a shape is scaled, its colour is scaled too. This will cause the base and basis vectors to be scaled too. a_col = col_cyl(lond,rd,hd,a_col_arg) The (p0,p1,p2) are taken to be cartesian xyz coordinates. The x-y plane can be considered the equator. The z axis can be considered the polar axis. A new p0 is computed as the longitude / lond. A new p1 is computed as the radius / rd. A new p2 is computed as the height (= original p2) / hd. The values are passed down to a_col_arg. This is used to perform cylindrical polar texture maps. eg: set_col x col_remap(xyz(1,2,3),xyz(1,0,0),xyz(0,1,0), col_cyl(rad(1),1,1, col_mat3d(1,0,0, 0,0,1, 0,1,0, col_field2d(0,0,"360x100.bmp")))) a_col = col_sph(lond,latd,rd,a_col_arg) The (p0,p1,p2) are taken to be cartesian xyz coordinates. The x-y plane can be considered the equator. The z axis can be considered the polar axis. A new p0 is computed as the longitude / lond. A new p1 is computed as the latitude / latd. A new p2 is computed as the radius / rd. The values are passed down to a_col_arg. This is used to perform spherical polar texture maps. eg: set_col earth_col col_remap(xyz(0,0,0),xyz(1,0,0),xyz(0,1,0), col_sph(rad(1),rad(1),1, col_field2d(0,90,"360x180.bmp"))) a_col = col_nomove(a_col_arg) When objects of a given colour are translated, rotated or scaled, as well as the objects shape being moved, the objects colour is moved too. Unless this primitive is used. eg: set_col col_dep_on_scene_not_object col_nomove(a_col_arg) a_col = col_mat2d(a00,a01, a10,a11,a_col_arg) 2x2 matrix modification of (p0,p1,p2) and chain on q0 = a00 * p0 + a01 * p1 q1 = a10 * p0 + a11 * p1 Evaluate a_col_arg with q0,q1,p2 This allows you arbitrarily remap p0,p1,p2 in terms of one another. It is useful for mapping textures at obscure angles around shapes, and changing the ordering of p0 and p1 a_col = col_mat3d(a00,a01,a02, a10,a11,a12, a20,a21,a22,a_col_arg) 3x3 matrix modification of (p0,p1,p2) and chain on q0 = a00 * p0 + a01 * p1 + a02 * p2 q1 = a10 * p0 + a11 * p1 + a12 * p2 q2 = a20 * p0 + a21 * p1 + a22 * p2 Evaluate a_col_arg with q0,q1,q2 Similar uses as above. Particularly useful with col_cyl. eg: set_col a_col col_remap(xyz(0,0,0),xyz(1,0,0),xyz(0,1,0), col_cyl(rad(1),1,1, ; here p0=longitude,p1=radius,p2=height col_mat3d(1,0,0, 0,0,1, 0,1,0, ; here p0=longitude,p1=height,p2=radius col_field2d(0,90,"bitmap.bmp")))) The structures above give the ability to map bitmaps anywhere in space - for example, on the sides of objects. Also the ability to do 3d texture mapping. Also interpolation between pixels in texture maps is optional in any or all of the directions in the texture map. Cylindrical polar and spherical polar mapping may be performed. Colour fields may move with the object when it is moved, or stay fixed against a given reference point (ie: the backdrop). It is admitted that this is complicated, and a few worked examples are given later. Every shape has its surfaces defined as the combination of various coefficients and ambient and diffuse colours. Phong power and refractive index also contributes to the overall effect. a_surf = surf(ka,kd,ks,kt,a_col_od,a_col_os, phong_power,refractive_index) Makes a surface colour structure Supply ambient, diffuse, specular and transmissive coeffs. Supply diffuse and specular colours Supply phong power and refractive index a_shape = plane(a,b,c,d,a_surf) Returns a half-plane solid for ax+by+cz+d<=0 This primitive is traced quicker than a general quadratic a_shape = x_lt(x,a_surf) Returns a shape solid for x <= some x value Similar functions x_gt, y_lt, y_gt, z_lt and z_gt also exist a_shape = biplane(a,b,c,d1,d2,a_surf) Returns a half-plane solid for ax+by+cz+d1>0 and ax+by+cz+d2<=0 This primitive is traced quicker than a general quadratic, and is also traced quicker than the intersection of 2 planes. a_shape = x_in(x1,x2,a_surf) Returns a shape solid for x in x1 to x2. Similar functions y_in and z_in also exist. a_shape = sphere(r,a_surf) Returns a solid sphere, radius r, at the origin This primitive is traced quicker than a general quadratic a_shape = ellipsoid(rx,ry,rz,a_surf) Returns an ellipsoid at the origin with given radii a_shape = x_ell_cyl(ry,rz,a_surf) Returns a elliptical cylinder along the x axis with given radii Similar functions y_ell_cyl, z_ell_cyl also exist a_shape = x_cyl(r,a_surf) Returns a cylinder along the x axis with given radius Similar functions y_cyl, z_cyl also exist a_shape = x_ell_cone(ky,kz,a_surf) Returns a elliptical cone along the x axis with given gradients to the y and z axis Similar functions y_ell_cone, z_ell_cone also exist a_shape = x_cone(k,a_surf) Returns a cone along the x axis with given gradient Similar functions y_cone, z_cone also exist a_shape = quad(a,b,c,d,e,f,g,h,i,j,a_surf) Returns a general quadratic as described above If a to f are 0, a half-plane results If d to i are 0, and a=b=c sphere around the origin results In these two cases, the functions above are traced faster a_shape = trans_x(a_shape,x) Returns a copy of the shape, translated by x in the x direction Similar functions trans_y and trans_z also exist a_shape = trans(a_shape,a_xyz) Returns a copy of the shape, translated by a given vector Note: trans(a_shape,xyz(x,y,z)) = trans_x(trans_y(trans_z(a_shape,z),y),x) a_shape = scale_x(a_shape,factor) Returns a copy of the shape, scaled by factor in x direction. (A sphere scaled in this way becomes a general quadratic). Similar functions scale_y and scale_z also exist a_shape = scale(a_shape,a_xyz_factor) Returns a copy of the shape, scaled in x, y and z by amounts. (A sphere scaled unequally becomes a general quadratic). (A sphere scaled equally remains a sphere). a_shape = rot_x(a_shape,angle) Returns a copy of the shape, rotated by angle about the x axis Angle is specified in radians Similar functions rot_y and rot_z exist a_shape = union(a_shape,a_shape) Returns a shape which is the CSG union of the two shapes Similar functions isect, diff, sdiff and extent exist sdiff means symmetric difference (like XOR) extent is explained later a_shape = resurf(a_shape,a_surf) Returns a shape with the same geometry as before, but with different surface characteristics All the commands that end in ',a_surf)' may have it omitted. The tracer just surfaces the shape in a grey colour. This feature is provided to avoid the need to specify surfaces for all the facets (subshapes) of a shape, if you know you are going to resurface it later anyway. The commands supported in the language take a number of rvalues as arguments. These arguments are space seperated. set_value a_new_value a_value Defines a variable a_new_value to be the value a_value eg: set_value door_width 34.5 set_xyz a_new_xyz a_xyz Defines a vector eg: set_xyz viewpoint xyz(1.0,3.5,10.2) set_rgb a_new_rgb a_rgb Defines a RGB colour vector eg: set_rgb yellow rgb(1,1,0) set_col a_new_col a_col Defines a new colour structure set_surf a_new_surf a_surf Defines a new surface structure eg: set_col shiny_red col(0.2,0.6,0.2,0.0, col(rgb(1.0,0.0,0.0)), col(rgb(1.0,1.0,1.0)), 200,1) set_shape a_new_shape a_shape Defines a variable a_new_shape to be the shape a_shape a_shape is anything that evalues to a shape eg: set_shape shell diff(sphere(2,a_surf),sphere(1,a_surf)) If you have set a variable using the above, then it can itself be used as a rvalue. eg: set_shape ball sphere(2.0,greeny_blue) set_shape earth ball Other commands are as follows :- set_attenuation af1 af2 Set light intensity with distance coefficents The nature of this equation and its parameter is arbitrary This function is likely to change later Defaults to 1.0 and 0.9 at present The 0.9 means that light intensity fades to 90%, per unit distance travelled. set_background a_rgb Sets background light intensity Defaults to rgb(0,0,0) at present Used when no object is struck by light ray. set_ambient a_rgb Sets ambient light intensity Defaults to rgb(0,0,0) at present eg: set_ambient shiny_red add_light a_xyz a_rgb Adds a light at specified position of given intensity No lights exist before the first add_light found Lights cannot be removed in present implementation eg: add_light xyz(1,1,1) rgb(1,1,0) render shape eye forward up hangle vangle hpixels vpixels depth rendertype "filename" Renders a view of shape View is from the eye position, looking forward The up vector used to decide which way is up hangle and vangle specify angles of viewing pyramidal volume hpixels and vpixels specify size of output bitmap extra depth to recurse to rendertype is 0 for a typical simple render operation. rendertype is 1 for an anti-aliased trace. "filename" is the output bitmap filename visdiff a_value Set minimum visible difference value used in anti-aliasing computation. Default is 1.0/255.0. include "filename.rt" Causes the given file to be read in and processed. Ideal for when you put an object in an .rt file and then wish to use it from another .rt file. A complicated example --------------------- We have a bitmap of the surface of the earth. It is 360 x 180 pixels and pixel (180,90) is longitude 0 degrees at the equator. set_col col1 col_field2d(180,90,"map.bmp") When col1 is evaluated p0 and p1 are indexed into the bitmap as x and y to give the colour of the earth at a longitude of p0 and latitude of p1. A half-plane aligned along the x-y plane drawn in this colour would show a map of the world. set_col col2 col_interp0(col_interp1(col1)) When you look close-up at something drawn in colour col1, you may be able to see the pixel boundarys. col2 does not suffer from this so badly, as linear interpolation has been used to smooth the pixels in both directions. set_col col3 col_sph(rad(1),rad(1),1,col2) When col3 is evaluated p0,p1 and p2 are mapped from x,y,z coordinates to a longitude, latitude and radius from the origin. The longitude is divided by rad(1) to give a p0 which is the multiple of 1 degree increments. Similarly for the latitude for p1. The radius is divided by 1 (ignored) for p2. ie: we will chain-on to evaluate col1 with p0 equal to the number of degrees east of Grenwich and p1 equal to the number of degrees above the equator. A sphere at the origin drawn in this colour would display a map of the world drawn on the sphere, much like a real globe. set_surf surf1 surf(...,col3...) ; other arguments to surf omitted for clarity set_shape shape1 sphere(1.0,surf2) This defines a sphere, at the origin, which is drawn in a colour that is a map of the world. set_shape shape2 trans(shape1,xyz(0.5,0.1,0.2)) This the same as shape1, only the origin of the globe is at (0.5,0.1,0.2). The colour of this shape has also moved so that the continents of the world still sit on the correct parts of the surface of the sphere. set_surf surf2 surf(...,col_nomove(col3),...) set_shape shape3 sphere(1.0,surf2) This is an awkward shape. Although this would render identically to shape1, should you apply the trans() or rot_x() operator to it, only the shape, not the 2d bitmap texture would move! The 'extent' CSG operator ------------------------- Operators such as union(shape_a,shape_b) conceptually tell the ray-tracer to intersect a ray with shapes shape_a and shape_b. This gives an intersection list which says where the ray enters and leaves shape_a, and another which says where the ray enters and leaves shape_b. By combining these intersection lists we can deduce where the ray enters and leaves the CSG union of shapes shape_a and shape_b. In practice the ray tracer can make certain optimisations. For example if we are tracing isect(shape_a,shape_b) and the intersection list generated for one of the shapes is empty (does not go through anything) then the result must also be the empty set. ie: nothing intersected with something is nothing. This type of optimisation allows the ray-tracer to avoid calculating ray intersections for certain parts of the shape tree. The extent(shape_a,shape_b) operator only intersects with shape_a, if the intersection with shape_b is non null. This is particularly useful when shape_b is made to enclose shape_a, and shape_a is difficult (complicated) to intersect. For example, if I had a scene with a dice (made of many primitives) in one small part of it. I could use extent(shape_dice,shape_enclosing_sphere) to speed up the tracing. The assumption here is that a sphere is much quicker to calculate intersections for than some complicated CSG shape such as a dice (which may have 6 half-plane faces, a rounding sphere and 1+2+3+4+5+6 spheres for spots subtracted etc!). The other assumption is that most of the time we will not be tracing the part of the picture with the dice in. Antialiasing ------------ This ray tracer has 2 modes (or rendertypes) in which it can trace pictures. Mode 0 is a simple point sample trace, which as a result can exhibit severe aliasing. Mode 1 is an antialiased trace, which significantly cuts down on aliasing. Because the Whitted adaptive supersampling technique is used, the penalty of tracing additional rays is only paid where adjacent pixels differ notably. 'Notably' is a little vague, and is specified by the visdiff command. Raytracing produces floating point intensities for each ray traced. These must be mapped to byte values to be written into the file. So the range of intensities from 0.0 to 1.0 map to byte values 0 to 255. Therefore the minimum visible difference is 1.0/255.0. This is the default visdiff value. However, if the 2 least significant bits of a byte are not required to be significant, then the visdiff value can be raised to 1.0/63.0. If the final output file is to be displayed on VGA hardware, this would be ideal. Raising the visdiff value reduces the number of extra rays that are traced due to adjacent samples being different colours, because fewer adjacent will exceed the higher visdiff difference value. One testcard requires 13x the basic cost to trace with the default visdiff, but only 6x with the higher visdiff value above. Other rendertypes, such as 'always-supersample' may be added later. Escher Perspective Rendering ---------------------------- By adding in 10 to the rendertype described above it is possible to tell the Ray Tracer to trace in the wide (or should I say tall) angle style of projection that M.C.Escher did in his "Above and Below" and "House of Stairs" woodcuts. Limitations of the refraction system ------------------------------------ I unconditionally admit that my CSG refraction code is a hack. In a CSG system, a point in space is empty or solid. To model refraction effectively a point in space is empty (a transmissive medium with a refractive index) or solid (non-transmissive medium). This means we should have many classifications of points in space. It is difficult to define boolean CSG operations on multivalue types. eg: what does it mean if a medium of index 1.5 intersects a medium of index 1.3? This program implements refraction by making a set of assumptions. Firstly, it is assumed that the refractive index of empty space is 1.0. Certain solid objects can be considered to have other indexes. All the surfaces that define the boundary of a transmissive shape should have a non-zero transmissive coefficient (ideally the same). This states how much of the light from the other side of the shape is to be allowed through. If the coefficients are not the same, you can produce shapes that look brighter from some directions. Also the surfaces should all have a refractive index set (ideally the same). This refractive index is used to bend rays into the shape, and out again. If the refractive indexes are not the same, you can produce shapes that have different optical properties when viewed from certain directions. This actually is contradictory to the physics being modelled! When a ray strikes a transmissive surface the following additional work is done. If total external reflection occurs then an additional reflected ray is spawned (this is unlikely, as it implies the tranmissive solid has a refractive index < 1.0, and most things don't - glass=1.5, water=1.3 etc.). Otherwise a refracted ray is sent through the solid until it emerges at the far side. If total internal reflection occurs at the far side, the ray is bounced back into the object again. Eventually the ray is refracted out into empty space. The emerging rays intensity is of course, scaled by the additional distance spent going through the solid object, and by kt of each surface the ray enters the shape by. There is a limit to the number of internal bounces allowed due to total internal reflection. This limit is around 10 bounces. If this limit is exceeded the refraction computation is aborted. Due to the way CSG systems merge shapes into one compound shape, certain problems can be produced. For example, if you place a large glass slab onto a smaller red block, you will find that the side faces of the red block, seen from above through the glass block are red, but the top of the red block is not! Why? Well the the two blocks may actually touch to form a composite CSG object. In the first case, the ray enters the composite object through a glass surface, leaves the solid via a glass surface, and strikes a red side surface. In the other case, the ray enters through a glass surface, but leaves through the bottom red surface of the composite CSG shape. The colour returned is whatever is beneath the red block. ie: in the diagram, there is no surface defined at point X to give the expected view of the red top of the block below the glass block. ray 1 ray 2 \ | gggggggg\ggggggggg|gggggggggggg g \ | g <--- Glass block gggggggggg\ggg X gggggggg \ r | r \r | r <--- Red block rrrrr|rrrrr | ooooooooo <--- Other shape The simple workaround to this problem is to ensure that the glass block is just the tiniest amount above the red block, so that the rays leave the glass before hitting the red block. Bitmap formats supported ------------------------ The code will always write out 24 bit bitmaps. When reading, (for texture maps etc.) 1,4,8 or 24 bit bitmaps can be used. This program utilises the services of the Bitmap Rosetta Stone, the Generalised Bitmap Module (or GBM for short). GBM supports the reading and writing of a large number of bitmap file formats in a manner that isolates the calling program (RT) from the format details. Under OS/2 this support is provided by the files GBM.DLL, GBM.LIB, GBM.H and is documented by the file GBM.TXT, and these files should be included with this package. Nature of bitmap bits --------------------- The bitmap bits both read and written are written with value proportional to physical brightness. This means that for OS/2 PM for example, these should be mapped to/from the L* cyclometric colour space. Similarly, when displaying the bitmaps on a specific monitor directly, the pixels should be mapped to a gamma corrected colour space designed to counteract the monitors gamma. In reality these mappings are often skipped, as the results are very similar. 3D Texture map files -------------------- In the absence of a readily available 3D texture map format, I invented one. The 3D texture map file format is inspired by the OS/2 2.0 bitmap formats :- typedef unsigned char byte; /* 8 bit number */ typedef unsigned long dword; /* Intel ordered 32 bit number */ typedef struct { byte b, g, r, dummy; } PAL; /* Palette entry */ typedef struct { byte i [(width*bits_per_voxel+31)/32*4]; } SCAN; typedef struct { dword 0x1a584554; /* Magic number */ dword width, height, depth; /* x,y and z dimensions */ dword bits_per_voxel; /* 1, 4, 8 or 24 only */ PAL pals [(1< 2, 4 -> 16, 8 -> 256 and 24 -> 0, ie: it converts the bits_per_voxel into number of palette entrys present. Much like OS/2 2.0 bitmaps. The expression inside the SCAN definition ensures each scanline is padded to the next biggest 32 bit boundary. Also like OS/2 2.0 bitmaps. Scan lines are stored leftmost pixel to rightmost, and they are stored one after another starting at lowest to highest. Also like OS/2 2.0 bitmaps. Finally complete 2D images are stored one after each other lowest depth first. Intersection lists ------------------ Internally the tracer uses intersection lists as it recursively intersects each ray with each sub-tree of the shape tree. The raytracer automatically computes the required number of lists. However, the user may wish to bear in mind that less deeply nested shape trees require fewer lists, and therefore less memory. Intersections lists hold the entrys and exits from surfaces caused by firing a ray from a given point in a given direction. An intersection list is implemented internally as an array, and so has finite size. If a ray enters/leaves surfaces too many times, the array could be overflown! Early versions of the raytracer had a fixed limit to the size of an intersection list. The current version automatically computes the worst case. The result of the worst case calculation can be significantly higher than the actual worst case for a given model, so in the future I may provide user override. Compilers etc. -------------- AIX 3.1 xlc compiler and should also support any general ANSI UNIX compiler. IBM C-Set++ 32 bit C/C++ compiler for 32 bit OS/2, although slow if no FPU. Relative tracing times (out of date) ------------------------------------ Effect of FPU (20 MHz 386 DX Model 80) :- No FPU 16 MHz 387 C-Set++ (with /O- /Gf-) 780:00 17:00 C-Set++ (with /O- /Gf+) 850:00 approx 16:00 Effect of CPU (with /O- /Gf+) :- 20 MHz 386 DX Model 80 (with 387 for fairness): 22:00 33 MHz 486 DX Model 95 (has FPU built in): 3:35 50 MHz 486 DX Model 95 (has FPU, with secondary cache): 2:37 50 MHz 486 DX2 No-Name clone (has FPU built in): 2:14 RS/6000 520: 1:20 Public domain declaration ------------------------- I wrote all this code in my own time on my own equiptment. I hereby place all this code into the public domain. Feel free to do whatever you like with it. No copyright / no royalties / no guarantees / no problem. Caveat Emptor. Source code ----------- All the source code is folded using Andys Source Code Folding Editor, which should be available from the same place you obtained this package. The source is all highly portable. The full source to GBM is hopefully available from the same place you obtained this Ray Tracer. By obtaining the source, versions of GBM for AIX and other 32 bit operating systems may be easily be built. GBM is also highly portable. Obtaining this code ------------------- Internet: ftp.cdrom.com:/pub/os2/2_x/graphics/rt.zip IBM-VNET: REQUEST RT FROM AKEY AT HVTVM5 Hopefully on the next Hobbes OS/2 CD-ROM too. Change Log ---------- 1/1/92 Initial general release. Various dates Fixed assorted bugs. Removed support for 16 bit systems. Tidied source to make fussier compilers happy (eg: IBM C-Set++) Added support for GBM based bitmap file handling. Complete rewrite of colour support. Added capability to handle 1,4 and 8bpp bitmap 2D textures. Added capability to do 3D block texture maps. Improved shape tree memory management. Improved intersection list management. Added resurface a shape capability. Submitted to Internet. 11/1/93 Removed support for non-GBM based bitmap file handling. Added biplane shape to accelerate tracing. Added of rendertype argument to render command. Added Whitted anti-aliased rendering rendertype. Added Escher perspective rendering rendertype. Submitted to Internet. 1/4/94 Sanitised documentation. Fixed very close to zero inaccuracy problem. 1/8/94 Tidied up source. Added optionality of surface arguments. {{{ Andy Key Internet: ak@vnet.ibm.com # Currently working at IBM until September 94 IBM-VNET: AKEY AT HVTVM # so addresses valid at least until then.