// *************************************************************************** void CVegetable::generateGroupEx(float nbInst, const CVector &posInWorld, const CVector &surfaceNormal, uint vegetSeed, std::vector<CVector2f> &instances) const { nlassert(_Manager); // Density modulation. //=================== // compute cos of angle between surfaceNormal and K(0,0,1). float cosAngle= surfaceNormal.z; // compute angleFactor density. Use a quadratic, because f'(_CosAngleMiddle)==0. float angleFact= 1 - sqr((cosAngle - _CosAngleMiddle) * _OOCosAngleDist); angleFact= max(0.f, angleFact); // modulate density with angleFactor. nbInst*= angleFact; // modulate result by Global Manager density nbInst*= _Manager->getGlobalDensity(); // Now, 0<=nbInst<+oo. If we have 0.1, it means that we have 10% chance to spawn an instance. // So add a "random" value (with help of a noise with High frequency) // if nbInst==0, we should never have any instance (which may arise if evalOneLevelRandom()==1). // hence the 0.99f* which ensure that we do nbInst+= [0..1[. nbInst+= 0.99f * RandomGenerator.evalOneLevelRandom(posInWorld); // and then get only the integral part. sint nbInstances= NLMISC::OptFastFloor(nbInst); nbInstances= max(0, nbInstances); // resize the instances instances.resize(nbInstances); // Position generation. //=================== // For now, generate them randomly. static CVector2f dSeed(0.513f, 0.267f); // random values. CVector seed= posInWorld; seed.z+= vegetSeed * 0.723f; // 0.723f is a random value. for(sint i=0; i<nbInstances; i++) { instances[i].x= RandomGenerator.evalOneLevelRandom(seed); seed.x+= dSeed.x; instances[i].y= RandomGenerator.evalOneLevelRandom(seed); seed.y+= dSeed.y; } }
// *************************************************************************** void CVegetable::generateGroupBiLinear(const CVector &posInWorld, const CVector posInWorldBorder[4], const CVector &surfaceNormal, float area, uint vegetSeed, std::vector<CVector2f> &instances) const { sint i; const float evenDistribFact= 12.25f; // an arbitrary value to have a higher frequency for random. // compute how many instances to generate on borders of the patch // ================== float edgeDensity[4]; for(i=0; i<4; i++) { // Get number of instances generated on edges edgeDensity[i]= area * Density.eval(posInWorldBorder[i]); if(MaxDensity >= 0) edgeDensity[i]= min(edgeDensity[i], area * MaxDensity); edgeDensity[i]= max(0.f, edgeDensity[i]); } // Average on center of the patch for each direction. float edgeDensityCenterX; float edgeDensityCenterY; edgeDensityCenterX= 0.5f * (edgeDensity[0] + edgeDensity[1]); edgeDensityCenterY= 0.5f * (edgeDensity[2] + edgeDensity[3]); // Average for all the patch float nbInstAverage= 0.5f * (edgeDensityCenterX + edgeDensityCenterY); // generate instances on the patch // ================== generateGroupEx(nbInstAverage, posInWorld, surfaceNormal, vegetSeed, instances); // move instances x/y to follow edge repartition // ================== // If on a direction, both edges are 0 density, then must do a special formula bool middleX= edgeDensityCenterX<=1; bool middleY= edgeDensityCenterY<=1; float OOEdgeDCX=0.0; float OOEdgeDCY=0.0; if(!middleX) OOEdgeDCX= 1.0f / edgeDensityCenterX; if(!middleY) OOEdgeDCY= 1.0f / edgeDensityCenterY; // for all instances for(i=0; i<(sint)instances.size(); i++) { float x= instances[i].x; float y= instances[i].y; // a seed for random. CVector randSeed(x*evenDistribFact, y*evenDistribFact, 0); // X change. if(middleX) { // instances are grouped at middle. this is the bijection of easeInEaseOut x= x+x - easeInEaseOut(x); x= x+x - easeInEaseOut(x); instances[i].x= x; } else { // Swap X, randomly. swap more on border // evaluate the density in X direction we have at this point. float densX= edgeDensity[0]*(1-x) + edgeDensity[1]* x ; // If on the side of the lowest density if(densX < edgeDensityCenterX) { // may swap the position float rdSwap= (densX * OOEdgeDCX ); // (densX * OOEdgeDCX) E [0..1[. The more it is near 0, the more is has chance to be swapped. rdSwap+= RandomGenerator.evalOneLevelRandom( randSeed ); if(rdSwap<1) instances[i].x= 1 - instances[i].x; } } // Y change. if(middleY) { // instances are grouped at middle. this is the bijection of easeInEaseOut y= y+y - easeInEaseOut(y); y= y+y - easeInEaseOut(y); instances[i].y= y; } else { // Swap Y, randomly. swap more on border // evaluate the density in Y direction we have at this point. float densY= edgeDensity[2]*(1-y) + edgeDensity[3]* y ; // If on the side of the lowest density if(densY < edgeDensityCenterY) { // may swap the position float rdSwap= (densY * OOEdgeDCY); // (densY * OOEdgeDCY) E [0..1[. The more it is near 0, the more is has chance to be swapped. rdSwap+= RandomGenerator.evalOneLevelRandom( randSeed ); if(rdSwap<1) instances[i].y= 1 - instances[i].y; } } } }