Todo list for snogray				-*- mode:org; coding:utf-8 -*-

* TODO Implement better integrators

  "OldInteg" is overly complicated, hard to control, and probably wrong.
  It should be removed once there's a decent replacement.

  * DONE Simple direct integrator

  * DONE Path-tracing integrator

  * TODO Photon-mapping integrator

* TODO Efficient Global Illumination.

  * TODO Photon mapping, as described by Henrik Wann Jensen
    See http://graphics.ucsd.edu/~henrik/papers/ewr7/

  * TODO Instant radiosity

  * TODO Irradiance Caching

* TODO Reorganize the Surface abstraction

  The Surface type currently contains geometry, and a material pointer.

  We would also like to add light information to primitives (see also
  "TODO Make surfaces lights").  Most likely, this means adding a light
  pointer to surfaces (which would usually be NULL).

  Because Surface is the basic object used for search acceleration, and
  meshes contain many, many, surfaces, this means that there's lots of
  space consumed by redundant material pointers, and potentially by NULL
  light pointers, in mesh triangle objects.  [This is especially bad on
  a 64-bit architecture, as each pointer takes 8 bytes!  Even on
  machines with lots of memory, the cache footprint of all those
  pointers is a big problem.]

  To allow expanding information stored in primitives, while reducing
  the size of meshes, we can do:
  
  1. Add a new class Primitive, which is a subclass of Surface

  2. Move the Surface::material field to Primitive::_material

  3. Most primitives (spheres, cylinders, entire meshes, etc), will be
     subclasses of Primitive instead of Surface, but as most external
     users will still refer to Surface, mesh triangles and other special
     cases can just be subclasses of that instead, to save space.

  4. Add a virtual Surface::material() method for getting the material
     for a surface; most rendering primitives will subclasses of
     Primitive, and Primitive::material() will just return its _material
     field directly, but for instance, mesh triangles will look up the
     material in their enclosing data to save space in the triangle
     object.

  5. Add a virtual Surface::light() method for obtaining a surface's
     associated light; like for materials, Primitive will implement this
     via an explicit field and mesh triangles will look it up in the
     parent mesh.

  6. The Intersect constructor will call the surfaces material() and
     light() fields to fill in the Intersect::material and (the new)
     Intersect::light fields.  This is not only for efficiency, but to
     also give, for instance, Instance::IsecInfo::make_intersect a
     chance to replace the light in a new intersection with a globally
     valid light (so the light actually stored in the primitive would
     have to be some sort of proxy light, and the instance would need to
     have a mapping between proxy lights inside that instance and real
     lights outside of it [repeat as necessary for nested instances].

* TODO Allow any surface to be a light

  Currently lights are entirely separate from surfaces, so if a user
  wants to for instance, make a "light bulb", he has to create both a
  sphere-light and add a sphere surface (with a special "glowing"
  material) to the scene at the same point.  Furthemore, there's a
  duplication of knowledge between source files implementing a "foo
  surface" and a "foo light".

  A more convenient way would be for lights to automatically be
  associated with surfaces, although from the user's point of view, the
  "lightness" of a surface is actually related to the _material_ of that
  surface.  Users could simply add a sphere with a "glowing material",
  and the code would automatically figure out there should be a
  sphere-light at that location.  [There would still need to
  non-associated lights, for special light types like point lights and
  environment-map lights.]
  
  The rendering code still needs to have a global list of light objects,
  so there basically should be a step before rendering where the scene
  is walked, and a light created for any surface with a "light material".

  For more details on how this is stored into surfaces, see "TODO
  Reorganize the Surface abstraction".

* TODO Add alternative types of sample generation

  E.g., quasi Monte Carlo.

* TODO Write a C extension to Lua for quickly parsing large vertex/triangle arrays

  This allow the caller to specify a very simplistic grammar --
  essentially requiring they being arrays of float/int constants in
  the same order, but with a little flexibility as to the strings
  separating the values.  This should vastly speed up some Lua
  parsers (which can take a lot of time to read in large meshes).

* TODO Add scene loaders:

  * TODO RenderMan/PBRT

  * TODO Cinema 4D

    There is a published spec for version 5 of the C4D format, which is
    not current, but apparently designated as a sort of "exchange format"
    for C4D.  This is a binary format, but maybe parseable using
    Lua/lpeg/struct.

  * TODO 3DS MAX

    Note this is different from 3DS format, which is already supported.

  * TODO Povray

* TODO Implement "Lightcuts" algorithm for optimizing (quite dramatically)
   _huge_ numbers of lights:

     http://www.cs.cornell.edu/~kb/publications/SIG05lightcuts.pdf

  Also implement "Reconstruction cuts" (further optimizes lightcuts algorithm)

* TODO Better light management to handle huge numbers of lights.

  1. Keep list of lights ordered in terms of "apparent strength"
     (e.g. intensity * solid angle); this varies per pixel, but is a
     good candidate for caching as it will change slowly for nearby
     points.

  2. Use the "apparent strength" of lights to influence sample allocation

  3. The cached ordered list of lights can have two categories: nearby
     lights and far-away lights (based on given point/bounding-box).
     When moving to a new point, we (1) see if any far-away lights have
     become "nearby", in which case we recalculate the whole list, and
     otherwise (2) reorder lights in the "nearby" list according to
     their current apparent strengths.

     Note that "nearby" lights are _not_ necessarily stronger than
     faraway lights, merely more likely to change in strength (the sun
     for instance, is probably always at the front of the "apparent
     strength" list, yet always in the faraway list).  For typical
     scenes, the number of nearby lights is probably much smaller than
     faraway lights.

* TODO Octree improvements

  * Make octree smarter

    See "voxtree-hacks-20050928-0.patch"

    Have different types of octree node for different situations:

    * Normal octree nodes

    * Leaf nodes (no children nodes, just objects)

    * Bounding-box-sub-nodes nodes:  instead of a simple octree,
      children nodes can have an arbitrary bounding box -- this is good
      for the case where the child(ren) has a dramatically different
      scale, as degenerate long single chains of octree nodes can be
      avoided (the "teapot in a stadium" problem)

  * Make octree searching directional

    Currently it will find object in random order; typically it would be
    much better to find closer objects first.

    For octree, put children node pointers in a length-8 array, where
    the 3 bits in the array index correspond to x-hi/lo, y-hi/lo,
    z-hi/lo respectively.  Then when starting the search at the
    top-level, we compute a quick "first check" index according to the
    rough direction of the ray we're searching for.  When iterating over
    sub-nodes in the octree, we can simply do:

       for (index_mask = 0; index_mask < 8; index_mask)
	 search_subnode (subnodes[ray_start_index ^ index_mask]);

  * Maybe try to use ray-marching instead of tree-searching

* TODO Implement alternative acceleration structures

  * TODO Bounding-Interval Hierarchy

  * TODO KD-trees

* TODO Implement new BRDFs

  * DONE Cook-Torrance
  * TODO Ashikhmin
  * TODO Ward
  * TODO Schick
  * TODO LaFortune
  * TODO Oren-Nayar

* TODO Implement more elegant material framework

  Pbrt has a nice system:

  * A generalization of the BRDF, the BxDF ("Bidirectional
    reflection/transmission Distribution Function") handles either
    hemisphere (ordinary BRDFs only handle the reflection hemisphere).

  * BxDFs are separable, and a container, the BSDF ("Bidirectional
    Sphere Distribution Function") can hold a set of them, which are
    combined to form the entire lighting calculation for a point.
    [This seems to be done dynamically, at intersection time?!?]

    For instance, instead of every BRDF calculating its own diffuse
    term, one can just add a standard Lambertian BRDF to whatever more
    specialized BxDFs are being used for a material.

  * Ideal specular reflection/transmission are defined as BxDFs (in
    terms of the Dirac delta function), not special materials.

  * Various types of microfacet materials are combined, with subclasses
    only needing to override the "D()" method.

* TODO Fix UV handling at wrapped seams of tessellated surfaces

  Mesh interpolation of UV parameters in meshes generated by
  tessellation screws when interpolating across seams.  The reason is
  that currently only a single vertex is generated where both "sides"
  of a seam meet, and obviously this single vertex can only have a
  single UV parameter.  Thus at a seam where U wraps at 1, if a seam
  vertex has a U value of 1, then interpolation will act funny on the
  side where it's "really" 0, and if that seam vertex has a U value of
  0, then interpolation will act funny on the side where the U value
  should really be 1.

  The way to fix this is to generate two vertices at seams, one for
  each side of the seams, at the same coordinates.  If no precise
  normal information is available for the tessellation available (which
  might be true for a displacement-mapped tessellations even if the
  base tessellation has normal info), then this will require the
  tessellation code to calculate its own vertex normals, _ignoring_ the
  vertex splitting at seams (treating seam vertices as singular),
  because otherwise the normals at seams will be slightly incorrect.

* TODO Clean up environment-map region-splitting code.

  Instead of weird iterative searching for the best split point for
  splitting regions, just add a LightMap method to return a split
  point (the current code ends up more or less just splitting as
  evenly as possible taking mapping distortion into account).

* TODO Implement system for generating (and preserving, in snogcvt) image meta-data

  Simple EXIF support is added by exif-20061030-1.patch, but probably
  it's better to use a more general abstraction (e.g., just keep
  meta-data in a ValTable until output time), so that other meta-data
  formats like XMP and IPTC can be supported.

* TODO Get rid of seams at corners of cube-maps.

   This is caused by the fact that the face textures run from edge to
   edge, and there is no interpolation at the edge of two adjoining
   faces.

   A simple fix is to simply add a 1-pixel border to each face image,
   and fill them with pixels from the adjacent face.  Then, the mapping
   from cube coordinates into texture coordinate can be slightly
   perturbed such that the face parameter range [-1, 1] maps into the
   texture parameter range [PIXW/2, 1 - PIXW/2], where "PIXW" is the
   width of one pixel in the texture's source image.

   Maybe to maintain the texture abstraction, a texture "adjoin" method
   can take care of filling in the pixels and tweaking the texture's own
   scaling factors so that the texture input parameters are still in the
   range [0, 1].

   [We don't really use cube-maps anymore, so maybe better just remove them?]


----------------------------------------------------------------

Completed items:


* DONE Figure out the whole damn cos-wo thing

  Some BRDF formulations include an implicit cos-wo term (to correct for
  projected area; "wo" is the angle between the surface normal and the
  light source), whereas others don't, and only include the raw BRDF
  function, but it's very confusing which is which, as sometimes this
  term is actually hidden deep within the BRDF formulas for efficiency.

  Ugh.  I'm totally confused by it, as I don't really understand the
  math behind half the BRDFs out there, but it has to be sorted out so
  everything's correct.

  Plan: BRDF sampling and evaluation functions should only use the raw
  function, and let the integrators deal with adding the cos-wo term.

* DONE Add system for sharing sample generation info among different levels of sampling

  For instance, if using 3x3 eye-rays and 25 light samples, the final
  stratification of light samples should be done using 225 (3 x 3 x 25)
  total samples, and the light-sample stratification state maintained
  across multiple eye-rays.  This should allow better stratification
  even when using a high eye-ray:light-sample ratio (e.g. for DOF).

  [DONE, as part of the new "integrator" rewrite.]

* DONE Restructure current "Trace" datatype

  Currently this serves two purposes:
    1. It provides a path upwards which can be used to do things like
       finding the proper index of refraction when existing a glass
       surface.
    2. It provides a place to hang caches which persist beyond the
       current ray; this is a "downward" operation.

  The first use, might be better served by a simple linked list
  of current Intersect objects.  The second, by an explicit
  "IsecCache" datatype, which would only be "downwards" (and which
  would hang off Intersect objects during tracing).

  [DONE, by moving most of the state out of Trace: various global info
   just moved into RenderContext, and the cache stuff just eliminated
   (it didn't actually help that much, and removing it makes the code a
   lot simpler).]

* DONE Texture support

  Add a "TextureMap" data type which maps between a surface point and
  texture coordinates.

  New class TexCoords to hold two texture coordinates?

  Add a "Pigment" data type, which contains a Color and a Texture
  pointer; most places where Color is now used in materials, should
  use Pigment instead (have constructors so that it can be
  initialized just like a color, resulting in a 0 Texture pointer).

  Pigment has a "color(...)" method, which takes an a texture-map and
  a location, and returns a color by using the texture-map to map the
  location into texture coordinates, and looking them in the texture
  (if the pigment's texture is 0 of course, return its color).

  Surface class gets a "texture_coords" method that returns Texture
  coordinates for a given point on the surface.  PrimarySurface gets
  a new field to explicitly store a texture map, and uses that to
  implement texture_coords; mesh triangles use something else, e.g.,
  explicit per-vertex texture-coordinate tables with interpolation.

  Intersect constructor should look up and cache texture-coordinates
  for the intersection point.

  Anyplace where a Color has been replaced by a Pigment should now
  call `pigment.color (isec.tex_coords)' instead of just returning
  the color directly (when the pigment's texture pointers is 0, this
  will be almost as fast).

  Similar techniques are needed for looking up normals; shared
  superclass with textures?
 
  [DONE, more generally, by rewriting illumination to use the IllumMgr
   and subclasses of Illum]

* DONE Split illumination into DirectIllum and IndirIllum superclasses

  The current SampleIllum class should probably just be renamed to
  DirectIllum.  IndirIllum would be a superclass for photon-mapping
  or hemisphere-sampling indirect illumination algorithms.

* DONE Make mirror reflections use light-model

  Importance sampling + indirect illumination

* DONE Implement instancing

* DONE Encapsulate space/octree abstraction inside a surface interface

  ... so that there can be multiple nested search spaces.  This might
  help speed (or hurt it...) by consolidating logically related
  surfaces into their own search spaces, but more importantly, it
  allows easy object instancing by allowing us to wrap a search-space
  with a coordinate transform.

* DONE Use single-precision floating-point uniformly

  Currently double-precision is used widely (e.g. the Vec and Pos
  classes).  Just switching completely to single-precision mostly
  works fine, but causes problems with reflected/transmitted rays
  after sphere-intersection -- so debug those errors, and make sphere
  intersection work with single-precision floating point.  Probably
  just needs some kind of error margin when tracing recursive rays.

* DONE Add a real scene definition language

  [DONE, by adding a Lua interpreter.]

* DONE Importance sampling

  Add method to Material class to supply a jittered set of rays
  (given a desired number of rays as input) corresponding to the
  Material's BRDF.  The output should be efficient for large number
  of rays (e.g. ~1000) so it can be re-sampled to combine it with
  another importance function, so each element in the set should just
  be something like <reflectance, direction> (the origin is implied). 

* DONE Lighting from environment map

  Use importance resampling to combine the BRDF importance function
  with an importance function for the whole environment map (one
  hemisphere?).

  See "Bidirectional Importance Sampling for Direct Illumination",
  http://www.cs.ubc.ca/~dburke/downloads/EGSR05-Bidir_Importance.pdf

* DONE Switch to proper filtering for anti-aliasing, taking jitter etc into account:

  Add a Filter class, which takes a simple x,y offset and returns a
  filter value at that point (relative to origin).  Add a "SampleGen"
  class will will generate a series of samples (stratified etc) in a
  unit square.  For each output pixel, generate samples, render them,
  and then get the filter value for the samples offset from the pixel
  center, and combine them using the formula

     Sum(filt(samp) light(samp)) / Sum(filt(samp))

  Get rid of wacky scan-line-based filtering I guess.

  For the problem of doing post-processing of HDR images, an idea is:

     When converting from an HDR representation to a limited-gamut
     representation, use filtering even if the image resolution is
     the same; make sure the filter support is wide enough so that a
     high-intensity pixel adjacent to a low-intensity pixel will
     "bleed" into it via the tail of the filter (but make the tail
     amplitude small enough so that the bleeding in normal cases is
     negligible).

* DONE Get rid of weird error handling in image code and just use exceptions

* DONE Get rid of "Image{Source,Sink}Params" classes and instead just pass
   user-supplied  "parameter strings" to image backends.

  The parameter strings can be appended to the "image type" command-line
  options, separated by ":", with "=" mean assign value.  So for
  instance, for jpeg, the user could specify "-Ojpeg:quality=98" (as the
  user will usually specify the image type indirectly via the output
  file extension, it could assume a "=" before the first ":" meant that
  the first element was a parameter rather than a type).

* DONE Use Fresnel equations to calculate reflectance/transmittance

  http://scienceworld.wolfram.com/physics/FresnelEquations.html

* DONE Abstract octree into a more generic "space division" data-type

  Allow experimenting with different implementations, e.g., KD-trees.
  [This might fit well with the octree generalization below.]

* DONE Soft shadows

  [DONE, RectLight, FarLight.]

* DONE Optimize triangle intersection calculation.

  (Accounts for a huge proportion of tracing time)

* DONE Simple support for shadows of transparent/translucent objects

  Real support (bending of light rays) is too hard, but for a simple
  straight light ray, it should be easy and better than nothing.
  [For real support, caustics etc., use photon transport]

;; arch-tag: 87fcbf10-c76f-43d6-9b09-469aba284b80
