Пример #1
0
//------------------------------------------------------------------------
float KdTreeNode::cost(const AxisAlignedBoundingBox& aabb, unsigned int lowerCount, unsigned int greaterCount, float distance, Vector3::AXIS direction) const
{
	float lowerSurfaceArea = aabb.getLowerSubAABB(distance, direction).getSurfaceArea();
	float greaterSurfaceArea = aabb.getGreaterSubAABB(distance, direction).getSurfaceArea();

	return 2.f + 10.f *	(lowerSurfaceArea * lowerCount + greaterSurfaceArea * greaterCount);
}
Пример #2
0
//------------------------------------------------------------------------
void KdTreeNode::build(KdTree* tree, const AxisAlignedBoundingBox& aabb, unsigned int depth)
{
	if (hasToStopBuilding(depth))
	{
		return;
	}

	float subcost  = std::numeric_limits<float>::max();
	float distance = std::numeric_limits<float>::max();

	Vector3::AXIS axis = aabb.getDirection();
	float lowerDistance = aabb.getLowerCorner().get(axis);
	float greaterDistance = aabb.getGreaterCorner().get(axis);

	// m_Spheres are sorted along axis to simplify the splitplane research
	std::sort(m_Spheres->begin(), m_Spheres->end(), [&](const Sphere* s1, const Sphere* s2) {
		return s1->getCenter().get(axis) < s2->getCenter().get(axis);
	});

	unsigned int greaterCount = unsigned int(m_Spheres->size());
	unsigned int lowerCount = 0;

	///////////////////////////
	// Find best split plane //
	///////////////////////////

	for (auto it = m_Spheres->begin(); it != m_Spheres->end(); it++)
	{
		const Sphere* pSphere = *it;
		const AxisAlignedBoundingBox& sphereAABB = pSphere->getAABB();
		float newDistance;
		float newSubcost;

		newDistance = sphereAABB.getLowerCorner().get(axis);

		if (lowerDistance < newDistance && newDistance < greaterDistance)
		{
			newSubcost = cost(aabb, lowerCount, greaterCount, newDistance, axis);

			if (newSubcost < subcost)
			{
				distance = newDistance;
				subcost = newSubcost;
			}
		}

		greaterCount--;
		lowerCount++;

		newDistance = sphereAABB.getGreaterCorner().get(axis);

		if (lowerDistance < newDistance && newDistance < greaterDistance)
		{
			newSubcost = cost(aabb, lowerCount, greaterCount, newDistance, axis);

			if (newSubcost < subcost)
			{
				distance = newDistance;
				subcost = newSubcost;
			}
		}
	}

	// if there is no interesting split
	if (distance <= lowerDistance || greaterDistance <= distance)
	{
		return;
	}

	////////////////////
	// Split the Node //
	////////////////////

	m_Axis = axis;
	m_SplitDistance = distance;

	AxisAlignedBoundingBox boxA = aabb.getLowerSubAABB(distance, axis);
	AxisAlignedBoundingBox boxB = aabb.getGreaterSubAABB(distance, axis);

	m_Nodes = tree->getNextNode();
	tree->getNextNode(); // we allocate a pair, they are next to each other in memory

	for (auto it = m_Spheres->begin(); it != m_Spheres->end(); it++)
	{
		const Sphere* pSphere = *it;

		if (boxA.intersect(*pSphere))
		{
			getA()->add(pSphere);
		}
		if (boxB.intersect(*pSphere))
		{
			getB()->add(pSphere);
		}
	}

	getA()->build(tree, boxA, depth + 1);
	getB()->build(tree, boxB, depth + 1);

	delete m_Spheres;
	m_Spheres = nullptr;
}