LINUX.ORG.RU

Не могу загрузить карту высот в физический движок Bullet

 


0

2

Всем привет. Жизнь столкнула с движком bullet для решения задачи RayCast трехмерных объектов. Так вот. С объектами на поверхности все отлично, однако появилась необходимость решения этой задачи с самой земной поверхностью. Пока она была плоской все хорошо, но я решил ввести карту высот и тут беда. Нашел в Bullet класс btHeightfieldTerrainShape, но у него куча недостатков, из-за которых вам и пишу:

1) Используется HeightMap 256x256. После введения класса fps спрыгнул с 300+ до 20. Вообще использовать класс btHeightfieldTerrainShape разумно или я отсталый и так никто не делает?

2) Сама HeightMap построена верно (рендер проходит норм), но в буллет она не грузится (взаимодействие идет с плоскостью без всякого изменения высоты).

Код загрузки местности в буллет привожу ниже. Он честно взят из демки к движку (в демке он так же после раскрытия дефайна не работал). Что я делаю не так?

int BulletEngineCore::LoadTerrain(HeightMap * hm, float xMin, float zMin, float size)
{
	int upAxis = 1; 
	bool useFloatData = false;
	bool flipQuadEdges = false;

	btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(hm->Width(), hm->Height(),
		hm->DataUnChar(), hm->GetMaxHeight(), upAxis, useFloatData,	flipQuadEdges);

	btVector3 mmin,mmax;
	heightFieldShape->getAabb(btTransform::getIdentity(), mmin, mmax);

	heightFieldShape->setUseDiamondSubdivision(true);


	btVector3 localScaling(1,1,1);
	localScaling[upAxis] = hm->GetScale();

	btCollisionShape* groundShape = heightFieldShape;
	groundShape->setLocalScaling(localScaling);
	_collisionShapes.push_back(groundShape);

	btTransform startTransform;
	startTransform.setIdentity();
	startTransform.setOrigin(btVector3(xMin, hm->GetMinHeight() * hm->GetScale(), zMin));

	btScalar mass=0.f;
	btVector3 localInertia(0,0,0);

	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,0, groundShape,localInertia);
	rbInfo.m_startWorldTransform = startTransform;
	btRigidBody* body = new btRigidBody(rbInfo);
	_dynamicsWorld->addRigidBody(body);

	++PhysTexID;
	return PhysTexID - 1;
}

Видимо не тот форум выбрал

Решил сделать в лоб. По времени вроде не затратно, но в целом все-таки неправильно. Суть такая. В случае, если луч с остальными объектами не пересекается (bullet нам об этом скажет), то выбираем максимальную длину луча dist для проверки пересечения с землей (у меня dist = 2.5 км). Иначе, если луч пересекается c каким-нибудь объектом, то dist = расстоянию до этого объекта. Далее итеративно (мне хватает итерации i = 1 метр) проверяем, находится ли i-тая точка луча под землей. Время выполнения в худшем случае (когда dist = 2.5) равно 1ms для одного луча. Криво, но работает. Будут какие идеи, тема актуальна, рад буду услышать другие мнения

Burns
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.