示例#1
0
        /// <summary>
        /// Random direction around the [0,0,1] vector.
        /// Normal distribution is used, using required variance.
        /// </summary>
        /// <param name="rnd">Random generator to be used.</param>
        /// <param name="variance">Variance of the deviation angle in radians.</param>
        /// <returns></returns>
        public static Vector3d RandomDirectionNormal(RandomJames rnd, double variance)
        {
            // result: [0,0,1] * rotX(deviation) * rotZ(orientation)

            double   deviation   = rnd.Normal(0.0, variance);
            double   orientation = rnd.RandomDouble(0.0, Math.PI);
            Matrix4d mat         = Matrix4d.CreateRotationX(deviation) * Matrix4d.CreateRotationZ(orientation);

            return(new Vector3d(mat.Row2)); // [0,0,1] * mat
        }
示例#2
0
        /// <summary>
        /// Random direction around the givent center vector.
        /// Normal distribution is used, using required variance.
        /// </summary>
        /// <param name="rnd">Random generator to be used.</param>
        /// <param name="dir">Central direction.</param>
        /// <param name="variance">Variance of the deviation angle in radians.</param>
        /// <returns></returns>
        public static Vector3d RandomDirectionNormal(RandomJames rnd, Vector3d dir, double variance)
        {
            // Matrix3d fromz: [0,0,1] -> dir
            // Vector4d delta: [0,0,1] * rotX(deviation) * rotZ(orientation)
            // result: delta * fromz

            dir.Normalize();
            Vector3d axis1, axis2;

            GetAxes(ref dir, out axis1, out axis2);
            Matrix4d fromz = new Matrix4d(new Vector4d(axis1), new Vector4d(axis2), new Vector4d(dir), Vector4d.UnitW);
            //fromz.Transpose();
            double   deviation   = rnd.Normal(0.0, variance);
            double   orientation = rnd.RandomDouble(0.0, Math.PI);
            Matrix4d mat         = Matrix4d.CreateRotationX(deviation) * Matrix4d.CreateRotationZ(orientation) * fromz;

            return(new Vector3d(mat.Row2)); // [0,0,1] * mat
        }
示例#3
0
        /// <summary>
        /// Computes one image sample. Internal integration support.
        /// </summary>
        /// <param name="x">Horizontal coordinate.</param>
        /// <param name="y">Vertical coordinate.</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="color">Computed sample color.</param>
        /// <returns>Hash-value used for adaptive subsampling.</returns>
        public virtual long GetSample( double x, double y, int rank, int total, RandomJames rnd, double[] color )
        {
            Vector3d p0, p1;
              int bands = color.Length;
              if ( !scene.Camera.GetRay( x, y, rank, total, rnd, out p0, out p1 ) )
              {
            Array.Clear( color, 0, bands );                    // invalid ray -> black color
            return 1L;
              }

              LinkedList<Intersection> intersections = scene.Intersectable.Intersect( p0, p1 );
              Intersection.countRays++;
              Intersection i = Intersection.FirstIntersection( intersections, ref p1 );
              if ( i == null )            // no intersection -> background color
              {
            Array.Copy( scene.BackgroundColor, color, bands );
            return 0L;
              }

              // there was at least one intersection
              i.Complete();

              // hash code for adaptive supersampling:
              long hash = i.Solid.GetHashCode();

              // apply all the textures fist..
              if ( i.Textures != null )
            foreach ( ITexture tex in i.Textures )
              hash = hash * HASH_TEXTURE + tex.Apply( i, rank, total, rnd );

              // terminate if light sources are missing
              if ( scene.Sources == null || scene.Sources.Count < 1 )
              {
            Array.Copy( i.SurfaceColor, color, bands );
            return hash;
              }

              // .. else apply the reflectance model for each source
              p1 = -p1;
              p1.Normalize();

              i.Material = (IMaterial)i.Material.Clone();
              i.Material.Color = i.SurfaceColor;
              Array.Clear( color, 0, bands );

              foreach ( ILightSource source in scene.Sources )
              {
            Vector3d dir;
            double[] intensity = source.GetIntensity( i, rank, total, rnd, out dir );
            if ( intensity != null )
            {
              double[] reflection = i.ReflectanceModel.ColorReflection( i, dir, p1, ReflectionComponent.ALL );
              if ( reflection != null )
              {
            for ( int b = 0; b < bands; b++ )
              color[ b ] += intensity[ b ] * reflection[ b ];
            hash = hash * HASH_LIGHT + source.GetHashCode();
              }
            }
              }

              return hash;
        }
