bool Sphere::intersect(const Ray &ray, Intersection &iSect) const { vec3 C, SP; float r, b, d, t; // Get sphere center in world space C = m_centerTransformed; // Transform ray origin to object space SP = C - ray.getOrigin(); // Get transformed radius r = m_radiusTransformed; // Solve the quadratic equation for t b = vec3::dot(SP, ray.getDirection()); d = b * b - vec3::dot(SP, SP) + r * r; if (d < 0.0f) { return false; } d = std::sqrt(d); t = (t = b - d) > EPSILON ? t : ((t = b + d) > EPSILON ? t : -1.0f); if (t == -1.0f) { return false; } // Set final surface intersection info iSect.setT(t); iSect.setPosition(ray(t)); iSect.setNormal((iSect.getPosition() - C) / r); iSect.setMaterial(m_material); return true; }
Chunk *ChunkGenerator::generateChunk(City *city, const Vector2 &position) { // First we check if position is valid (if both X and Y are multiple of 1000) if ((int) position.x % 1000 != 0 || (int) position.y % 1000 != 0) { return nullptr; } // And also if this chunk doesn't already exists if (FileIO::fileExists(Chunk::getFileName(position))) { return nullptr; } Profiler::getTimer(3)->startMeasurement(); /* * Generate Intersections and Roads */ //TODO: Put this condition on the different grid layout generators. Each may have different limits int minDistanceIntersections = 50; // Minimum distance between intersections Chunk *chunk = new Chunk(position, city); std::vector<Chunk*> neighbourChunks = city->getNeighbourChunks(chunk, true); ManhattanGridLayout gridLayout = ManhattanGridLayout(Vector2(), Vector2()); int numSubChunks = Chunk::CHUNK_SIZE / Chunk::SUBCHUNK_SIZE; float subChunkSize = (float) Chunk::SUBCHUNK_SIZE; for (int i = 0; i < numSubChunks; i++) { for (int j = 0; j < numSubChunks; j++) { // Calculate the position of the new intersection on this subchunk gridLayout.posMin = Vector2(i * subChunkSize, j * subChunkSize); gridLayout.posMax = Vector2((i + 1) * subChunkSize, (j + 1) * subChunkSize); Vector2 intersectionPos = gridLayout.getIntersectionPosition(); float den = Perlin::getCityBlockDensity(intersectionPos.x + position.x, intersectionPos.y + position.y); if (intersectionPos.x > -99 && intersectionPos.y > -99 && den > 0.0f) { // If there's an intersection in this subchunk, check if it has enough distance from the others intersectionPos += position; // Convert to World Position auto it = chunk->getIntersections()->begin(); auto itEnd = chunk->getIntersections()->end(); bool tooClose = false; Vector3 newIntPos = Vector3(intersectionPos.x, 0, intersectionPos.y); for (; it != itEnd; it++) { Intersection *intersection = (*it); // Chunk position for the new intersection position (0 to 1000) float length = (intersection->getPosition() - newIntPos).getLength(); //std::cout << length << std::endl; if (length < minDistanceIntersections) { tooClose = true; break; } } if (!tooClose) { // If the new intersections is sufficiently distant from all the others, proceed Intersection *newInter = nullptr; Intersection *neighbourSubstitute = nullptr; // Check if the new Intersection is too close to any Intersection on the neighbours for (auto it = neighbourChunks.begin(); it != neighbourChunks.end(); it++) { Intersection *closest = (*it)->getClosestIntersectionTo(newIntPos); if (closest != nullptr) { float distance = (closest->getPosition() - newIntPos).getLength(); if (distance < minDistanceIntersections) { // The new Intersection is too close to an Intersection on an neighbour. Use the // neighbour's Intersection instead neighbourSubstitute = closest; break; } } } if (neighbourSubstitute != nullptr) { newInter = neighbourSubstitute; } else { newInter = new Intersection(newIntPos); } chunk->addIntersection(newInter); gridLayout.generateRoads(chunk, newInter); } } } } //Profiler::getTimer(3)->finishMeasurement(); //Profiler::getTimer(3)->resetCycle(); //std::cout << chunk->getChunkPos() << " generated in " << Profiler::getTimer(3)->getAverageTime() << "ms" << std::endl; //return chunk; /* * Generate City Blocks and Buildings */ auto itEnd = chunk->getIntersections()->end(); for (auto it = chunk->getIntersections()->begin(); it != itEnd; it++) { CityBlock *cityBlock = gridLayout.generateCityBlock(chunk, (*it)); if (cityBlock != nullptr) { // Check if this CityBlock has any Intersections that are in mutiple Chunks. If it does, add the CityBlock to // those Chunks /*Intersection *multiIntersection = nullptr; for (auto it = cityBlock->getVertices()->begin(); it != cityBlock->getVertices()->end(); it++) { if ((*it)->getNumChunksSharing() > 1) { multiIntersection = *it; } } if (multiIntersection != nullptr) { for (auto it = neighbourChunks.begin(); it != neighbourChunks.end(); it++) { if ((*it)->hasIntersection(multiIntersection)) { (*it)->addCityBlock(cityBlock); } } }*/ auto itEndC = chunk->getCityBlocks()->end(); bool duplicate = false; for (auto itC = chunk->getCityBlocks()->begin(); itC != itEndC; itC++) { if ((*itC)->getCentralPosition() == cityBlock->getCentralPosition() && (*itC) != cityBlock) { duplicate = true; } } if (!duplicate) { cityBlock->generateBuildings(); } else { chunk->removeCityBlock(cityBlock); delete cityBlock; } } } Profiler::getTimer(3)->finishMeasurement(); Profiler::getTimer(3)->resetCycle(); std::cout << chunk->getChunkPos() << " generated in " << Profiler::getTimer(3)->getAverageTime() << "ms" << std::endl; //std::cout << ResourcesManager::getResourcesCount() << std::endl; return chunk; /* Chunk Generator Algorithm: */ /* * 1 - We try to load the adjacent chunks to detect invalid intersections near the borders. * * 2 - Iterate over the 10x10 grid of partial chunks, calculate the grid layout for each one and call the generator * algorithm of the correct grid layout to generate intersections and roads for each one of the partial chunks. * NOTE: Consider Voronoi Diagram for the GridLayout selector * * 3 - Connect this chunk's intersections with the adjacent chunk's intersections, if the corresponding adjacent * chunk exists. * * 4 - Generate empty city blocks and add everything generated so far to the scene, so it can render something * while we generate the buildings * * 5 - Use the grid layout and city zone to assign a city block type to each city block * * 6 - Generate the buildings for all city blocks * * 7 - Add the new buildings to the scene so it can render everything * * 8 - Save this chunk to its file * * 9 - Update the adjacent chunks with the new edge city blocks, intersections and roads */ }