// ========================================
// MakeSnow macro
// by Gilles Tran (c) 2003
// Feel free to use and modify in any project
// ----------------------------------------
// This macro project blob elements on an object, making it look like it is covered by snow.
// It was first developed to be used on trees, and it works better on complex shapes than on flat ones.
// Note: this macro uses the trace() function. This means that every surface will be detected, including 
// transparent ones used for media for instance.

#declare Particles=20000; // number of snow particles
//      More particles = more parsing time and smoother effect
//      The macro loops until this number of "hits" is completed ("misses" do not count).

#declare Size=2; // size of the largest snow particle
//       Sizes between 2 and 100 should be OK for objects whose size is expressed in centimetres

#declare Thickness=1.2; // thickness of the particles
//     
#declare MinHeight=0; // snow starts falling from this height ( 1 = max height of the object)
#declare MaxHeight=1.1; // snow stops falling from this height  ( 1 = max height of the object)
//       Using MinHeight < 1 makes it possible to have snow on lower parts of the object that are protected 
//       by overhangs, higher branches and such, but it may requires more particles to get a proper effect

#declare Direction=-y+x*0.1+z*0.3; // Direction of gravity, wind etc.(-y = vertical, no wind)
//     
#include "transforms.inc"
#macro MakeSnow(Obj,Particles,Size,Thickness,MinHeight,MaxHeight,Direction)
    #ifndef (T_Snow)
        #local T_Snow=texture{
            pigment{rgb 1}
            finish{ambient 0 diffuse 1}
        }
    #end
    #ifndef (rd)
        #local rd=seed(2003);
    #end
    #local Obj2=object{Obj Reorient_Trans(-y,<-Direction.x,Direction.y,-Direction.z>)}
    #local Min=min_extent(Obj2);
    #local Max=max_extent(Obj2);
    blob{
        threshold 0.6
        #local i=0; // first layer
        #debug "first layer of snow\n"
        #while (i<Particles/3)
            #local Start=<Min.x+rand(rd)*(Max.x-Min.x),(MinHeight+rand(rd)*(MaxHeight-MinHeight))*Max.y,Min.z+rand(rd)*(Max.z-Min.z)>;
            #local Norm=<0,0,0>;
            #local Inter= trace (Obj2, Start, -y, Norm );
            #if (vlength(Norm)!=0)
                #local Angle=pow((180-abs(degrees(acos(min(1,vdot(vnormalize(Norm),y))))))/180,2);
                #local FlakeSize=Angle*<1+rand(rd)*1.3,(Angle*0.5+rand(rd))*Thickness,1+rand(rd)*1.3>;
                sphere{0,Size*2,1 scale FlakeSize Reorient_Trans(y,Norm) translate Inter}
                #if (mod(i,1000)=0) 
                    #debug concat(str(i,0,0),"\n")
                #end
                #local i=i+1;
            #end
        #end 
        #local  i=0;
        #debug "second layer of snow\n"
        #while (i<Particles*2/3) // second layer of smaller particles
            #local Start=<Min.x+rand(rd)*(Max.x-Min.x),(MinHeight+rand(rd)*(MaxHeight-MinHeight))*Max.y,Min.z+rand(rd)*(Max.z-Min.z)>;
            #local Norm=<0,0,0>;
            #local Inter= trace (Obj2, Start, -y, Norm );
            #if (vlength(Norm)!=0)
                #local Angle=pow((180-abs(degrees(acos(min(1,vdot(vnormalize(Norm),y))))))/180,2);
                #local FlakeSize=Angle*<1+rand(rd)*1.3,(Angle*0.5+rand(rd))*Thickness,1+rand(rd)*1.3>;
                sphere{0,Size*2,1 scale FlakeSize*0.25 Reorient_Trans(y,Norm) translate Inter}
                #if (mod(i,1000)=0) 
                    #debug concat(str(i,0,0),"\n")
                #end
                #local i=i+1;
            #end
        #end 
        //material{M_Glass}
		material {
						texture{
				pigment {
					rgbt <1.000000, 1.000000, 1.000000, 1>
				}
				finish {
					ambient rgb <0.329992, 0.329992, 0.329992>
					reflection {
						rgb <0.489998, 0.489998, 0.489998>
					}
					diffuse 0.2
					brilliance 1
					phong 1
					phong_size 40
				}
			}
			interior {
				ior 1.305
				//caustics 0.8
				media {
					scattering {
						1,	//isotropic_scattering
						rgb <1.0, 1.0, 1.0>
					}
					method 3
					intervals 3
				}
			}
		}
		hollow on
		//texture{T_Snow}
        Reorient_Trans(<-Direction.x,Direction.y,-Direction.z>,-y)
    }
#end    