示例#4
0
        /// <summary>
        /// Computes one image sample. Internal integration support.
        /// </summary>
        /// <param name="x">Horizontal coordinate.</param>
        /// <param name="y">Vertical coordinate.</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="color">Computed sample color.</param>
        /// <returns>Hash-value used for adaptive subsampling.</returns>
        public override long GetSample( double x, double y, int rank, int total, RandomJames rnd, double[] color )
        {
            // initial color = black
              Array.Clear( color, 0, color.Length );

              Vector3d p0, p1;
              if ( !scene.Camera.GetRay( x, y, rank, total, rnd, out p0, out p1 ) )
            return 11L;

              long hash = shade( 0, 1.0, ref p0, ref p1, rank, total, rnd, color );

              return hash;
        }
示例#5
0
        /// <summary>
        /// Recursive shading function - computes color contribution of the given ray (shot from the
        /// origin 'p0' into direction vector 'p1''). Recursion is stopped
        /// by a hybrid method: 'importance' and 'level' are checked.
        /// Internal integration support.
        /// </summary>
        /// <param name="level">Current recursion depth.</param>
        /// <param name="importance">Importance of the current ray.</param>
        /// <param name="p0">Ray origin.</param>
        /// <param name="p1">Ray direction vector.</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="color">Result color.</param>
        /// <returns>Hash-value (ray sub-signature) used for adaptive subsampling.</returns>
        protected virtual long shade( int level, double importance, ref Vector3d p0, ref Vector3d p1,
                                   int rank, int total, RandomJames rnd, double[] color )
        {
            int bands = color.Length;
              LinkedList<Intersection> intersections = scene.Intersectable.Intersect( p0, p1 );
              Intersection.countRays++;
              Intersection i = Intersection.FirstIntersection( intersections, ref p1 );
              int b;

              if ( i == null )          // no intersection -> background color
              {
            Array.Copy( scene.BackgroundColor, color, bands );
            return 1L;
              }

              // there was at least one intersection
              i.Complete();

              // hash code for adaptive supersampling:
              long hash = i.Solid.GetHashCode();

              // apply all the textures fist..
              if ( i.Textures != null )
            foreach ( ITexture tex in i.Textures )
              hash = hash * HASH_TEXTURE + tex.Apply( i, rank, total, rnd );

              p1 = -p1;   // viewing vector
              p1.Normalize();

              if ( scene.Sources == null || scene.Sources.Count < 1 )
            // no light sources at all
            Array.Copy( i.SurfaceColor, color, bands );
              else
              {
            // apply the reflectance model for each source
            i.Material = (IMaterial)i.Material.Clone();
            i.Material.Color = i.SurfaceColor;
            Array.Clear( color, 0, bands );

            foreach ( ILightSource source in scene.Sources )
            {
              Vector3d dir;
              double[] intensity = source.GetIntensity( i, rank, total, rnd, out dir );
              if ( intensity != null )
              {
            if ( DoShadows && !dir.Equals( Vector3d.Zero ) )
            {
              intersections = scene.Intersectable.Intersect( i.CoordWorld, dir );
              Intersection.countRays++;
              Intersection si = Intersection.FirstIntersection( intersections, ref dir );
              // Better shadow testing: intersection between 0.0 and 1.0 kills the lighting
              if ( si != null && !si.Far( 1.0, ref dir ) ) continue;
            }

            double[] reflection = i.ReflectanceModel.ColorReflection( i, dir, p1, ReflectionComponent.ALL );
            if ( reflection != null )
            {
              for ( b = 0; b < bands; b++ )
                color[ b ] += intensity[ b ] * reflection[ b ];
              hash = hash * HASH_LIGHT + source.GetHashCode();
            }
              }
            }
              }

              // check the recursion depth:
              if ( level++ >= MaxLevel ||
               !DoReflections && !DoRefractions )
            return hash;                        // no further recursion

              Vector3d r;
              double maxK;
              double[] comp = new double[ bands ];
              double newImportance;

              if ( DoReflections )                  // trying to shoot a reflected ray..
              {
            Geometry.SpecularReflection( ref i.Normal, ref p1, out r );
            double[] ks = i.ReflectanceModel.ColorReflection( i, p1, r, ReflectionComponent.SPECULAR_REFLECTION );
            if ( ks != null )
            {
              maxK = ks[ 0 ];
              for ( b = 1; b < bands; b++ )
            if ( ks[ b ] > maxK )
              maxK = ks[ b ];

              newImportance = importance * maxK;
              if ( newImportance >= MinImportance ) // do compute the reflected ray
              {
            hash += HASH_REFLECT * shade( level, newImportance, ref i.CoordWorld, ref r, rank, total, rnd, comp );
            for ( b = 0; b < bands; b++ )
              color[ b ] += ks[ b ] * comp[ b ];
              }
            }
              }

              if ( DoRefractions )                  // trying to shoot a refracted ray..
              {
            maxK = i.Material.Kt;               // simple solution, no influence of reflectance model yet
            newImportance = importance * maxK;
            if ( newImportance < MinImportance )
              return hash;

            // refracted ray:
            if ( (r = Geometry.SpecularRefraction( i.Normal, i.Material.n, p1 )) == null )
              return hash;

            hash += HASH_REFRACT * shade( level, newImportance, ref i.CoordWorld, ref r, rank, total, rnd, comp );
            for ( b = 0; b < bands; b++ )
              color[ b ] += maxK * comp[ b ];
              }

              return hash;
        }
