00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "volume.h"
00025 #include "texture.h"
00026
00027 namespace lux
00028 {
00029
00030 class CumulusSphere {
00031 public:
00032 void setPosition( Point p ) { position = p; };
00033 void setRadius( float r ) { radius = r; };
00034 Point getPosition() const { return position; };
00035 float getRadius() const { return radius; };
00036
00037 private:
00038 Point position;
00039 float radius;
00040 };
00041
00042
00043 class Cloud : public DensityRegion {
00044 public:
00045
00046 Cloud(const RGBColor &sa, const RGBColor &ss,
00047 float gg, const RGBColor &emit, const BBox &e, const float &r, const Transform &v2w,
00048 const float &noiseScale, const float &t, const float &sharp, const float &v, const float &baseflatness,
00049 const int &octaves, const float &o, const float &offSet, const int &numspheres, const float &spheresize );
00050 virtual ~Cloud() {
00051 delete sphereCentre;
00052 delete[] spheres;
00053 }
00054
00055 virtual bool IntersectP(const Ray &r, float *t0, float *t1) const {
00056 Ray ray = WorldToVolume(r);
00057 return extent.IntersectP(ray, t0, t1);
00058 }
00059 virtual BBox WorldBound() const { return WorldToVolume.GetInverse()(extent); }
00060 virtual float Density(const Point &p) const;
00061 static VolumeRegion *CreateVolumeRegion(const Transform &volume2world, const ParamSet ¶ms);
00062
00063 private:
00064
00065 bool SphereFunction(const Point &p ) const;
00066 float CloudShape(const Point &p) const;
00067 float NoiseMask(const Point &p ) const;
00068 Vector Turbulence(const Point p, float noiseScale, int octaves) const;
00069 Vector Turbulence(const Vector &v, float &noiseScale, int &octaves) const;
00070 float CloudNoise(Point p, const float &omegaValue, int octaves) const;
00071
00072 BBox extent;
00073 Vector scale;
00074 Point *sphereCentre;
00075 float inputRadius, radius;
00076
00077 bool cumulus;
00078 int numSpheres;
00079 float sphereSize;
00080 CumulusSphere *spheres;
00081
00082 float baseFadeDistance, sharpness, baseFlatness, variability;
00083 float omega, firstNoiseScale, noiseOffSet, turbulenceAmount;
00084 int numOctaves;
00085 };
00086
00087 Cloud::Cloud(const RGBColor &sa, const RGBColor &ss,
00088 float gg, const RGBColor &emit, const BBox &e, const float &r,
00089 const Transform &v2w, const float &noiseScale, const float &t, const float &sharp, const float &v,
00090 const float &baseflatness, const int &octaves, const float &o, const float &offSet, const int &numspheres, const float &spheresize )
00091 : DensityRegion(sa, ss, gg, emit, v2w),
00092 extent(e), inputRadius(r), numSpheres(numspheres), sphereSize(spheresize), sharpness(sharp),baseFlatness(baseflatness), variability(v),
00093 omega(o), firstNoiseScale(noiseScale), noiseOffSet(offSet), turbulenceAmount(t), numOctaves(octaves) {
00094
00095 if( numSpheres == 0 )
00096 cumulus = false;
00097 else
00098 cumulus = true;
00099
00100 radius = (extent.pMax.x-extent.pMin.x);
00101
00102 firstNoiseScale *= radius;
00103 turbulenceAmount *= radius;
00104
00105 radius *= inputRadius;
00106
00107 baseFadeDistance = float(extent.pMax.z-extent.pMin.z)*(1.0-baseFlatness);
00108
00109 sphereCentre = new Point(
00110 (extent.pMax.x+extent.pMin.x)*0.5,
00111 (extent.pMax.y+extent.pMin.y)*0.5,
00112 (extent.pMax.z+2*extent.pMin.z)*0.33 );
00113
00114 float angley, anglez;
00115 Vector onEdge;
00116 Point finalPosition;
00117
00118 if( cumulus )
00119 {
00120
00121 spheres = new CumulusSphere[numSpheres];
00122
00123 srand(int(noiseOffSet));
00124
00125 for( int i = 0; i < numSpheres; i++ )
00126 {
00127 spheres[i].setRadius( (float(rand()%10)*0.05+0.5)*sphereSize );
00128 onEdge = Vector( radius*0.5*(rand()%1000)/1000.0, 0, 0 );
00129 angley = float(rand()%1000)/1000.0*(-180);
00130 anglez = float(rand()%1000)/1000.0*360;
00131 onEdge = Vector(RotateY(angley)(onEdge));
00132 onEdge = Vector(RotateZ(anglez)(onEdge));
00133 finalPosition = Point(sphereCentre->x+onEdge.x,sphereCentre->y+onEdge.y,sphereCentre->z+onEdge.z);
00134 finalPosition += Turbulence( finalPosition + Point(noiseOffSet*4,0,0), radius*0.7, 2 )*radius*1.5;
00135 spheres[i].setPosition( finalPosition );
00136 }
00137 }
00138 }
00139
00140 float Cloud::Density(const Point &p) const {
00141 if (!extent.Inside(p)) return 0;
00142 float amount;
00143
00144 amount = CloudShape( p + turbulenceAmount * Turbulence(p,firstNoiseScale, numOctaves) );
00145
00146 float finalValue = pow(amount,sharpness)*pow(10,sharpness*0.7);
00147
00148 return finalValue <= 1.0 ? finalValue : 1.0;
00149 }
00150
00151 Vector Cloud::Turbulence(const Point p, float noiseScale, int octaves) const {
00152
00153 Point noiseCoords[3];
00154 noiseCoords[0] = Point( p.x/noiseScale, p.y/noiseScale, p.z/noiseScale );
00155 noiseCoords[1] = Point( noiseCoords[0].x+noiseOffSet, noiseCoords[0].y+noiseOffSet, noiseCoords[0].z+noiseOffSet );
00156 noiseCoords[2] = Point( noiseCoords[1].x+noiseOffSet, noiseCoords[1].y+noiseOffSet, noiseCoords[1].z+noiseOffSet );
00157
00158 float noiseAmount = 1.0;
00159
00160 if( variability < 1.0 )
00161 noiseAmount = (1.0-variability)+variability*NoiseMask( p + Point(noiseOffSet*4,0,0) );
00162
00163 if( noiseAmount > 1.0 ) noiseAmount = 1.0;
00164 if( noiseAmount < 0.0 ) noiseAmount = 0.0;
00165
00166 Vector turbulence;
00167
00168 turbulence.x = (CloudNoise(noiseCoords[0], omega, octaves)-0.15);
00169
00170 turbulence.y = (CloudNoise(noiseCoords[1], omega, octaves)-0.15);
00171
00172 if( p.z >= sphereCentre->z + baseFadeDistance )
00173 turbulence.z = -CloudNoise(noiseCoords[2], omega, octaves)*1.0;
00174 else
00175 turbulence.z = -CloudNoise(noiseCoords[2], omega, octaves)*1.0 * (p.z-sphereCentre->z)/baseFadeDistance/2;
00176
00177
00178 turbulence *= noiseAmount;
00179
00180 return turbulence;
00181 }
00182
00183 Vector Cloud::Turbulence(const Vector &v, float &noiseScale, int &octaves) const {
00184 return Turbulence(Point(v.x,v.y,v.z),noiseScale,octaves);
00185 }
00186
00187
00188 float Cloud::CloudShape(const Point &p) const {
00189 if( cumulus )
00190 {
00191 if( SphereFunction( p ) )
00192 return 1.0;
00193 else
00194 return 0.0;
00195 }
00196
00197
00198 Vector fromCentre(
00199 float(p.x-sphereCentre->x),
00200 float(p.y-sphereCentre->y),
00201 float(p.z-sphereCentre->z)
00202 );
00203
00204 float amount = 1.0 - fromCentre.Length() / radius;
00205 if( amount < 0.0 ) amount = 0.0;
00206
00207 if( p.z < sphereCentre->z )
00208 {
00209 if( p.z < sphereCentre->z-radius*0.4 )
00210 amount = 0.0;
00211
00212 amount *= 1.0-cos(float(p.z-sphereCentre->z+baseFadeDistance)/float(baseFadeDistance)*3.1415927*0.5);
00213 }
00214 return amount > 0.0 ? amount : 0.0;
00215 }
00216
00217 float Cloud::NoiseMask(const Point &p ) const {
00218 return CloudNoise(p/radius*1.4,omega,1);
00219 }
00220
00221
00222 bool Cloud::SphereFunction(const Point &p ) const {
00223 for( int i = 0; i < numSpheres; i++ )
00224 {
00225 if( Vector(p-spheres[i].getPosition()).Length() < spheres[i].getRadius() )
00226 return true;
00227 }
00228 return false;
00229 }
00230
00231 float Cloud::CloudNoise( Point p, const float &omegaValue, int octaves) const {
00232
00233 float sum = 0., lambda = 1., o = 1.;
00234 for (int i = 0; i < octaves; ++i) {
00235 sum += o * Noise(lambda * p);
00236 lambda *= 1.99f;
00237 o *= omegaValue;
00238 }
00239 return sum;
00240 }
00241
00242 }
00243