home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-02-02 | 42.4 KB | 1,539 lines |
- Rayce version 2.7
-
- A Raytracer
-
- by Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
-
- Rayce is based on Ray, a raytracer written by George Kyriazis
-
-
-
- 0.99 LEGALESE
-
- Rayce is Copyright 1993 Han-Wen Nienhuys. Rayce is distributed under
- the terms of the GNU General Public License. You can modify and
- redistribute Rayce under certain conditions. It is distributed "as
- is", without warranties of any kind. See the file "copying" for
- details. If you have not received a copy of the GNU General Public
- License along with this program, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-
- 1. INTRODUCTION
-
- Rayce is a raytracer I've written to find out how raytracing works.
- It's written for purely educational purposes. If you want to make
- neat pictures, use PoV or Vivid instead. Oh, by the way,
- "educational" means "for my education", but you could use it in a CG
- class too. It wouldn't make a very good example, though, I am
- afraid.
-
- Still, Rayce has been expanded very much, and I plan to incorporate a
- lot of weird and new stuff into it.
-
-
- 2. CREDITS
-
-
- These people have (knowingly or unknowingly) contributed to Rayce:
-
- George Kyriazis <kyriazis@turing.cs.rpi.edu>
- Shawn McHorse <Zaphod@fcircus.sat.tx.us>
- The PoV-team
- Mark VandeWettering <markv@cs.uoregon.edu>
- Ben Trumbore
- David G Hook, Bernie Kirby and Peter McAree, <echidna@munnari.oz.au>
- Jochen Schwarze
- Harm Hanemaayer <hhanemaa@cs.ruu.nl>
-
-
- Rayce is based on a very small raytracer by George Kyriazis. You can
- still download this raytracer on wuarchive.wustl.edu, in the directory
- /pub/graphics/graphics/ray/gk/ as ray2*.shar.Z. This raytracer was
- called Ray, I've changed the name to avoid confusion. Besides, "ray"
- isn't a very original name for a raytracer, is it ? (and "Raycer" was
- too obvious :-).
-
- In developing, I have used Persistence of Vision, a great raytracer
- usually dubbed PoV, as a shining example. That's why it looks like PoV
- so much.
-
- I would like to especially thank Shawn McHorse
- <Zaphod@fcircus.sat.tx.us> for valuable comments, bugfixes, the Rayce
- output in the SPD, DJGCC compile and the new shading code.
-
- The color include, and the concave polygon code were taken from for
- Mark Vandewettering's MTV tracer. BTW. It looks an awful lot like the
- X11 color database.
-
- Most of the auto bounding for primitives is from: Graphics Gems III,
- section VI.5, bounding_volumes.c, Ben Trumbore, "Rectangular Bounding
- Volumes for Popular Primitives"
-
- The formulas from the surfs.inc were taken partly from PoV 2.0.
-
- The sturm sequence code in solve.c was taken from the raytracer Art,
- part of the Vort package (it is almost identical to the code in
- Graphics Gems I), by David G Hook, Bernie Kirby and Peter McAree,
- reachable via <echidna@munnari.oz.au>
-
- The random numbers are also from Vort.
-
- The cubic and quartic solver was by Jochen Schwarze, and was taken
- from Graphics Gems I.
-
- The gif reader was done by Harm Hanemaayer <hhanemaa@cs.ruu.nl>, and
- it was based on posting in rec.games.programmer in spring of 1993.
-
-
-
- 3. USAGE & OPTIONS
-
- The syntax is simple:
-
- rayce [options]
-
- If you don't give options, it will print a small usage screen. You can
- use the following command line options:
-
- -o<file>
-
- Specifies the output file (default: output.tga). The output format is
- 24 bit type 2 uncompressed Targa.
-
- -i<file>
-
- Specifies the input file (default: input.r)
-
- -I#
-
- Specifies the number of samples per pixel to use (default: use the number
- In the options{} block, and that's 1 by default)
-
- -c
-
- Continue a previously aborted trace (default: don't continue)
-
- -x
-
- Disable abort via keypress (default: allow abort). If you have
- compiled Rayce for a different computer than IBM PC, your check_abort()
- determines the abort condition.
-
- For Linux, this flag has nog effect. Interrupting should be done by
- sending a SIGINT (pressing ^C, killing rayce, rebooting, etc.)
-
- -h#
-
- Specify image height in pixels (default: 50)
-
- -w#
-
- Specify image width in pixels (default: 50)
-
- -d#
-
- Turn on debugging. The number given is the sum of the debug flags you
- want to use:
-
- 1 switch on debugging for tokenizer.
- 2 switch on debugging for parser (yydebug = 1)
- 4 switch on debugging for memory (doesn't work under
- linux)
- 8 print the interior after parsing
-
- This only works if rayce was compiled with -DDEBUG.
-
- After a line has been finished, some statistics are printed, and after
- Rayce has finished tracing, more elaborate statistics are printed.
-
-
- 4. INPUT
-
- The input is based on PoV 1.0 and 2.0 format. Below is an overview.
- If you want the details, check out rayparse.y, the yacc/bison file
- which implements the parser. Ok. Fasten your seatbelts:
-
-
- 4.1. Basic stuff
-
- Comments are between /* and */, and after a //. It is legal to nest
- the /* */.
-
- A float is what you would expect it to be:
-
- 1.2 12e-1 .12e1
-
- all specify the same number.
-
- Additionally, you can use expressions for floats:
-
- 12/10
- 0.12*10
- 1.0 + 0.2
- 1.2^2 - 0.14
- - (- 1.2)
-
- These expressions are all valid, and all specify 1.2.
-
- You can make a vector out of three floats:
-
- <FEXP1, FEXP2, FEXP3>
-
- FEXP1, FEXP2 and FEXP3 are floating point expressions. You can use
- expressions on vectors in the same manner as you can with floats: -, +
- do addition and substraction. Use * for scalar multiplies, ^ for a
- vector cross product. From now on, I will use <VECTOR>
- to denote a vector. Use
-
- (<VEXP1>, <VEXP2>)
-
- for the improduct, a float expression. "x", "y" and "z" are the
- coordinate vectors: Example:
-
- <1, 2/3, 4 * (x , <2,0,0>) >
-
- should give <1, 0.6666, 8>. There is one other feature:
-
- <0.5>
-
- will produce a vector <0.5,0.5,0.5>. Although this isn't custom in
- mathematics, it is very easy for specifying all kinds of shapes, eg.
- boxes, scaling factors, etc.
-
- ! Please note that everywhere two adjacent floats or vectors should be
- ! separated by a comma.
-
- Keywords should be in lowercase. Everything is case sensitive.
-
- Colors work the PoV-way. For reasons of compatibility, an alpha part
- is allowed, but it will be ignored.
-
- An extra feature is to convert colors from and to vectors. This makes
- adding and substracting colors easier.
-
- Example:
-
- color red 0.5 green 0.1
- color red 0.5 green 0.1 alpha 0.5
- color rgb <0.5, 0.1, 0>
- #declare testcol = color red 1.0 green 0.2
- color rgb 0.5 * <color testcol>
-
- All give the same color.
-
-
- 4.2 Camera
-
- Rayce has a simple pinhole camera, and it is lefthanded, similar to
- PoV's camera. This camera can't be distorted, though.
-
- The viewpoint is specified by
-
- camera {
- location <EYE>
- sky <SKYVECTOR>
- fov FOV
- direction <DIRECTION>
- aspect ASPRATIO
- look_at <POINT>
- }
-
- EYE is the eye location.
-
- <SKYVECTOR> is the analogon of the PoV sky vector. Your pictures will
- have their the top of your screen aligned to <SKYVECTOR>
-
- <DIRECTION> is the viewing direction. This is not used very often,
- since look_at is so much easier.
-
- FOV specifies the vertical Field of View.
-
- ASPRATIO is the aspect ratio of your picture (normal computer screens
- have aspect 4/3 = 1.333)
-
- look_at points the camera to towards <POINT>, while preserving the
- direction vector length.
-
- Hope you understand this... A camera can be scaled, rotated and
- translated.
-
-
- 4.3 Options
-
- General options can be set from the opions block:
-
- options {
- time START, STOP
- background [<GRADIENT>] color BACKGROUNDCOLOR
- depth DEPTH
- iterations NUMBEROFFRAMES
- tolerance TOL
- antialias WIDTH
- cutoff TRESHOLD
- }
-
- START and STOP specify the time interval in which the scene takes
- place: this is used with the speed<> vector from the object
- declaration. <GRADIENT> specifies in which direction the gradient
- of the background color should be, and BACKGROUNDCOLOR is the color to
- use. If you don't want the gradient coloring, then use
-
- background color BACKGROUNDCOLOR.
-
- DEPTH is the maximum recursion depth.
-
- NUMBEROFFRAMES is the number of eyerays per pixel. If you want to use
- antialiasing, set iterations to a value greater than 1. This should
- also be done if you want to use distributed raytracing (If you are not
- familiar with this technique read section 11 of this document)
-
- TOL is the minimum intersection distance: any intersection that is
- closer than TOL to the ray origin is ignored. By default it is 1e-5,
- and normally you could make it as small as 1e-10. With certain shapes
- (notably high order surfaces, such as toruses), this needs to be
- bigger, otherwise numerical inaccuracies will find the intersection at
- x = t*dir + pos with t smaller than TOL. These are the intersections
- that should have t = 0. These intersections cause "phantom" shadows
- and digital zits.
-
- If you want to do antialiasing, use "antialias WIDTH". This makes
- Rayce do Monte Carlo anti aliasing: Rayce will sample the rays within
- WIDTH times the pixelsize, using a Gaussian distribution. If antialias
- is not give, Rayce will use 1-(1/samples) as the antialias width.
-
- This should be done using a grid, I haven't implemented it (yet).
-
- Adaptive depth control is done by specifying a cutoff THRESHOLD. If a
- ray would contribute less than a TRESHOLD fraction of the color
- written to the output, then the ray is not traced. This is called
- adaptive depth cutoff or adaptive depth control.
-
-
- 4.4 PRIMITIVE SHAPES
-
- Rayce supports the following primitives:
-
- 4.4.1. The sphere
-
- a sphere specified this way:
-
- sphere { <CENTER>, RADIUS }
-
- Here, CENTER is a vector, and RADIUS a float. The sphere is a special
- kind of quadric, and it is about 60% faster, see speedtst.r for some
- info.
-
- You might expect a better performance of the sphere in comparison to
- the quadric. I guess, that's because I didn't use vector operations
- in quadric.c; instead I directly calculated the quadratic equation in
- t. See quadric.c if you don't understand what I just typed. (or you
- might just as well forget it :)
-
-
- 4.4.2. Polygon
-
- You can make polygons in this way:
-
- polygon { <P1>, <P2>, .. }
-
- <P1>, <P2>,... are the vertices of the polygon.
-
- Convex polygons will render a lot faster.
-
- 4.4.3. Quadric
-
- A quadric shape is a curve, which is described in this way: it is a set
- Q, with
-
- Q = { (x,y,z) in R^3 | Phi(x,y,z) = 0 }
-
- In which Phi is
-
- Phi(x,y,z) = ax^2 + by^2 + cz^2 + dxy + eyz + fzx +
- gx + hy + iz + j = 0
-
- or, more casually said: a quadric consists of points x,y,z for which
-
- ax^2 + by^2 + cz^2 + dxy + eyz + fzx + gx
- + hy + iz + j = 0
-
- If you'd take a = b = c =1, j = -1, and d,e,f, .. = 0, Q forms a
- sphere, center in (0,0,0), and radius 1. The quadric is specified in
- same fashion as in PoV:
-
- quadric { <COEFF1>, <COEFF2>, <COEFF>, CONST }
-
- The coefficients (a,b,c) form <COEFF1>, (c,d,e) <COEFF2>, (f,g,h)
- <COEFF3>, all of which are vectors. The constant j is CONST. You
- could also use an "algebraic" for specifying a quadric, but this is
- faster.
-
-
- 4.4.4. The Plane
-
- The plane is a shape mathematically defined by
-
- P = { X in R^3 | X.n = a }
-
- Here, X.n denotes the dot vector product of the normal n, and X. In
- Rayce and PoV it is usually defined by
-
- plane { <NORMAL>, A }
-
- NORMAL is the normalvector to the plane, and A the distance in which
- it is moved along the normalvector. Note that the normal isn't
- normalised (which sounds quite funny if you read it aloud :-) The
- reason for this is that it isn't normalised in PoV either.... For the
- best results, always use a vector with length 1.
-
-
- 4.4.5. The Box
-
- A box is CSG intersection of six planes. You should specify it
- using
-
- box { <POINT>, <OPPOSITE_POINT> }
-
- both POINT and OPPOSITE_POINT are vectors which correspond to two
- opposite corners of the box you want Rayce to produce. The box has
- it's planes along the X, Y and Z axis. The order of the points
- doesn't matter, so
-
- box { <-1, 0, 0 >, <1, 1, 1> }
-
- and
-
- box { <1, 0, 1>, <-1, 1, 0> }
-
- should look the same. A box can be transformed in the usual ways.
- Rotating it will slow down tracing a bit, though.
-
-
- 4.4.6. Light source
-
- Lightsources are cause for diffuse and specular illumination, the
- things that make those nice shadows and highlights. Use them in this
- way
-
- light_source {
- <ORIGIN> color LIGHTCOLOR
- [light_modifiers]
- }
-
- The ORIGIN and LIGHTCOLOR are mandatory parts; they tell Rayce the
- point from which point lightrays emanate and their color (actually,
- shadow rays are directed to the light_source, but you knew that,
- right?). Light sources in Rayce cannot be seen,
- intersect_lightsource() always returns FALSE.
-
- These are the allowed light_modifiers:
-
- attenuation FALLOFFEXPONENT
- radius RADIUS
-
- If you're interested: the intensity I is calculated using
-
-
- I = (1/r)^FALLOFFEXPONENT
-
- Here r denotes the distance to the light source.
-
- FALLOFFEXPONENT is the exponent to use for fading light: in real life,
- the intensity of light diminishes with the distance; the intensity is
- proportional to 1/r^2, so in real life the FALLOFFEXPONENT is 2.
- Light in Rayce will diminsh with 1/r^FALLOFFEXPONENT. By default it
- is 0, i.e. the intensity does not depend on the distance from the
- light source.
-
- Rayce can do penumbra (soft shadows) as well. Use RADIUS to specify
- the radius of a discshaped lightsource.
-
-
- 4.4.7. Triangle
-
- A triangle is specified this way:
-
- triangle { <P1>, <P2>, <P3> }
-
- P1, P2 and P3 are the points of the triangle, and the order in which
- the points are specified points does not matter. No backface culling
- is done, and these are ordinary triangles, i.e. no normal
- interpolation is done.
-
-
- 4.4.8. Smooth triangle.
-
- A triangle with interpolated normal vectors is represented in this
- way:
-
- smooth_triangle { <P1>, <N1>, <P2>, <N2>, <P3>, <N3> }
-
- <P?> are the the vertices, and <N?> the normals at these vertices.
-
-
- 4.4.9. Torus
-
- A torus is a shape that looks like a donut. If you want to make a
- torus, then use:
-
- torus { MAJOR, MINOR }
-
- MAJOR is the major radius, and MINOR is the minor radius. The torus
- produced lies in the XZ plane, so you have to rotate it if you want
- another direction. Technically speaking, a torus is a circle in the
- XZ plane with radius MINOR and center <MAJOR, 0, 0>, swept around the Z
- axis.
-
- Don't try to use bounding shapes on toruses. The torus is already
- enclosed in an intersection of a minimal bounding sphere and two
- planes.
-
- A torus is a quartic surface. Among others, this means that a torus
- can at most have 4 intersections with a ray. For calculating these
- intersections, by default, a technique known as Ferrari's method is
- used.
-
- Although this technique is relatively fast, it can give surface acne
- because of numerical inaccuracies. This is sometimes called "digital
- zits", black dots -- try a zoomed in version of the papercl.r with
- tolerance 1e-5, and no "sturm" keywords.
-
- If this happens to you, then try adding the keyword "sturm" after the
- definition. A different method --Sturm sequences-- for calculating
- intersections will be used, which is slower, but more accurate.
- Alternatively you can set SHADOW_TOLERANCE (see OPTIONS) higher, eg
- 0.05. This won't make the calculations more exact, but it will take
- away most of the phantom shadows.
-
-
- 4.4.10. High order surfaces.
-
- You can model arbitrary algebraic (polynomial) surfaces using Rayce.
- Anything is allowed, as long as the order is less than 12 (if you'd
- like more, then you'll have to recompile; change MAX_ORDER in ray.h to
- suit your needs).
-
- The algebraic surface S is determined by a polynomial Phi. The surface
- is the set S for which
-
- S = { (x,y,z) | Phi(x,y,z) = 0 }
-
- In Rayce you get such a surface by defining Phi(), or specifying
-
- Psi(x,y,z) = Chi(x,y,z)
-
- Which means that
-
- Phi = Psi - Chi.
-
- so Phi is a polynomial in x,y and z. You can perform the following
- operations on x,y and z to form new polynomials:
-
- addition x + y + 83
- substraction x - z - 83
- exponentation y ^ 4
- multiplication 5 * x * y
- grouping (x+y)^2
-
- Notice that only floating point numbers are allowed, and no
- expressions. Example:
-
- $ 1 + 2 $ // ok, we're adding the polynomials 1 and 2
- $ (x,y) $ // WRONG, (x,y) is a float-expression not a
- // float
- $ 1*x $ // ok
- $ 1/2 $ // WRONG, you can't divide polynomials (not
- // even 1 and 2
-
- If you want to use expressions, then use declared floating point
- constants. Example:
-
- #declare R = 1.0
- #declare r = R/2
- #declare mytorus = algebraic {
- $ (x^2 + y^2 + z^2 + R^2 - r^2)^2 = 4*R*(x^2+y^2) $
- closed
- }
-
- In the above, mytorus is declared a torus with minor radius 0.5, and
- major radius 1.0. The "closed" keyword is for speeding up
- inside/outside calculations, and the rootfinder is the ordinary
- Ferrari rootfinder.
-
- Example:
-
- algebraic { $ x^4 + y^4 + z^4 -1 $ closed sturm }
-
- should specify a closed finite surface (in this case a superquadric; a
- cube with rounded corners), and it is to be calculated using Sturm
- sequences.
-
- Since an algebraic is stored in terms of operations,
-
- algebraic { $ (x-1)^2 + y^2 - 1 $ }
-
- is calculated differently from
-
- algebraic { $ (x^2 -2*x + 1) + y^2 - 1 $ }
-
- The latter requires more operations, thus it is more expensive. Try to
- make your formula as compact and efficient as possible.
-
-
- 4.4.12. Cylinder
-
- You can make a cylinder between <P1> and <P2> having radius R by
- inserting
-
- cylinder { <P1>, <P2>, R }
-
- This isn't really a primitive. If Rayce encounters a cylinder
- definition in its input, then it is converted to an extrusion of a
- sphere with radius R.
-
-
- 4.4.13. Superquadric
-
- A superquadric is a generalized sphere. A n-dimensional sphere is
- defined by
-
- || X || = 1 (p >= 1) X in R^n
-
- Here, || . || is the Euclidian norm: ||X|| = sqrt(x_1^2 + x_2 ^2 +
- .. + x_n^2). This norm can be generalized to the p-norm defined by
-
- (|x_1|^p + |x_2|^p + ... + |x_n|^p)^(1/p) = 1
-
- If we consider 3D space, then n = 3, and the p-norm is
-
- ||X||_p = (|x|^p + |y|^p + |z|^p)^(1/p)
-
- So a sphere in the p-norm is
-
- ||X||_p = 1
-
- or
-
- (|x|^p + |y|^p + |z|^p)^(1/p) = 1
-
- since 1^p = 1, this is equivalent to
-
- |x|^p + |y|^p + |z|^p = 1
-
- if p is large, then this forms a cube, with faces parallel to the axes
- and rounded corners.
-
- if p = 1, it's a cube with corners in <0,0,1>, <1,0,0>, <-1,0,0>
- etc.
-
- if p = 2, it's a sphere.
-
- This is how you define such a primitive in rayce:
-
- superq { <p> }
-
- NB. If p < 1, then you still get a shape, but since it will then not be
- convex anymore, an intersection algorithm would be harder; It will
- probably not work, if you try
-
- superq { <0.5> }
-
- You probably won't get a good render.
-
- In rayce the previous is generalized. The algorithm for computing
- intersections with superquadrics works for arbitrary shapes
-
- C1(x) + C2(y) + C3(z) = 1
-
- If C1,C2 and C3 are convex functions. So in rayce, you can also render
- elements from this class of shapes:
-
- |x|^p1 + |y|^p2 + |z|^p3 = 1
-
- where p1, p2 and p3 are all greater than 1. This is how you specify it.
-
- superq { <p1, p2, p3> }
-
- See superq.tex, an article on superquadrics, which should be included.
-
-
- 4.4.13. Discs
-
- Discs are round shaped pieces of a flat planes, they could be
- simulated with a plane clipped by a sphere, but they have been put in
- on special request from Shawn McHorse. Syntax:
-
- disc { <CENTER>, <NORMAL>, Rad }
-
- The above is a simple disc
-
- disc { <CENTER>, <NORMAL>, Majrad, minrad }
-
- This is a disc with a hole in the center.
-
- 4.4.14. Transformations
-
- * All primitives may transformed using scale<>, rotate<> and
- translate<>.
-
- * Every shape can have it's own private texture.
-
- * Every shape which has a proper inside and outside defined, can be
- inverted using "inverse" (see below).
-
-
-
- 4.5 NON-PRIMITIVE SHAPES
-
-
- 4.5.1. Union
-
- Union is a CSG operation, it merges two shapes into one. Syntax:
-
- union {
- CSGSHAPE
- [CSGSHAPE]
- [CSGSHAPE]
- [.. etc]
- [inverse]
- }
-
- The "inverse" flips a shape inside out. Check out the mathematics
- section below for details.
-
- Note that Rayce has a real union. That is, if you do
-
- union {
- sphere { <0, 0, 0>, 1 }
- sphere { <0, 0, 1>, 1 }
- }
-
- the interior walls are removed: if you are standing in the the first
- sphere, facing the second sphere, you can actually look inside the
- second sphere.
-
-
- 4.5.2. Intersection
-
- Intersection is another CSG operation. If you do an intersection of N
- shapes, then only points that are contained in all N shapes
- simultaneously, are part of the intersection.
-
- Actually, you can only see the boundary of this intersection. An
- intersection looks like this:
-
- intersection {
- CSG_items
- }
-
- CSG_item is one the following shapes:
-
- sphere
- quadric
- plane
- box
- intersection
- union
- torus
- algebraic
- extrusion (make sure it's closed! )
- cylinder (idem ditto)
- superquadric
-
-
- or it is a
-
- transformation
- inverse statement
- texture block
-
-
- [Mathematics follows, so don't read it, unless you are interested. :]
-
- The shapes mentioned above are special, because their boundaries are
- special.
-
- [intermezzo]
-
- In mathematics, these boundaries are usually called "frontiers".
- These are the points which can be reached from both a set and its
- complement. More exactly speaking, the frontier of a set S, usually
- denoted by dS is the following:
-
- dS consists of points P, for which the following holds: For every P,
- one can find a sequence a1,a2, ... which converges to P, and lies
- Entirely in S, and one can find another sequence b1, b2, ... which
- also converges to P, but lies completely outside S.
-
- More casually said: one can reach a point of dS by walking via points
- in S, and by walking via points outside of S.
-
- [Back to the computers and the special boundaries.]
-
- The above mentioned surfaces (sphere, quadric etc...) have
- following properties:
-
- I. They divide the whole of 3D space into two distinct pieces (sets):
- an "inside" and an "outside". Every point lies either inside or
- outside the shape. Theoretically, a point could be on the frontier of
- the inside and outside, i.e. on the surface itself. Due to numerical
- inaccuracies and implementation, this will happen next to never.
-
-
- [sideway]
- [Of every ray tested agains a CSG, only
-
- origin + 2*tolerance * direction
-
- is tested for inside/outside. So if you want to create quirky images,
- make sure you have intersections with CSG parts at distances d with
-
- tolerance < d < 2*tolerance.
-
- (So be warned! :-)
-
- Some special primitives, like the torus or the sphere, don't need this
- testing: if a ray intersects the shape an even number of times, then
- the rays origin lies outside the shape, if the ray has an odd number
- of intersections, then it's origin is inside.
- ]
-
- II. If you would walk along a ray, changing inside/outside of a shape
- happens if and only if the ray hits the surface.
-
- Other CSG algorithms can also use triangles and rings for CSG, but this
- one cannot, because a triangle fails property II.
-
- The inside/outside for various shapes is determined using the following
- criteria:
-
- Sphere:
- The inside of a sphere are the points X with
-
- distance(X, center) < radius
-
-
- Box:
- For a box, the inside is collection of points (x,y,z) which satisfy
-
- MaxX < x < MaxX
- MaxY < y < MaxY
- MaxZ < z < MaxZ
-
-
- Torus:
- The inside of a torus (donut) is the part where the jelly usually resides.
-
- The above shapes all have finite insides. In jargon, you'd say that
- they are closed curves. The plane is somewhat different:
-
- Plane:
- The outside of a plane is the part which is on the "side of the normal".
- Symbolically: X is inside the plane if
-
- X.n < a
-
- See the section on planes. This means, that both the inside, and the
- outside are infinite.
-
- Quadrics:
- For a quadric, the inside are points (x,y,z) with
-
- Phi(x,y,z) < 0.
-
- see the section on quadrics.
-
- Algebraic:
- An algebraic is specified by a polynomial p(x,y,z). A point is inside
- if p(x,y,z) < 0.
-
- Intersection:
- A point is inside a CSG intersection of shapes S1, S2, etc if and only
- if the point is inside S1, and S2, and S3 and etc.
-
- Union:
- A point is contained in the inside of a CSG union of S1, S2,
- etc. if and only if the point is inside at least one of S1, S2, etc.
-
- The "inverse" keyword flips a shape: the inside of
-
- B = shape { A inverse }
-
- has all points which are outside of A, and the inside of B has all
- points which are outside of A. Mathematically speaking, taking the
- inverse of a shape, is equivalent to taking the complement of the set,
- formed by a shape.
-
- It is legal to transform CSGs. In effect, you are then transforming all
- components of the CSG.
-
-
- 4.4.11. Extrusion
-
- You can extrude surfaces with rayce: Say, you'd want to make a column
- for use in a roman temple.
-
-
- extrusion {
- HEIGHT
- shape { ... }
- }
-
- This takes a shape, and extends the intersection of the shape with the
- XY plane to the Z-direction. Your extrusion will have height HEIGHT.
- HEIGHT should be bigger than 0. For instance, if you have defined the
- projection of a cogwheel on the XY plane, then you could make a 3d object
- out of it by specifying
-
- extrusion {
- 1 intersection { cogwheel }
- }
-
- NB. This is not the same as Polyray's sweep. Polyray only extrudes
- polygonal objects.
-
-
-
- 4.5.4 TRANSFORMATIONS
-
- * You can transform a nonprimitive shape using translate<>, rotate<>,
- scale<>: the composite is transformed. This means that it's bounding
- shape is transformed, and it's objects and composites are transformed.
-
- * Translation, rotation and scaling will only affect a CSG as far as
- it has been specified. For more information, look at the definition of
- hexagon in shapes.inc.
-
- * All nonprimitive shapes (composites, CSG) can have their own
- texture. In PoV, only objects contained in a composite could have a
- texture
-
-
- 4.6 TEXTURES
-
- Rayce's textures have more freedom than PoV's: every surface
- characteristic can have it's own color. Although this isn't
- realistic, it can give nice effects. I haven't implemented procedural
- textures yet, so checker- or marbletextures are not possible. For now,
- use an imagemap.
-
- Textures have the following syntax:
-
- texture {
- [texture_modifiers]
- }
-
- A texture_modifier is one of the following:
-
- ambient AMBCOLOR
-
- the ambient color. It defaults to black.
-
- diffuse DIFFCOLOR
-
- diffuse color, black by default.
-
- specular SPECCOLOR
-
- This is the specular color. In PoV this is always White. (NB I've
- just found out, that this is not the PoV specular, but that these are
- Phong highlights)
-
- reflection REFLCOLOR
-
- makes the surface reflect an AMOUNT part of the light, and it uses a
- REFLCOLOR filter. default: no reflection.
-
- refraction REFRCOLOR
-
- makes the surface refract a REFRCOLOR part of the light. Default:
- black, no reflection.
-
- You can also use
-
- specular AMOUNT
-
- This scales the specular color by AMOUNT. The same can be done for the
- other colors:
-
- ambient AMOUNT
- diffuse AMOUNT
- reflection AMOUNT
- refraction AMOUNT
-
-
- roughness ROUGHNESS
-
- This is PoV's roughness factor. It defaults to 0.0. (actually, PoV's
- 1/phong)
-
- ior IOR
-
- Index of Refrection, default: 1.0
-
- refract_angle ANGLE
-
- maximum deviation for refracted rays. This causes blurred refraction.
-
- reflect_angle ANGLE
-
- maximum deviation for reflected rays. This causes blurred reflection.
-
- For PoV compatibility you can also specify
-
- color COLOR
-
- This sets all colors (refraction, reflection, diff, ambient, specular)
- to COLOR, and the intensities to the default values used by PoV.
- (ambient 0.2, diffuse 0.6 etc.) From then on, these work PoV
- compatible:
-
- You can also use
-
- specular AMOUNT
-
- This scales the specular color by AMOUNT. The same can be done for the
- other colors:
-
- specular AMOUNT
- ambient AMOUNT
- diffuse AMOUNT
- reflection AMOUNT
- refraction AMOUNT
-
-
- You can specify an imagemap: this is the syntax:
-
- image_map { FILETYPE FILENAME [map_type TYPE] [uvswap] [uvrange
- UR, VR] [uvoffset UO, VO] [once] [interpolate INTTYPE] }
-
- This maps the file FILENAME onto the shape. FILETYPE is the type of
- the image which is in FILENAME. The following types for FILETYPE are supported:
-
- "tga" for Targa 24 bit uncompressed type 2 (the same type Rayce outputs)
- "gif" for a standard gif file.
-
- map_type tells how the image should be wrapped around the object.
- TYPE is one the following:
-
- 0 maps the image onto the XY plane
- 1 maps the image onto sphere centered in (0,0,0)
- 2 maps the image onto cylinder along the Z axis.
- 3 maps the image onto a torus lying in the XZ plane,
- radius 1.0
-
- uvswap swaps the u and v parameters. This is identical to rotating the
- bitmap 90 degrees.
-
- uvrange scales the bitmap down by UR, VR, ie.
-
- image_map { "marijke.gif" map_type 3 uvrange 2 2 }
-
- will cause "marijke.gif" to be shrunk, until it fits 4 times on a
- torus (two times along the big equator, two times along the small one)
-
- uvoffset translates the image by UO, VO.
-
- if "once" is set, then the image can be seen only once.
-
- If you specify "interpolate" then interpolation is turned on. For PoV
- compatibity, the interpolations should be followed by a integer, 0 for
- no interpolation (default), something else for interpolation. The
- interpolation is bilinear, anything else is not supported.
-
- The color of an imagemap at (x,y,z) in R^3 is computed as follows:
-
- 1. First find u and v for the desired image.
- 2. Swap u and v if uvswap is set.
- 3. Scale: u = u*UR, v = v*VR
- 4. Translate: u = u + UO, v = v + VO
- 5. Determine color:
- a. if (once) and not (0.0 <= u,v <= 1.0) then return black.
- b. Get color at (u,v) in the image. If interpolation is
- turned on, then interpolate colors, else round the u,v
- coordinates and use that coordinate
-
-
- Textures can be scaled, rotated and translated.
-
-
-
- 4.7 TEXTURE HIERARCHY
-
- A texture block which contains the object's texture. If an object
- doesn't have a texture, then Rayce uses the texture of its father.
- Objects in Rayce have a hierarchy.
-
-
- #declare C = union {
- A
- B
- }
- union { C }
-
- In this example, A and B are children of C, and C is a child of the
- whole scene. If Rayce registers a hit with primitive A, then it first
- looks at A's texture. If A doesn't have a texture, Rayce checks C for
- a texture. If C doesn't have a texture, then the Rayce checks C's
- daddy. C's daddy is the whole scene, and the whole scene always has a
- texture, the default texture.
-
- You can change the texture by putting this in your input file:
-
- default = texture { TEXT }
-
- This will make TEXT the default texture. Take a look at hier.r for an
- example of hierarchic textures.
-
-
- 4.8.1 OBJECTS
-
- In Rayce, objects are specified in this manner:
-
- SHAPENAME {
- shape_body
- }
-
- or
-
- object {
- SHAPENAME {
- shape_body
- }
- }
-
-
- SHAPENAME is one of the nine allowed shapes, shape_body the statements
- with info about the shape in it. The difference between these two
- ways of specifying is: you can use speed and bounding shapes with the
- latter.
-
-
- 4.8.2. COMPOSITES
-
- Rayce supports composites as well. A composite collects a bunch of
- shapes, and treats them as one. This makes transforming and handling
- a lot easier. A composite's syntax is the same as PoV's:
-
- composite {
- [OBJECTs|COMPOSITEs]
- }
-
- Example:
-
- composite {
- box { <-1,1,1>, <2,3,4> }
- object { heike }
- composite { Dikkerd }
- }
-
-
- 4.8.3 TRANSFORMATIONS
-
- These transformations on objects and composites are legal:
-
- * texture { }
-
- An object can have a texture.
-
- Example:
-
- object {
- sphere { <0,0,0>, 1 }
- texture { ambient color red 1.0 }
- }
-
- This is equivalent to
-
- sphere {
- <0,0,0>, 1
- texture { ambient color red 1.0 }
- }
-
- * translate <> , rotate<>, scale<>
-
- Translation, rotation and scaling will only affect a CSG as far as it
- has been specified. For more information, look at the definition of
- hexagon in shapes.inc.
-
- * speed <VELOCITY>
-
- This says the composite will have a speed. This is implemented by
- adding SPEEDVECTOR to the speed of each object in the composite.
-
- Note that only the bounding shapes of the noncomposite objects ("the
- leafs in the tree") are moved along. (this is why I actually find this
- motion blur a pain the reet, because it makes all kinds of stuff extra
- complicated). So be careful about your bounding shapes with moving
- objects. For a nice and smooth picture, don't forget to turn the numer
- of frames from the options {} block up.
-
- Note: this motion blur is only linear. Implementing rotational blur is
- very expensive, so I haven't done it.
-
- Example:
-
- object {
- sphere { <0,0,0>, 1 }
- speed <0,0,1>
- }
-
- composite {
- composite { fubar }
- object { fubular }
- bounded_by { box { <-1,-1,-1>,<1,1,1> } }
- speed <0,0,1>
- }
-
- this is not allowed.
-
- sphere {
- <0,0,0>, 1
- speed <0,0,1> // WRONG! syntax error
- }
-
-
- * bounded_by { BOUNDINGSHAPES }
-
- This means that the composite is bounded by BOUNDINGSHAPE. A lot of
- shapes, especially compound shapes, take up a lot of time. To speed
- this up, you can specify bounding shapes: simple shapes that encompass
- a much more complex shape. This bounding shape should be closed; my
- suggestion is to use a sphere or a box, if possible.
-
- If an object has bounding shapes, then all rays are first tested
- against these shapes, in the order which they have been specified. If
- this intersection test fails, or closer intersections have been found
- previously, then the object itself is not tested.
-
- Example:
-
- object {
- algebraic { $ x^4 + y^4 + z^4 - 1 $ }
- bounded_by { box { <-1,-1,-1>,<1,1,1> } }
- }
-
- composite {
- composite { fubar }
- object { fubular }
- bounded_by { box { <-1,-1,-1>,<1,1,1> } }
- }
-
- This is not allowed:
-
- algebraic {
- $ x^4 + y^4 + z^4 - 1 $
- bounded_by { box { <-1,-1,-1>,<1,1,1> } } // WRONG! syntax error
- }
-
-
- * clipped_by { CLIPPINGSHAPES }
-
- The object is clipped by SHAPE. A clipping shape is the Procrustes in
- raytracing: a clipping shape cuts of all parts of an object that stick
- out of the CLIPPINGSHAPES. If you want to use a shape as bounding
- shape and clipping shape simultaneously, then you must use
-
- clipped_by { bounded_by }
-
- Example:
-
- object {
- quadric { Cylinder_X } // now it's infinite
- clipped_by {
- box <-1,-1,-1>, <1,1,1>
- sphere { <0,0,0>, 100 }
- }
- // now it's a tube, and you can look inside.
- }
-
- composite {
- composite { fubar }
- object { fubular }
- bounded_by { box { <-1,-1,-1>,<1,1,1> } }
- clipped_by { bounded_by }
- }
-
-
-
- 4.8 # COMMANDS
-
- If your scene file says:
-
- #include "foobar.inc"
-
- then the parser will act as if the contents of foobar.inc are in the
- place of the #include. The '#' is optional: since the PoV team hasn't
- made it mandatory, all '#' s in the input are treated is whitespace:
- they are ignored. If a file is opened, '[' is shown, and an "operator
- pacification indicator" (.) is printed every 25 lines read, after a
- file has been read ']' is printed.
-
- If you use objects, cameras, etc. a lot, you should declare them for
- the greater benefit of the human race:
-
- #declare foo = object { sphere { <0, 0, 9>, 1 }
-
- means you can use
-
- object { foo }
-
- instead of
-
- object { sphere { <0, 0, 9>, 1 }
-
- These can be declared:
-
- any shape: #declare foo = sphere { .. }
- camera: #declare foo = camera { .. }
- color: #declare foo = color red ....
- texture: #declare foobar = texture { ... }
- vector expressions:
- #declare fub = <0, 1, 0>^<1,0,0>
- floating point expressions:
- #declare blab = 1.34/2
- image_maps: #declare auk = image_map { .. }
-
- You can expect Bad Things to happen if you try something like:
-
- #declare foo = object { sphere { bla } texture { foo } }
-
- If you attempt to save memory, don't use declarations: they only cost
- more memory during the parsing stage. Actually #define would have been
- a better term, but I didn't invent the PoV syntax.
-
-
- 5. COMPILING RAYCE
-
- You can compile Rayce yourself if you want; then you have to get the
- sources to Rayce, which should be available from the same source
- you've got this from. Refer to tech.doc, included with the sources.
-
-
- 7. ME
-
- About the author: I am a student, as of today (Januari 15 '94) I am
- 19, and I study applied mathematics at the Eindhoven University of
- Technology, in the Netherlands. I am in my second year, and I spend
- too little time on my study. Oh well. Raytracing is my hobby. If I
- am not spending my time behind my computer I also play the French horn
- and the piano.
-
- The following have been helpful in developing Rayce:
-
- - the sources to MTV, PoV, Rayshade, Vort, Ray, Graphics Gems
-
- - The fractal.028 and PCGNet Raytracing echo community for
- making me happy with mail.
-
- - "Tutorial: Computer Graphics: Image Synthesis", Kenneth I
- Joy, a.o. ISBN 0-8186-8854-4.
-
- - "Three Dimensional Computer Graphics", Alan Watt, Addison
- Wesley.
-
- - "Advanced Rendering and Animation Techniques", Alan Watt &
- Mark Watt, Addison Wesley.
-
- - Linus Torvaldsen, for creating Linux, an excellent free Unix
- system for the 386/486 PCs. Try it! It's the best thing since
- sliced bread (The next best thing after linux being Rayce, of
- course! :)
-
- If you want something implemented, or if you want to hack something
- yourself: please contact me, so other people can benefit from it too.
- I also appreciate any comment on the Rayce, its sources and its docs.
-
- I hope that all mathematics were understandable, and that my English
- doesn't show that I normally speak Dutch.
-
- Send your compliments, beer, bugreports and daughters to:
-
- Han-Wen Nienhuys
- Dommelseweg 1A
- 5581 VA Waalre
- The Netherlands
-
- But email is preferred for the compliments and bugreports, of course:
-
- hanwen@stack.urc.tue.nl
-
- If you can't find me there, then try my dad's account:
-
- wsadjw@urc.tue.nl
-
- If you are connected to fidonet, then you can reach me at
-
- 2:284/102.27
-
- My PCGNet address is
-
- 9:580/203.56
-
- You could also try post a message to fractal.028, a fidonet graphics
- echo in Holland. I will try to have the latest version of Rayce
- available at
-
- Bennekom BBS: fido node 2:283/203, PCGNet 9:580/203, tel.
- 31-8389-15331. (freqqing times: 07.30 to 01.00, local time)
-
- Bennekom BBS supports V32bis and V42bis. I regularly read the PCGNet
- raytracing echo, and I am subscribed to the DKB-L mailing list.
-
-
- 8. HISTORY AND TODO-list
-
- See the file "history.doc".
-
-
- 9. SYNTAX
-
- Use The Source, Luke!
-
-
- 10. BUGS
-
- Yes.
-
-
-
- But seriously :), I am not a big tester myself. It is very probable
- that Rayce contains bugs.
-
- * Maybe you will see "assert failed file XXX.c, line XXX". These are
- messages you shouldn't ever get to see, they show that some internal
- consistency check failed. If you see this, then please mail a
- bugreport to me.
-
- (On the other hand, if it came from csg.c, you are probably not using
- correct shapes. Make sure extrusions and cylinders are closed, and
- use the "closed" keyword correctly)
-
- * If Rayce crashes, that's obviously subversive behaviour of Rayce.
- Especially if the crashes are violent, you should report them.
-
- * If you find very subtle bugs, I am also very interested. On the
- average, it takes me two new versions before I discover those kind of
- errors. I should do more testing. Yes. I know. But coding is so much
- more fun.
-
- Known bugs:
-
- - Some algebraics don't render correctly. This is probably
- caused by the root finder, which was copied from Vort almost verbatim.
- When I learn numerical methods (in a few months) I'll take another
- look at it.
-
- - Some algebraics have singular points, where there is no
- normal to the surface (the normal is <0,0,0> ). When this happens,
- "NNV # XXX.c" is printed, with line number and the file where it
- happened.
-
- - Some algebraics aren't fun calculate precisely. If you use
- sturm sequences, you will sometimes see solve.c scream if you use the
- runtime warnings turned on (-d4). This happens because the sturm code
- first tries a fast way of calculating a root.
-
- Check out the history.doc on resolved bugs, and stuff that needs to be
- done.
-
-
-
- 11. DISTRIBUTED RAYTRACING.
-
- Detailed information on what distributed ray tracing is can be found
- in the paper by Cook, Porter and Carpenter: "Distributed Ray Tracing",
- ACM Computer Graphics, Vol.18, Num.3, July 1984. [Note: this paper is
- also included in "Image Synthesis"]
-
- [Note: what follows is a interpretation of what I think distributed
- raytracing is, so no garantuee is made that it is correct. ]
-
- Distributed raytracing is a process used to model "fuzzy" phenomena,
- such as soft shadows, focal blur, motion blur, fuzzy reflections and
- fuzzy refractions. In raytracing, refractions usually are crystal
- clear, and and reflections look unrealistically crisp. The shadows
- have sharp edges. Although this is good for generating nifty pictures,
- it is not realistic. In the real life, shadows don't have these sharp
- edges, and you cannot comb your hair using a teaspoon as a mirror.
-
- Let's take a closer look at this spoon. The surface of this spoon is
- scratched and bumped. Indeed, if you would look at the surface through
- a microscope you'd see a pretty wobbly surface. So not all of the
- light falling on the metallic surface will be reflected in the same
- direction.
-
- Since light works bidirectional, this also means that eyerays cast
- onto the surface don't generate one single reflection ray, but a huge
- number of "small" reflection rays, all in slightly different
- directions. The light of a reflection we're searching for is the sum
- of all these tiny contributions from various directions.
-
- Mathematically speaking: the intensity I of the incoming light at a
- point P, is a function of the direction D from which the light is
- coming, and of the location on the surface (P), so
-
- I = I(D, P)
-
- Because the surface is bumped, the light coming from a direction D
- will be reflected in P for percentage dependent on: D, the
- "theoretical" reflection direction R, and the surface normal N at P.
- So the reflection r percentage is:
-
- r (D, N, R)
-
- So what we will be seeing of a reflected light from a certain direction is
-
- r (D, N, R) * I (D)
-
- And the total reflection is the sum of all these tiny bits:
-
- /
- total = | I(D)*r(D,N,R)
- /
- all directions D
-
- Of course in practical situations, this mathematical descriptions
- isn't gonna help us. However, we could aproximate the above integral
- by carefully choosing a few (say 16) directions D, and summing all
- contributions:
-
-
- __
- total = 1/16 \ I(D) * r(D,N,R)
- ~ /_
-
- some directions D
-
-
-
- This is the process which is modeled via "distributed" raytracing:
- instead of one, multiple reflection rays are spawned off the surface
- of our spoon. In effect, we are taking discrete samples of the "real"
- reflection I*r, which is a continuous function.
-
- In rayce: penumbra, and fuzzy refraction is also modelled in this way.
- There is one caveat: If we would spawn N rays at each intersection
- point for determining the fuzzy reflection/refraction/shadow, then we
- would be tracing O((3N)^depth) rays. If we'd have complex scenes,
- rendering would take a really LONG time. So instead rayce shoots a
- fixed number of eyerays. All these eyerays are sampled differently at
- each intersection point (this is called multidimensional sampling.
- Sounds good, huh? :-).
-
- At present, the rays are sampled with a simple random function. This
- will be changed in the future.
-
- Of course, you could do the sampling with 1 eyeray only. But then the
- blur won't be so good since Rayce evaluates the color of the ray with
- only one try. The more samples the better, but if you use a higher
- resolution, then less samples per pixel suffice.
-
- The refl_diffuse and refr_diffuse produce non-sharp reflections and
- refractions. The argument is in degrees. Anything less than 15 or 20
- is good, altough the closer to zero the better you can see it.
-
-
-