예제 #1
0
// Right now there are some inconsistencies in the way this function behaves
// compared to the OBB-OBB version. I think this one is correct, but it's tough to tell...
std::list<Contact> OBB::GetClosestPoints(const AABB& other) const {
	std::list<Contact> ret;

	// Find the vector from our center to theirs
	vec2 centerVecN = other.C - C;
	vec2 faceN(0);
	// Make it a unit vector in the direction of largest magnitude
	faceN = glm::normalize(maxComp(centerVecN));

	// Get supporting vertex / vertices along that direction
	std::array<int, 2> sV;
	int nSupportVerts = GetSupportIndices(faceN, sV);

	// one support vert means a vertex-face collision
	if (nSupportVerts == 1) {
		// Two contact points; the support vertex, and it's best neighbor
		std::array<glm::vec2, 2> pA_arr = GetSupportNeighbor(faceN, sV[0]);
		for (auto& pA : pA_arr) {
			vec2 pB = other.clamp(pA);
			float d = glm::distance(pA, pB);
			ret.emplace_back((RigidBody_2D *)this, (RigidBody_2D *)&other, pA, pB, faceN, d);
		}
	}
	// face-face collsion, average two support verts into one contact point
	else {
		vec2 pA = 0.5f * (GetVert(sV[0]) + GetVert(sV[1]));
		vec2 pB = other.clamp(pA);
		float d = glm::distance(pA, pB);
		ret.emplace_back((RigidBody_2D *)this, (RigidBody_2D *)&other, pA, pB, faceN, d);
	}

	return ret;
}
예제 #2
0
// Indices of the vertices returned by the above function
int OBB::GetSupportIndices(vec2 n, std::array<int, 2>& sV) const {
	// Find the furthest vertex
	float dMin = -FLT_MAX;
	for (int i = 0; i < 4; i++) {
		vec2 v = GetVert(i);
		float d = glm::dot(n, v);
		if (d > dMin) {
			dMin = d;
			sV[0] = i;
		}
	}

	int num(1);

	// If there's a different vertex
	for (int i = 0; i < 4; i++) {
		if (i == sV[0])
			continue;
		vec2 v = GetVert(i);
		float d = glm::dot(n, v);
		// That's pretty close...
		if (feq(d, dMin, 100.f * kEPS)) {
			// Take it too
			dMin = d;
			sV[num++] = i;
		}
	}

	return num;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CVRADDispColl::DispUVToSurfDiagonalTLtoBR( int snapU, int snapV, int nextU, int nextV,
											    float fracU, float fracV, Vector &surfPt, 
												float pushEps )
{
	// get displacement width
	int width = GetWidth();

	if( ( fracU + fracV ) >= ( 1.0f + TRIEDGE_EPSILON ) )
	{
		int triIndices[3];
		triIndices[0] = nextV * width + snapU;
		triIndices[1] = nextV * width + nextU;
		triIndices[2] = snapV * width + nextU;

		Vector triVerts[3];
		for( int i = 0; i < 3; i++ )
		{
			GetVert( triIndices[i], triVerts[i] );
		}

		Vector edgeU, edgeV;
		edgeU = triVerts[0] - triVerts[1];
		edgeV = triVerts[2] - triVerts[1];

		surfPt = triVerts[1] + edgeU * ( 1.0f - fracU ) + edgeV * ( 1.0f - fracV );

		// get face normal and push point away from surface the given pushEps
		Vector vNormal;
		vNormal = CrossProduct( edgeU, edgeV );
		VectorNormalize( vNormal );
		surfPt += ( vNormal * pushEps );
	}
	else
	{
		int triIndices[3];
		triIndices[0] = snapV * width + snapU;
		triIndices[1] = nextV * width + snapU;
		triIndices[2] = snapV * width + nextU;

		Vector triVerts[3];
		for( int i = 0; i < 3; i++ )
		{
			GetVert( triIndices[i], triVerts[i] );
		}

		Vector edgeU, edgeV;
		edgeU = triVerts[2] - triVerts[0];
		edgeV = triVerts[1] - triVerts[0];

		// get the position
		surfPt = triVerts[0] + edgeU * fracU + edgeV * fracV;

		// get face normal and push point away from surface the given pushEps
		Vector vNormal;
		vNormal = CrossProduct( edgeU, edgeV );
		VectorNormalize( vNormal );
		surfPt += ( vNormal * pushEps );
	}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CVRADDispColl::ClosestBaseFaceData( Vector const &worldPt, Vector &closePt, 
										 Vector &closeNormal )
{
	Vector delta;
	float minDist = 99999.0f;
	int ndxMin = -1;
	for( int ndxPt = 0; ndxPt < 4; ndxPt++ )
	{
		delta = worldPt - m_Points[ndxPt];
		float dist = delta.Length();
		if( dist < minDist )
		{
			minDist = dist;
			ndxMin = ndxPt;
		}
	}

	int width = GetWidth();
	int height = GetHeight();

	switch( ndxMin )
	{
	case 0: { ndxMin = 0; break; }
	case 1: { ndxMin = ( height - 1 ) * width; break; }
	case 2: { ndxMin = ( height * width ) - 1; break; }
	case 3: { ndxMin = width - 1; break; }
	default: { return; }
	}

	GetVert( ndxMin, closePt );
	GetVertNormal( ndxMin, closeNormal );
}
예제 #5
0
void CSubTriangle::GetDivision(int& o_nStartOfLongest, CVector3DF& o_vMidPoint, CVector3DF& o_vMidPointBar) const
{	
    //get parent bezier patch
    //    const CBezierPatch& ParentBezierPatch = m_pParent_SubTriangle ? m_pParent_SubTriangle->GetBezierPatch() : m_Parent.GetBezierPatch();
    float fDistance = 0.0f;

    CVector3DF vMidPointBar, vMidPoint;

    for (int i = 0; i < 3; i++)
    {
        const int j = (i + 1) % 3;

        vMidPointBar = (GetVertBar(i) + GetVertBar(j)) / 2.0f;
        vMidPoint = m_Parent.GetBezierPatch().GetPointFromBarycentric(vMidPointBar);

        const float fNewDistance = (GetVert(i) - vMidPoint).Length();// this should work with bezier stuff

        if (fNewDistance > fDistance)
        {
            fDistance = fNewDistance;
            o_nStartOfLongest = i;
            o_vMidPoint = vMidPoint;
            o_vMidPointBar = vMidPointBar;
        }
    }
}
예제 #6
0
// Pick the best support neighbor along n
// It's critical that this function return an array where the vertices
// are in the proper clockwise order
std::array<vec2, 2> OBB::GetSupportNeighbor(vec2 n, int idx) const {
	std::array<vec2, 2> ret;

	vec2 vb = GetVert(idx);
	vec2 va = GetVert(idx - 1);
	vec2 vc = GetVert(idx + 1);

	vec2 nab = glm::normalize(perp(vb - va));
	vec2 nbc = glm::normalize(perp(vc - vb));
	float d1 = glm::dot(nab, n);
	float d2 = glm::dot(nbc, n);

	if (d1 > d2)
		return{ { va, vb } };
	return{ { vb, vc } };
}
예제 #7
0
// Not tested, and there may be a better way...
bool IsOverlapping( Circle * pCirc, OBB * pOBB )
{
	for ( int i = 0; i < 4; i++ )
		if ( IsPointInside( GetVert( pOBB, i ), pCirc ) )
			return true;
	return IsPointInside( pCirc->v2Center, pOBB );
}
예제 #8
0
//-----------------------------------------------------------------------------
void CCollision::Resolve()
{
	CIwManaged::Resolve();
	
	IwResolveManagedHash(&m_pModel, IW_GRAPHICS_RESTYPE_MODEL);

	//Build face normals (done on resolve to save disk space)
	for(uint32 i = 0; i < m_Points.size(); i+=3)
	{
		CIwVec3 v1 = (CIwVec3)GetVert(i);
		CIwVec3 v2 = (CIwVec3)GetVert(i+1);
		CIwVec3 v3 = (CIwVec3)GetVert(i+2);

		CIwSVec3 cross = (CIwSVec3)(v2 - v1).Cross(v3 - v1);
		if( cross != CIwSVec3::g_Zero )
			cross.Normalise();
		m_Norms.push_back(cross);
	}
}
예제 #9
0
void OpenGLRect::DrawMyBothRect(const float& fLineWidth /*= 1.0f*/)
{
	GetVert(m_fRectVert);
	GetColor(m_fRectColor);
	DrawMyRect(1.0f, GL_QUADS);

	GetBorderVert(m_fRectVert);
	GetBorderColor(m_fRectColor);
	DrawMyRect(fLineWidth);
}
예제 #10
0
// Resolve ghost modelspace location
void GhostCollision::ResolveLocation() {

	float y1 = INT32_MAX;
	float y2 = INT32_MIN;
	float x1 = INT32_MAX;
    float x2 = INT32_MIN;

    for (uint32 i = 0; i < m_Points.size(); i++)
    {
        CIwFVec3 v = (CIwFVec3)GetVert(i);

		if (v.y < y1) y1 = v.y;
		if (v.y > y2) y2 = v.y;
		if (v.x < x1) x1 = v.x;
		if (v.x > x2) x2 = v.x;
    }

	ghostY = y2;
	ghostX = x1;
	ghostW = x2 - x1;
}
예제 #11
0
bool CSubTriangle::Intersect(const CRay &ray, CIntersactionInfo &intersectionInfo, bool bDebug) const
{
//    intersectionInfo.m_nBezierIntersections += 1;
//    QElapsedTimer timer;
//    timer.start();

    bool bIntersect = false;
    if (intersectionInfo.m_bHighQuality)
    {
       bIntersect = m_Parent.GetBezierPatch().IntersectHighQuality(ray, intersectionInfo, *this, bDebug);

//        if (b && GetSettings()->m_bNormalSmoothing)
//        {
//            intersectionInfo.m_vNormal = GetSubSurfSmoothedNormal(intersectionInfo.m_vBarCoordsGlobal);
//        }
    }
    else
    {
        bIntersect = CUtils::IntersectTriangle(ray, intersectionInfo, GetVert(0), GetVert(1), GetVert(2), m_vABar, m_vBBar, m_vCBar);

        if (bIntersect)
        {
            if (GetSettings()->m_bNormalSmoothing)
            {
                //Smoothed normal
                CVector3DF vNormalA = intersectionInfo.m_vBarCoordsGlobal.X() * m_Parent.A().Normal_Get();
                CVector3DF vNormalB = intersectionInfo.m_vBarCoordsGlobal.Y() * m_Parent.B().Normal_Get();
                CVector3DF vNormalC = intersectionInfo.m_vBarCoordsGlobal.Z() * m_Parent.C().Normal_Get();
                intersectionInfo.m_vNormal = vNormalA + vNormalB + vNormalC;
                intersectionInfo.m_vNormal.Normalize();
            }
            else
            {
                CVector3DF m_vAB = GetVert(1)- GetVert(0);
                CVector3DF m_vAC = GetVert(2)- GetVert(0);
                intersectionInfo.m_vNormal = CVector3DF::Normal(m_vAB, m_vAC);
            }
        }
    }

//    intersectionInfo.m_nObjTime += timer.nsecsElapsed();
    return bIntersect;
}
예제 #12
0
void OpenGLRect::DrawMyFillRect(void)
{
	GetVert(m_fRectVert);
	GetColor(m_fRectColor);
	DrawMyRect(1.0f, GL_QUADS);
}
예제 #13
0
// Simlar to the AABB case, but we only care about the center of the circle
std::list<Contact> GetSpecContacts( Circle * pCirc, AABB *  pAABB)
{
	// Determine which feature region we're on
	vec2 n;
	int vIdx( -1 );

	// top/bottom face region
	if ( (pAABB->Right() < pCirc->v2Center.x || pAABB->Left() > pCirc->v2Center.x) == false )
	{
		// Circle is below box
		if ( pCirc->v2Center.y < pAABB->Bottom() )
		{
			vIdx = 1;
			n = vec2( 0, 1 );
		}
		else
		{
			vIdx = 3;
			n = vec2( 0, -1 );
		}
	}
	// left/right face region
	else if ( (pAABB->Top() < pCirc->v2Center.y || pAABB->Bottom() > pCirc->v2Center.y) == false )
	{
		// Circle is to the left of the box
		if ( pCirc->v2Center.x < pAABB->Left() )
		{
			vIdx = 2;
			n = vec2( 1, 0 );
		}
		else
		{
			vIdx = 0;
			n = vec2( -1, 0 );
		}
	}
	// Vertex region
	else
	{
		// Determine which vertex
		bool bAIsLeft = (pCirc->v2Center.x < pAABB->Left());
		bool bAIsBelow = (pCirc->v2Center.y < pAABB->Bottom());
		if ( bAIsLeft )
		{
			if ( bAIsBelow )
				vIdx = 2;
			else
				vIdx = 3;
		}
		else
		{
			if ( bAIsBelow )
				vIdx = 1;
			else
				vIdx = 0;
		}

		// We don't need to average contact positions for the corner case
		vec2 posB = GetVert( pAABB, vIdx );
		n = glm::normalize( posB - pCirc->v2Center );
		vec2 posA = pCirc->v2Center + pCirc->circData.fRadius * n;
		float fDist = glm::distance( posA, posB );
		return{ Contact( pCirc, pAABB, posA, posB, n, fDist ) };
	}
	// For a face region collision, we want to make sure the contact knows it's
	// working with one of the box's face normals (meaning distance is along that normal)
	vec2 posB = 0.5f*(GetVert( pAABB, vIdx ) + GetVert( pAABB, vIdx + 1 ));
	//n = glm::normalize( posB - pCirc->v2Center );
	vec2 posA = pCirc->v2Center + pCirc->circData.fRadius * n;
	float fDist = glm::dot( posB - posA, n );
	return{ Contact( pCirc, pAABB, posA, posB, n, fDist ) };
}
예제 #14
0
//-----------------------------------------------------------------------------
int32 GhostCollision::GetFaceUnderCursor(int32 x, int32 y)
{
    //Calculate pos/dir of cursor from camera
    CIwFVec3 pos = IwGxGetViewMatrix().t;
    CIwFVec3 dir(x, y, IwGxGetPerspMul());
    dir.x -= IwGxGetScreenWidth()/2;
    dir.y -= IwGxGetScreenHeight()/2;

    //Extend to the far plane
    dir *= IW_FIXED_DIV(IwGxGetFarZ(), IwGxGetPerspMul());

    //Transform pos/dir into model space
    dir = IwGxGetViewMatrix().RotateVec(dir);
    dir = modelMatrix->TransposeRotateVec(dir);

    //Use more accurate normalise
    dir.Normalise();

    // Scale to touch far plane
    dir *= IwGxGetFarZ();

    pos = modelMatrix->TransposeTransformVec(pos);

    //find first face intersection
    int32 minf = INT32_MAX; //nearest intersection distance
    uint32 nearest = 0; //nearest intersection index

    for (uint32 i = 0; i < m_Points.size(); i += 3)
    {
        CIwFVec3 v1 = (CIwFVec3)GetVert(i);
        CIwFVec3 v2 = (CIwFVec3)GetVert(i+1);
        CIwFVec3 v3 = (CIwFVec3)GetVert(i+2);

        float f = 0;
        if (IwIntersectLineTriNorm(pos, dir, v1, v2, v3, m_Norms[i/3], f)) {
            if (f < minf)
            {
                minf = f;
                nearest = i;
            }
        }

		/*{ // Draw the custom resource. Kills fps but helps debugging.
			CIwMaterial* pMat = IW_GX_ALLOC_MATERIAL();
			pMat->SetColAmbient(0xff0000ff);
			pMat->SetCullMode(CIwMaterial::CULL_NONE);
			IwGxSetMaterial(pMat);

			CIwFVec3* verts = IW_GX_ALLOC(CIwFVec3, 3);
			verts[0] = v1;
			verts[1] = v2;
			verts[2] = v3;
			IwGxSetVertStreamModelSpace(verts, 3);
			IwGxDrawPrims(IW_GX_TRI_LIST, NULL, 3);
		}*/
    }

    if (minf != INT32_MAX)
    {
        return nearest;
    }

    return -1;
}