English

OpenGL game

Test kolize paprsku (polopřímky) s koulí

Zdroják enginu ke stažení (711,5kB)

14.11.2006

Ukážeme si, jak zjistit kolizi paprsku (polopřímky) s koulí. Tuto kolizi lze ve hrách použít například pro míření na určité objekty ve scéně, kdy paprsek vychází z pozice kamery a míří do nekonečna před kameru. Testujeme kolizi tohoto paprsku s kolizní koulí objektu.

1. Paprsek a koule mají tuto strukturu:

class K3dRay
{
	// Ray is R(t) = P+t*D for t >= 0.  D is not necessarily unit length.

    K3dVector3 m_kOrigin;  // P
    K3dVector3 m_kDirection;  // D
public:
	K3dRay(K3dVector3 &_rkOrigin, K3dVector3 &_rkDirection)
	{
		m_kOrigin = _rkOrigin;
		m_kDirection = _rkDirection;
	}
	K3dRay()
	{
		m_kOrigin.Reset();
		m_kDirection.Reset();
	}
	~K3dRay() {}

	K3dVector3& GetOrigin()
	{
		return m_kOrigin;
	}

	const K3dVector3& GetOrigin() const
	{
		return m_kOrigin;
	}

	K3dVector3& GetDirection()
	{
		return m_kDirection;
	}

	const K3dVector3& GetDirection() const
	{
		return m_kDirection;
	}
};



class K3dSphere
{
	K3dVector3 m_kPosition;	///< Sphere position
	float m_fRadius;	///< Sphere radius
	
	public:		
		K3dSphere()
		{
			m_kPosition.Reset();
			m_fRadius = (float) 32;
		}
		K3dSphere(const K3dVector3 &_rkPosition, const float _fRadius)
		{
			m_kPosition = _rkPosition;
			m_fRadius = _fRadius;
		}
		~K3dSphere()
		{
		}

		///\brief Get or set sphere position
		K3dVector3 &GetPosition()
		{
			return m_kPosition;
		}
		const K3dVector3 &GetPosition() const
		{
			return m_kPosition;
		}

		///\brief Get or set sphere radius
		float &GetRadius()
		{
			return m_fRadius;
		}
		const float &GetRadius() const
		{
			return m_fRadius;
		}
};


2. Potřebujeme vypočítat dot produkt (skalární součin) 3D vektorů, kdy vstupní vektor bude direction (směrový) vektor paprsku a vektor
float m_afVector[3] bude rozdíl mezi pozicí paprsku a pozicí kamery.:

///\brief Calculate dot product between two vectors
float K3dVector3::Dot(const K3dVector3 &_rkVector)
{
	float fX,fY, fZ, fResult;

	fX = m_afVector[0] * _rkVector.m_afVector[0];
	fY = m_afVector[1] * _rkVector.m_afVector[1];
	fZ = m_afVector[2] * _rkVector.m_afVector[2];

	fResult = fX + fY + fZ;
	return fResult;
}


3. Potřebujeme vypočítat délku vektoru na druhou:

///\brief Calc vector square length
float K3dVector3::SquaredLength ()
{
	float fSqrLen = 0.0f;
	for (int i = 0; i < 3; i++)
		fSqrLen += (float) m_afVector[i]*m_afVector[i];
	return fSqrLen;
}


4. Potřebujeme vypočítat vzdálenost paprsku a bodu, kdy bod bude pozice kamery:

///\brief Calculate squared distance between point and ray
float SqrPointRay(const K3dVector3 &_rkPoint,const K3dRay &_rkRay, float* _pfParam=NULL)
{
	float fDotMM;
	float fT = (float) 0;
	K3dVector3 kDiff;
			
	kDiff = _rkPoint - _rkRay.GetOrigin();
	fT = kDiff.Dot(_rkRay.GetDirection());
		
			
	if ( fT <= (float)0.0 )
	{
		fT = (float)0.0;
	}
	else
	{
		fDotMM = _rkRay.GetDirection().SquaredLength();
		if(fDotMM)
		{
			fT = fT / fDotMM;
			kDiff -= _rkRay.GetDirection()*fT;
		}
	}
		
	if ( _pfParam )
		*_pfParam = fT;
		
	return kDiff.SquaredLength();
}


5. Konečný výpoček kolize paprsku s koulí vypadá následovně:

///\brief Test intersection between ray and sphere
bool K3dIntrLinSph::TestIntersection(const K3dRay &_rkRay, const K3dSphere &_rkSphere)
{
	K3dDistance kDistance;
	float fSqrDist = (float) 0;
	float fSqr = (float) 0;

	fSqrDist = kDistance.SqrPointRay(_rkSphere.GetPosition(),_rkRay, 0);
	fSqr = _rkSphere.GetRadius()*_rkSphere.GetRadius();
	if(fSqrDist<=fSqr)
	{
		return true;
	}
	return false;
}



home / opengl game


Valid XHTML 1.0 Transitional