示例#6
0
        /// <summary>
        /// Renders the given rectangle into the given raster image.
        /// Has to be re-entrant since this code is started in multiple parallel threads.
        /// </summary>
        /// <param name="image">Pre-initialized raster image.</param>
        /// <param name="sel">Selector for this working thread.</param>
        /// <param name="rnd">Thread-specific random generator.</param>
        public virtual void RenderRectangle( Bitmap image, int x1, int y1, int x2, int y2, ThreadSelector sel, RandomJames rnd )
        {
            bool lead = sel( 0L );
              if ( lead &&
               ProgressData != null )
            lock ( ProgressData )
            {
              ProgressData.Finished = 0.0f;
              ProgressData.Message = "";
            }

              double[] color = new double[ 3 ];     // pixel color

              // run several phases of image rendering:
              int cell = 32;                        // cell size
              while ( cell > 1 && cell > Adaptive )
            cell >>= 1;
              int initCell = cell;

              int x, y;
              bool xParity, yParity;
              float total = (x2 - x1) * (y2 - y1);
              long counter = 0L;
              long units = 0;

              do                                    // do one phase
              {
            for ( y = y1, yParity = false;
              y < y2;                       // one image row
              y += cell, yParity = !yParity )

              for ( x = x1, xParity = false;
                x < x2;                     // one image cell
                x += cell, xParity = !xParity )

            if ( cell == initCell ||
                 xParity || yParity )       // process the cell
            {
              if ( !sel( counter++ ) )
                continue;

              // determine sample color ..
              RenderPixel( x, y, color, rnd );

              if ( Gamma <= 0.001 )
                for ( int b = 0; b < color.Length; b++ )
                  color[ b ] = Arith.Clamp( color[ b ], 0.0, 1.0 );

              // .. and render it:
              Color c = Color.FromArgb( (int)(color[ 0 ] * 255.0),
                                        (int)(color[ 1 ] * 255.0),
                                        (int)(color[ 2 ] * 255.0) );
              lock ( image )
              {
                if ( cell == 1 )
                  image.SetPixel( x, y, c );
                else
                {
                  int xMax = x + cell;
                  if ( xMax > x2 )
                    xMax = x2;
                  int yMax = y + cell;
                  if ( yMax > y2 )
                    yMax = y2;
                  for ( int iy = y; iy < yMax; iy++ )
                    for ( int ix = x; ix < xMax; ix++ )
                      image.SetPixel( ix, iy, c );
                }
              }

              if ( (++units & 63L) == 0L &&
                   ProgressData != null )
                lock ( ProgressData )
                {
                  if ( !ProgressData.Continue )
                    return;
                  if ( lead )
                  {
                    ProgressData.Finished = counter / total;
                    ProgressData.Sync( image );
                  }
                }
            }
              }
              while ( (cell >>= 1) > 0 );         // do one phase
        }
