home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / graphics / rtnews / rtnv2n8 < prev    next >
Encoding:
Text File  |  1995-05-19  |  18.9 KB  |  347 lines

  1.  _ __                 ______                         _ __
  2. ' )  )                  /                           ' )  )
  3.  /--' __.  __  ,     --/ __  __.  _. o ____  _,      /  / _  , , , _
  4. /  \_(_/|_/ (_/_    (_/ / (_(_/|_(__<_/ / <_(_)_    /  (_</_(_(_/_/_)_
  5.              /                               /|
  6.             '                               |/
  7.  
  8.             "Light Makes Right"
  9.  
  10.             October 27, 1989
  11.                 Volume 2, Number 8
  12.  
  13. Compiled by Eric Haines, 3D/Eye Inc, 2359 Triphammer Rd, Ithaca, NY 14850
  14.     NOTE ADDRESS CHANGE: wrath.cs.cornell.edu!eye!erich
  15.     [distributed by Michael Cohen <m-cohen@cs.utah.edu>, but send
  16.     contributions and subscriptions requests to Eric Haines]
  17. All contents are US copyright (c) 1989 by the individual authors
  18. Archive locations: anonymous FTP at cs.uoregon.edu (128.223.4.1) and at
  19.            freedom.graphics.cornell.edu (128.84.247.85), /pub/RTNews
  20.  
  21. Contents:
  22.     Introduction
  23.     Tracing Tricks, edited by Eric Haines
  24.  
  25. -------------------------------------------------------------------------------
  26.  
  27. Introduction
  28.  
  29.     I've decided to pass on an article published in the SIGGRAPH '89
  30. "Introduction to Ray Tracing" course notes.  It's something of a "best of the
  31. Ray Tracing News" compendium of ideas.  Since the notes are not easy for
  32. everyone to access, and the article probably will not be printed elsewhere, I
  33. thought it worthwhile to reprint here.
  34.  
  35. -------------------------------------------------------------------------------
  36.  
  37. Tracing Tricks, edited by Eric Haines
  38.  
  39. Over the years I have learnt a variety of tricks to increase the performance
  40. and image quality of my ray tracer.  It's almost a cliche that today's
  41. successful trick is tomorrow's established technique.  Photorealistic computer
  42. graphics is, after all, concerned with figuring out shortcuts and
  43. approximations for rendering various physical phenomena, i.e. tricks.
  44.  
  45. For whatever reason, many of the tricks mentioned here are not common
  46. knowledge.  Some have been published (and sometimes overlooked), some have
  47. been discussed informally and have never made it into research papers, and
  48. others seem to have appeared out of nowhere.  It's most likely that there are
  49. tricks that are commonly known that have not percolated over to me yet.
  50.  
  51. When possible, I have tried to give appropriate references or attributions; if
  52. not attributed, the ideas are my own (I think!).  My apologies if I have
  53. overlooked anyone.  Only references that do not appear in the book's "Ray
  54. Tracing Bibliography" are included at the end of this article.  For more
  55. general rendering hacks, see [Whitted85], which originally inspired me to
  56. attempt to pass on some ideas from my bag of tricks.
  57.  
  58.  
  59. Ambient Light
  60.  
  61. One common trick (origins unknown) is to put a light at the eye to do better
  62. ambient lighting.  Normally if a surface is lit by only ambient light, its
  63. shading is pretty crummy.  For example, a non-reflective cube totally in
  64. shadow will have all of its faces shaded the exact same shade.  All edges
  65. disappear and the cube becomes a hexagonal blob.  The light at the eye gives
  66. the cube definition.  Note that a light at the eye does not need shadow
  67. testing:  wherever the eye can see, the light can see, and vice versa.
  68. However, this trick can lead to various artifacts, e.g.  there will always be
  69. a highlight near the center of every specular sphere in the image.
  70.  
  71.  
  72. Efficiency Schemes
  73.  
  74. There are any number of efficiency schemes out there, including Bounding
  75. Volume Hierarchy, Octree, Grid, and 5D Ray Classification.  See Jim Arvo's
  76. section of the book for an excellent overview of all of these.  The most
  77. important conclusion is that any efficiency scheme is better than none.  Even
  78. on the simplest scenes an efficiency scheme will help execution.  For example,
  79. in one test scene with only ten objects, using an efficiency scheme made the
  80. job take only one third the time.  Grid subdivision is probably the quickest
  81. to implement, though the others are not that much harder.
  82.  
  83. While at the University of Utah, John Peterson and Tom Malley actually
  84. implemented Whitted/Rubin, Kay/Kajiya, and an octree scheme, and found that
  85. all three schemes were within 10-20% of each other speedwise.  In an informal
  86. survey at SIGGRAPH '88, the BV Hierarchy, Octree, Grid and 5D schemes all had
  87. about the same number of users (all the 5D users were from Apollo; on the
  88. other hand, 5D is the new kid on the block).
  89.  
  90. There are a number of techniques I have found to be generally useful for all
  91. efficiency schemes.
  92.  
  93. 1) When shadow testing, keep the opaque object (if any) which shadowed each
  94.    light for each ray tree node.  Try this object immediately during the next
  95.    shadow test at that ray tree node.  Odds are that whatever shadowed your
  96.    last intersection point will shadow again.  If the object is hit you can
  97.    immediately stop testing because the light is not seen.  This was first
  98.    published in [Haines86].
  99.  
  100. 2) When shadow testing, save transparent objects for later intersection.  Only
  101.    if no opaque object is hit should the transparent objects be tested.  The
  102.    idea here is to avoid doing work on transparent filters when in fact the
  103.    light does not reach the surface.
  104.  
  105. 3) Don't calculate the normal for each intersection.  Get the normal only
  106.    after all intersection calculations are done and the closest object for
  107.    each node is known.  After all, each ray can have only one intersection
  108.    point and one normal.  Saving intermediate results is worthwhile for some
  109.    intersection calculations, which are then used if the object is actually
  110.    hit.  This idea was first mentioned in [Whitted85].  Similarly, other
  111.    calculations about the surface can be delayed, such as (u,v) location, etc.
  112.  
  113. 4) One other idea (which I have not tested) is sorting each intersection list
  114.    by various criteria.  Most efficiency schemes have in common the idea of
  115.    lists of objects to be tested.  For a given list, the order of testing is
  116.    important.  For example, all else being equal, if a list contained a spline
  117.    surface and a polygon, I would want to test the polygon first since it is
  118.    usually a quicker intersection test.  Given an opaque object and a bounding
  119.    box in a list, I probably want to test the opaque object first when doing
  120.    shadow testing, since I want to find any intersection as soon as possible.
  121.    If two polygons are on the list, I probably want to test the larger one
  122.    first, as it is more likely to cast a shadow or give me a maximum depth
  123.    (see next section).  There are many variations on this theme and at this
  124.    point little work has been done on these possibilities.
  125.  
  126.  
  127. Bounding Volume Hierarchy
  128.  
  129. I have a strong bias towards this scheme since it handles a wide variety of
  130. object sizes, types, and orientations in a robust fashion.  Other schemes will
  131. often be faster, but this scheme has the fewest crippling pathological cases
  132. (e.g. a grid subdivision scheme is useless whenever most of the objects fall
  133. into one grid box).  I favor the automatic bounding volume generation technique
  134. described by [Goldsmith87].
  135.  
  136. I have found a number of tricks to speed up hierarchy traversal, most of which
  137. are simple to implement. Some of the ideas can also be useful for other
  138. efficiency schemes.
  139.  
  140. 1) Keep track of the closest intersection distance.  Whenever an object is
  141.    hit, keep its distance as the maximum distance to search.  During further
  142.    intersection testing use this distance to cut short the intersection
  143.    calculations:  if an object or bounding box is beyond the maximum distance,
  144.    no further testing of it needs to be done.  Note that for shadow testing
  145.    the distance to the light provides an initial maximum.
  146.  
  147. 2) When building a ray intersection tree, keep the ray tree which was
  148.    previously built.  For each ray tree node, intersect the object in the old
  149.    ray tree, then proceed to intersect the bounding box/object tree.  By
  150.    intersecting the old object first you can usually obtain a good maximum
  151.    distance immediately, which can then be used to aid trick #1.
  152.  
  153. 3) When shooting rays from a surface (e.g.  reflection, refraction, or shadow
  154.    rays), get the initial list of objects to intersect from the bounding
  155.    volume hierarchy.  For example, a ray beginning on a sphere must hit the
  156.    sphere's bounding volume, so include all other objects in this bounding
  157.    volume in the immediate test list.  The bounding volume which is the parent
  158.    of the sphere's bounding volume must also automatically be hit, and its
  159.    other children should automatically be added to the test list, and so on up
  160.    the object tree.  Note also that this list can be calculated once for any
  161.    object, and so could be created and kept around under a least-recently-used
  162.    storage scheme.  Another advantage of this scheme is that nearby neighbors
  163.    of the object are tested for shadowing first.  These neighbors are more
  164.    likely to cast a shadow on the point than any random object.  I first saw
  165.    this trick used in Weghorst and Hooper's ray tracer at Cornell's Program of
  166.    Computer Graphics.
  167.  
  168. 4) Similar to trick #3, the idea is simply to do the same list making process
  169.    for the eye position.  Check if the eye position is inside the topmost node
  170.    of the hierarchy.  If it is, check the children which are boxes.  Continue
  171.    to check and unwrap until you are left with a list of objects to intersect.
  172.    Again, the idea is to avoid wasting time shooting a ray against boxes which
  173.    you know must be hit.
  174.  
  175.    For light sources, since the farthest endpoint of the ray is also known, it
  176.    can also be used to open some boxes early on.  The tradeoff here, however,
  177.    is that for shadow testing we want to find any intersection we can.
  178.    Wasting time opening boxes near the light or ray origin might be better
  179.    spent trying to find an intersection as fast as possible.
  180.  
  181. 5) An improvement to trick #3 is also to use trick #4 to open more boxes
  182.    initially.  You work up the hierarchy opening all parent boxes; any
  183.    children of the parent (except the original one, of course) are then tested
  184.    against the ray position.  However, this can be done only when the trick is
  185.    done on the fly, since the ray's origin will change.
  186.  
  187. Kay & Kajiya's hierarchy scheme [Kay86] is about the best overall traversal
  188. method.  However, Jeff Goldsmith and others note that if you do use Kay &
  189. Kajiya's heapsort on bounding volumes in order to get the closest, don't
  190. bother to do it for illumination rays.  In shadowing, you don't care about the
  191. closest intersection, but just whether anything blocks the light.
  192.  
  193.  
  194. Octree
  195.  
  196. There are a few tips on accessing and moving through the octree.  Olin Lathrop
  197. and others have pointed out that there is a faster method than Glassner's
  198. hashing scheme for finding which octree voxel contains a point.  Quickest is
  199. to simply transform the point into the octree's (0,0,0) to (1,1,1) space.  Say
  200. you allow your octree a maximum of eight levels.  This means you'll want to
  201. convert from world coordinates to eight bits in X, Y, and Z.  For example, if
  202. the octree box went from 3.0 to 6.0 along the X axis in world space, you would
  203. convert 5.25 into the binary fraction 0.11000000 (which is equal to 0.75
  204. decimal, which is where 5.25 lies between 3.0 and 6.0).  The most significant
  205. bit of each binary fraction for each coordinate is then combined and used to
  206. access the correct topmost octree voxel (i.e. 0 through 7, similar to
  207. Glassners' scheme).  The next-most significant three bits are then stripped
  208. off, and the corresponding subordinate octree voxel is accessed, on down until
  209. a leaf voxel is found.
  210.  
  211. In practice, each octree voxel notes whether it is a parent of further voxels
  212. or is a leaf and contains a list of objects to hit.  If it is a parent, it
  213. stores a list of 8 pointers to its subordinate octrees, with null pointers
  214. meaning that the subordinate octree is empty; otherwise, a list of objects is
  215. used.
  216.  
  217. One problem with building octrees is deciding when enough is enough.  You want
  218. to subdivide an octree voxel if the number of objects is too many, but you may
  219. find that these further subdivisions do not gain you anything.  Olin Lathrop
  220. has an interesting method for octree subdivision.  First, the biggest win is
  221. to subdivide on the fly.  Never subdivide anything until you find there is a
  222. demand for it (this same idea was used by Arvo and Kirk [Arvo87] in their 5D
  223. efficiency scheme).  His subdivision criteria are, in order of precedence:
  224.  
  225. 1) Do not subdivide if subdivision generation limit is hit.
  226.  
  227. 2) Do not subdivide if a voxel contains less than X objects (These first two
  228.    criteria were first proposed in [Glassner84]).  Olin uses X=1.
  229.  
  230. 3) Do not subdivide if less than N rays passed through this voxel, but did not
  231.    hit anything.  Olin uses N=4.
  232.  
  233. 4) Do not subdivide if M*K >= N, where M is the number of rays that passed
  234.    through this voxel that did hit something, and K is a parameter you chose.
  235.    Olin uses K=2, but suspects it should be higher.  This step seeks to avoid
  236.    subdividing a voxel that may be large, but has a good history of producing
  237.    real intersections anyway.  Keep in mind that for every ray that did hit
  238.    something, there are probably shadow test rays that did not hit anything.
  239.    This can distort the statistics, and make a voxel appear less "tight" than
  240.    it really is, hence the need for larger values of K.
  241.  
  242. Another possible criterion is to base the subdivision generation limit
  243. (criterion 1) on the number of objects in the octree.  If you had, say, 6
  244. objects and 5 of them are clustered tightly together, you may find your octree
  245. reaching its maximum depth without the subordinate octrees actually splitting
  246. up the 5 objects.  These octree voxels are useless, costing extra time and
  247. memory.  They could be avoid by setting the limit based on the total number of
  248. objects.  I use something along the lines of the depth limit being equal to
  249. log sub 4 of (number of objects).
  250.  
  251. Andrew Glassner has a better method to avoid this problem.  When you subdivide
  252. a voxel, look at its children.  If only one child is non-empty, replace the
  253. original voxel with its non-null child.  Do this recursively until the
  254. subdivision criterion is satisfied.  He does this in his spacetime ray tracer,
  255. and the speedup can be large.  Note that this scheme means adding a field to
  256. the octree structure to identify what level in the hierarchy it represents.
  257.  
  258. An idea to speed octree traversal was first mentioned to me by Andrew Glassner
  259. and later by Mike Kaplan.  The idea is to place a pointer on each face of each
  260. octree voxel.  If a voxel's face is next to a larger or same size voxel, a
  261. pointer to this neighbor is stored.  If the voxel face's neighbors are
  262. smaller, then the face pointer is set to point at the bordering voxel of the
  263. same size (which is these neighbors' common parent).  If there are no
  264. neighbors (i.e. the face is on the exterior), a null pointer is stored.
  265.  
  266. When a ray exits a voxel, the voxel face is accessed and the next voxel found
  267. directly.  This voxel may have to be descended, but this trick saves having to
  268. descend the octree from the top.
  269.  
  270. Mike Kaplan independently arrived at a similar method, in which he stores
  271. quadtrees at the faces so that he can immediately access the next voxel and
  272. avoid any descent altogether.
  273.  
  274.  
  275. Bounding Box Intersection
  276.  
  277. The fastest method in general is Kay and Kajiya's slab intersection method
  278. [Kay86].  As they point out, precompute as much as you can for the ray, i.e.
  279. check whether the ray is parallel to any of the axes, and for whichever axes
  280. it is not, computing the multiplicative inverse of the ray direction vector.
  281. However, there are other tests which can actually improve the performance of
  282. the box intersector.  For example, I have found that for my particular ray
  283. tracer, if we first do a quick inside-outside test with the ray origin and the
  284. box, the overall box intersection time goes down (for a related trick, which
  285. is something of a preprocess version of this method, see #4 under "Bounding
  286. Volume Hierarchy").
  287.  
  288.  
  289. Spline Surface Intersection
  290.  
  291. There are three camps on this question:  the numerical analysts, the polygon
  292. meshers, and the synthesists (who do a little of each).  The following
  293. comments are distilled from John Peterson's thoughts on the subject.  The
  294. analytic methods are often slow, and there are many nightmares involved in
  295. finding roots of two equations (see section 9.6 of [Press86]).  To find the
  296. quadrilaterals, John recommends subdividing the surfaces by using the Oslo
  297. Algorithm, due to its generality [Bartels87, Sweeney86].  Easiest to implement
  298. is simply subdividing the surface by a given step size, then ray tracing the
  299. mesh of polygons produced (throwing these polygons into an octree or grid
  300. efficiency scheme is recommended).  Another method is to use adaptive
  301. subdivision with a quadtree structure, checking a flatness criteria to see
  302. whether a given quadrilateral should be subdivided into four
  303. sub-quadrilaterals.
  304.  
  305. Peterson's subdivision criterion is to use a bounding box around each quad
  306. generated, subdividing until the box is smaller than a certain number of
  307. pixels.  A drawback of this method is that it does not elegantly handle
  308. objects that are part of the scene yet do not appear in the viewing frustum
  309. (e.g.  if the teapot is only seen in a mirror, we cannot get a good sense of
  310. how much to subdivide it).  Snyder and Barr [Snyder87] have some good
  311. recommendations on this process, and they use the change in the tangent vector
  312. between the quad's points as a subdivision criterion.  This article also
  313. points out other pitfalls of tessellation and of rendering polygons with a
  314. normal at each vertex.
  315.  
  316. If adaptive techniques are used, one problem to guard against is cracking.
  317. Say there are two adjacent quadrilaterals, and one has been subdivided into
  318. four smaller quads.  Something must be done along the seam between the two
  319. large quadrilaterals, as normally the subdivision point between the two common
  320. vertices will not lie on the large, undivided quad.  If rendered from some
  321. angle, there will be a noticeable crack between the large quad and the two
  322. neighboring smaller quads.
  323.  
  324.  
  325. Acknowledgements
  326.  
  327. This article owes a large debt to Andrew Glassner, who began "The Ray Tracing
  328. News," an informal journal for ray tracing researchers to share ideas.  He has
  329. kept the hardcopy version moving along, while I have had the pleasure of
  330. running the electronic edition.  Most of the ideas given a personal
  331. attribution in this article are from contributions to the "News", and I thank
  332. all those who have contributed to it over the years.  Finally, my thanks to
  333. Kells Elmquist and Andrew Glassner for their comments on this paper.
  334.  
  335.  
  336. Bibliography
  337.  
  338. [Bartels87] Bartels, Richard H., John C.  Beatty, Brian A.  Barsky, An
  339. Introduction to Splines for Use in Computer Graphics, Morgan Kaufmann, Los
  340. Altos, California, 1987.
  341.  
  342. [Press88] Press, William H.  et al, Numerical Recipes in C, Cambridge
  343. University Press, Cambridge, 1988.
  344.  
  345. -------------------------------------------------------------------------------
  346. END OF RTNEWS
  347.