void WorldRenderer::GenerateGrass(const Vector2UINT& sectorCoords) { // Grass Turned Off if ( !zGrassDensity ) { return; } // Delete previous grass if existing. auto grassIterator = this->zGrass.find(sectorCoords); // Create Sector Rect Rect sectorRect; sectorRect.topLeft.x = (float)sectorCoords.x * FSECTOR_WORLD_SIZE; sectorRect.topLeft.y = (float)sectorCoords.y * FSECTOR_WORLD_SIZE; sectorRect.size.x = FSECTOR_WORLD_SIZE; sectorRect.size.y = FSECTOR_WORLD_SIZE; // Check if inside clip range Circle clipCircle(zGraphics->GetCamera()->GetPosition().GetXZ(), zGrassFarDistance); // Check Intersection if ( !DoesIntersect(sectorRect, clipCircle) ) { if ( grassIterator != this->zGrass.end() ) { // Remove from graphics engine. this->zGraphics->DeleteBillboardCollection(grassIterator->second); // Remove from map. this->zGrass.erase(grassIterator); } return; } // Delete Old Grass if( grassIterator != this->zGrass.end() ) { // Remove from graphics engine. this->zGraphics->DeleteBillboardCollection(grassIterator->second); // Reset grassIterator->second = 0; } // First check if the sector has any grass texture Sector* sector = this->zWorld->GetSector(sectorCoords); bool found = false; for(unsigned int i = 0; i < SECTOR_BLEND_CHANNELS && !found; ++i) { if(strcmp(sector->GetTextureName(i), "01_v02-Moss.png") == 0) { found = true; } else if(strcmp(sector->GetTextureName(i), "06_v01-MossDark.png") == 0) { found = true; } else if(strcmp(sector->GetTextureName(i), "07_v01-MossLight.png") == 0) { found = true; } } // No Grass Textures Found if(!found) { return; } float width = FSECTOR_WORLD_SIZE; float depth = FSECTOR_WORLD_SIZE; unsigned int sqrtGrassDensity = (unsigned int)sqrt((long)this->zGrassDensity); float xDiff = width / sqrtGrassDensity; float zDiff = depth / sqrtGrassDensity; Vector2 grassPos = Vector2(0.0f); Vector2 terrainPosXZ = sectorRect.topLeft; float blendValueGrassLight = 0.0f; float blendValueGrassMedium = 0.0f; float blendValueGrassDark = 0.0f; float blendThreshHold = 0.32f; const static float RGB_MIN_MAX = 50.0f / 255.0f; Vector3* positions = new Vector3[this->zGrassDensity]; Vector2* sizes = new Vector2[this->zGrassDensity]; Vector3* colors = new Vector3[this->zGrassDensity]; fast_rand_seed = sectorCoords.x + sectorCoords.y; float rndMaxInv = 1.0f / (float)RAND_MAX; float grassWidth = 0.0f; float grassHeight = 0.0f; float terrainY = 0.0f; Vector2 offsetVector = Vector2(xDiff, zDiff) * 0.5f; unsigned int index = 0; float totBlendValue = 0.0f; //Values taken from average texture color. Vector3 colorGrassLight = Vector3(91.0f, 131.0f, 65.0f) / 255.0f; Vector3 colorGrassMedium = Vector3(107.0f, 142.0f, 77.0f) / 255.0f; Vector3 colorGrassDark = Vector3(68.0f, 104.0f, 45.0f) / 255.0f; Vector3 rndGrassColorOffsetVecGrassLight = Vector3(0.0f, 0.0f, 0.0f); Vector3 rndGrassColorOffsetVecGrassMedium = Vector3(0.0f, 0.0f, 0.0f); Vector3 rndGrassColorOffsetVecGrassDark = Vector3(0.0f, 0.0f, 0.0f); float minMaxDistX = xDiff * 0.5f - zGrassNeightbourDistance * 0.5f; float minMaxDistZ = zDiff * 0.5f - zGrassNeightbourDistance * 0.5f; for(unsigned int x = 0; x < sqrtGrassDensity; ++x) { for(unsigned int z = 0; z < sqrtGrassDensity; ++z) { // Initial position grassPos = terrainPosXZ + Vector2((float)x * xDiff, (float)z * zDiff) + offsetVector; // Move initial position randomly grassPos.x += fastrand() * rndMaxInv * 2.0f * minMaxDistX - minMaxDistX; grassPos.y += fastrand() * rndMaxInv * 2.0f * minMaxDistZ - minMaxDistZ; // Randomize Size grassWidth = fastrand() * rndMaxInv * (zGrassWidthMax-zGrassWidthMin) + zGrassWidthMin; grassHeight = fastrand() * rndMaxInv * (zGrassHeightMax-zGrassHeightMin) + zGrassHeightMin; // Randomize dark grass RGB = rgb[-RGB_MIN_MAX, 0] rndGrassColorOffsetVecGrassDark.y = fastrand() * rndMaxInv * RGB_MIN_MAX - RGB_MIN_MAX; // Randomize medium grass RGB = rgb[-RGB_MIN_MAX / 2, RGB_MIN_MAX / 2] rndGrassColorOffsetVecGrassMedium.y = (fastrand() * rndMaxInv * 2.0f * RGB_MIN_MAX - RGB_MIN_MAX)*0.5f; // Randomize light grass RGB = rgb[0, RGB_MIN_MAX] rndGrassColorOffsetVecGrassLight.y = fastrand() * rndMaxInv * RGB_MIN_MAX; try { terrainY = zWorld->CalcHeightAtWorldPos(grassPos); } catch (...) { continue; } //blendValueGrassLight + blendValueGrassMedium + blendValueGrassDark -> range[0,1] blendValueGrassLight = this->zWorld->GetAmountOfTexture(grassPos, "07_v01-MossLight.png"); blendValueGrassMedium = this->zWorld->GetAmountOfTexture(grassPos, "01_v02-Moss.png"); blendValueGrassDark = this->zWorld->GetAmountOfTexture(grassPos, "06_v01-MossDark.png"); totBlendValue = blendValueGrassLight + blendValueGrassMedium + blendValueGrassDark; if(totBlendValue > blendThreshHold) { //totBlendValue range[blendThreshHold, 1], we want [0,1] float tmp = totBlendValue - blendThreshHold; //range[0, 1 - blendThreshHold]; tmp /= 1.0f - blendThreshHold; totBlendValue = tmp; //Set size grassHeight *= totBlendValue; //modify grass height depending on blend values //If it is below minGrassHeight, don't add it. (It can never be greater than maxHeight) if(grassHeight >= zGrassHeightMin) { sizes[index] = Vector2(grassWidth, grassHeight); //Set position positions[index] = Vector3(grassPos.x, terrainY + grassHeight * 0.5f, grassPos.y); //Set color Vector3 test = (colorGrassLight + rndGrassColorOffsetVecGrassLight) * blendValueGrassLight + (colorGrassMedium + rndGrassColorOffsetVecGrassMedium) * blendValueGrassMedium + (colorGrassDark + rndGrassColorOffsetVecGrassDark) * blendValueGrassDark + Vector3(1.0f, 1.0f, 1.0f) //Color is a multiplier. - Vector3(0.8f, 0.8f, 0.8f); //Adjust ambient & diffuse TTILLMAN colors[index] = test; //Increase index(number of grass objects) index++; } } } } //Add grass //No offset vector needed since grass positions is in world space. if(index > 0) { this->zGrass[sectorCoords] = this->zGraphics->CreateBillboardCollection(index, positions, sizes, colors, Vector3(0.0f, 0.0f, 0.0f), "Media/Grass.png"); this->zGrass[sectorCoords]->SetRenderShadowFlag(false); //Don't render shadows. this->zGrass[sectorCoords]->SetCullFarDistance(zGrassFarDistance); this->zGrass[sectorCoords]->SetCullNearDistance(zGrassNearDistance); } //Delete data delete [] positions; delete [] sizes; delete [] colors; }