示例#7
0
 /// <summary>
 /// Ray-generator. Internal integration support.
 /// </summary>
 /// <param name="x">Origin position within a viewport (horizontal coordinate).</param>
 /// <param name="y">Origin position within a viewport (vertical coordinate).</param>
 /// <param name="rank">Rank of this ray, 0 <= rank < total (for integration).</param>
 /// <param name="total">Total number of rays (for integration).</param>
 /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
 /// <param name="p0">Ray origin.</param>
 /// <param name="p1">Ray direction vector.</param>
 /// <returns>True if the ray (viewport position) is valid.</returns>
 public bool GetRay( double x, double y, int rank, int total, RandomJames rnd, out Vector3d p0, out Vector3d p1 )
 {
     return GetRay( x, y, out p0, out p1 );
 }
示例#8
0
        /// <summary>
        /// Renders the single pixel of an image.
        /// </summary>
        /// <param name="x">Horizontal coordinate.</param>
        /// <param name="y">Vertical coordinate.</param>
        /// <param name="color">Computed pixel color.</param>
        /// <param name="rnd">Shared random generator.</param>
        public virtual void RenderPixel( int x, int y, double[] color, RandomJames rnd )
        {
            ImageFunction.GetSample( x + 0.5, y + 0.5, color );

              // gamma-encoding:
              if ( Gamma > 0.001 )
              {                                     // gamma-encoding and clamping
            double g = 1.0 / Gamma;
            for ( int b = 0; b < color.Length; b++ )
              color[ b ] = Arith.Clamp( Math.Pow( color[ b ], g ), 0.0, 1.0 );
              }
                                           // else: no gamma, no clamping (for HDRI)
        }
示例#9
0
 /// <summary>
 /// Renders the given rectangle into the given raster image.
 /// </summary>
 /// <param name="image">Pre-initialized raster image.</param>
 /// <param name="rnd">Shared random generator.</param>
 public virtual void RenderRectangle( Bitmap image, int x1, int y1, int x2, int y2, RandomJames rnd )
 {
     RenderRectangle( image, x1, y1, x2, y2, ( n ) => true, rnd );
 }
示例#10
0
 public SamplingState( RectangleLightSource src, RandomJames _rnd )
 {
     source = src;
     rnd = _rnd;
     permU = new RandomJames.Permutation();
     permV = new RandomJames.Permutation();
     rank = total = 0;
 }
示例#11
0
 /// <summary>
 /// Returns intensity (incl. color) of the source contribution to the given scene point.
 /// Internal integration support.
 /// </summary>
 /// <param name="intersection">Scene point (only world coordinates and normal vector are needed).</param>
 /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
 /// <param name="total">Total number of samples (for integration).</param>
 /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
 /// <param name="dir">Direction to the source is set here (zero vector for omnidirectional source).</param>
 /// <returns>Intensity vector in current color space or null if the point is not lit.</returns>
 public double[] GetIntensity( Intersection intersection, int rank, int total, RandomJames rnd, out Vector3d dir )
 {
     return GetIntensity( intersection, out dir );
 }
示例#12
0
        /// <summary>
        /// Returns intensity (incl. color) of the source contribution to the given scene point.
        /// Internal integration support.
        /// </summary>
        /// <param name="intersection">Scene point (only world coordinates and normal vector are needed).</param>
        /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
        /// <param name="total">Total number of samples (for integration).</param>
        /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
        /// <param name="dir">Direction to the source is set here (zero vector for omnidirectional source). Not normalized!</param>
        /// <returns>Intensity vector in current color space or null if the point is not lit.</returns>
        public override double[] GetIntensity( Intersection intersection, int rank, int total, RandomJames rnd, out Vector3d dir )
        {
            if ( rnd == null )
            return GetIntensity( intersection, out dir );

              SamplingState ss;
              lock ( states )
              {
            if ( !states.TryGetValue( rnd.GetHashCode(), out ss ) )
            {
              ss = new SamplingState( this, rnd );
              states.Add( rnd.GetHashCode(), ss );
            }
              }

              // generate a [new] sample:
              ss.generateSample( rank, total );
              dir = ss.sample - intersection.CoordWorld;
              if ( Vector3d.Dot( dir, intersection.Normal ) <= 0.0 )
            return null;

              if ( Dim == null || Dim.Length < 3 ) return intensity;

              double dist = dir.Length;
              double dimCoef = 1.0 / (Dim[0] + dist * (Dim[1] + dist * Dim[2]));
              int bands = intensity.Length;
              double[] result = new double[ bands ];
              for ( int i = 0; i < bands; i++ )
            result[ i ] = intensity[ i ] * dimCoef;

              return result;
        }
示例#13
0
 /// <summary>
 /// Apply the relevant value-modulation in the given Intersection instance.
 /// Internal integration support.
 /// </summary>
 /// <param name="inter">Data object to modify.</param>
 /// <param name="rank">Rank of this sample, 0 <= rank < total (for integration).</param>
 /// <param name="total">Total number of samples (for integration).</param>
 /// <param name="rnd">Global (per-thread) instance of the random generator.</param>
 /// <returns>Hash value (texture signature) for adaptive subsampling.</returns>
 public long Apply( Intersection inter, int rank, int total, RandomJames rnd )
 {
     return Apply( inter );
 }
示例#14
0
        /// <summary>
        /// Renders the single pixel of an image.
        /// </summary>
        /// <param name="x">Horizontal coordinate.</param>
        /// <param name="y">Vertical coordinate.</param>
        /// <param name="color">Computed pixel color.</param>
        /// <param name="rnd">Shared random generator.</param>
        public override void RenderPixel( int x, int y, double[] color, RandomJames rnd )
        {
            Debug.Assert( color != null );
              Debug.Assert( rnd != null );

              int bands = color.Length;
              int b;
              Array.Clear( color, 0, bands );
              double[] tmp = new double[ bands ];

              int i, j, ord;
              double step = 1.0 / superXY;
              double amplitude = Jittering * step;
              double origin = 0.5 * (step - amplitude);
              double x0, y0;
              for ( j = ord = 0, y0 = y + origin; j++ < superXY; y0 += step )
            for ( i = 0, x0 = x + origin; i++ < superXY; x0 += step )
            {
              ImageFunction.GetSample( x0 + amplitude * rnd.UniformNumber(),
                                   y0 + amplitude * rnd.UniformNumber(),
                                   ord++, Supersampling, rnd, tmp );
              for ( b = 0; b < bands; b++ )
            color[ b ] += tmp[ b ];
            }

              double mul = step / superXY;
              if ( Gamma > 0.001 )
              {                                     // gamma-encoding and clamping
            double g = 1.0 / Gamma;
            for ( b = 0; b < bands; b++ )
              color[ b ] = Arith.Clamp( Math.Pow( color[ b ] * mul, g ), 0.0, 1.0 );
              }
              else                                  // no gamma, no clamping (for HDRI)
            for ( b = 0; b < bands; b++ )
              color[ b ] *= mul;
        }