Example #1
0
bool Actor::patternFracture(const PxVec3& hitLocation, const PxVec3& dirIn, float scale, float vel, float radiusIn)
{
	int compoundNr = -1;
	int convexNr = -1;
	PxVec3 normal;
	float dist;
	bool ret = false;
	PxVec3 dir = dirIn;

	mScene->getScene()->lockWrite();

	bool hit = false;
	if (dir.magnitudeSquared() < 0.5f)
	{
		dir = PxVec3(1.f,0.f,0.f);
		hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
		if(!hit)
		{
			dir = PxVec3(0.f,1.f,0.f);
			hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
			if(!hit)
			{
				dir = PxVec3(0.f,0.f,1.f);
				hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
			}
		}
	}
	else
	{
		hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
	}
	if (hit)
	{
		float radius = mMinRadius + mRadiusMultiplier*radiusIn;
		float impulseMagn = scale*vel*mImpulseScale;

		if (mSheetFracture)
		{
			normal = ((Compound*)mCompounds[(uint32_t)compoundNr])->mNormal;
		}
		PxVec3 a(0.f,0.f,1.f);
		normal.normalize();
		a -= a.dot(normal)*normal;
		if( a.magnitudeSquared() < 0.1f )
		{
			a = PxVec3(0.f,1.f,0.f);
			a -= a.dot(normal)*normal;
		}
		a.normalize();
		PxVec3 b(normal.cross(a));
		PxMat33 trans(a,b,normal);
		ret = base::Actor::patternFracture(hitLocation,dir,compoundNr,trans,radius,impulseMagn,impulseMagn);
	}

	mScene->getScene()->unlockWrite();

	mRenderResourcesDirty = true;

	return ret;
}
void AddRadialImpulseToPxRigidBody_AssumesLocked(PxRigidBody& PRigidBody, const FVector& Origin, float Radius, float Strength, uint8 Falloff, bool bVelChange)
{
#if WITH_PHYSX
	if (!(PRigidBody.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
	{
		float Mass = PRigidBody.getMass();
		PxTransform PCOMTransform = PRigidBody.getGlobalPose().transform(PRigidBody.getCMassLocalPose());
		PxVec3 PCOMPos = PCOMTransform.p; // center of mass in world space
		PxVec3 POrigin = U2PVector(Origin); // origin of radial impulse, in world space
		PxVec3 PDelta = PCOMPos - POrigin; // vector from origin to COM

		float Mag = PDelta.magnitude(); // Distance from COM to origin, in Unreal scale : @todo: do we still need conversion scale?

		// If COM is outside radius, do nothing.
		if (Mag > Radius)
		{
			return;
		}

		PDelta.normalize();

		// Scale by U2PScale here, because units are velocity * mass. 
		float ImpulseMag = Strength;
		if (Falloff == RIF_Linear)
		{
			ImpulseMag *= (1.0f - (Mag / Radius));
		}

		PxVec3 PImpulse = PDelta * ImpulseMag;

		PxForceMode::Enum Mode = bVelChange ? PxForceMode::eVELOCITY_CHANGE : PxForceMode::eIMPULSE;
		PRigidBody.addForce(PImpulse, Mode);
	}
#endif // WITH_PHYSX
}
Example #3
0
void BasicRandom::unitRandomPt(PxVec3& v)
{
	v.x = randomFloat();
	v.y = randomFloat();
	v.z = randomFloat();
	v.normalize();
}
void AddRadialForceToPxRigidBody_AssumesLocked(PxRigidBody& PRigidBody, const FVector& Origin, float Radius, float Strength, uint8 Falloff, bool bAccelChange)
{
#if WITH_PHYSX
	if (!(PRigidBody.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
	{
		float Mass = PRigidBody.getMass();
		PxTransform PCOMTransform = PRigidBody.getGlobalPose().transform(PRigidBody.getCMassLocalPose());
		PxVec3 PCOMPos = PCOMTransform.p; // center of mass in world space
		PxVec3 POrigin = U2PVector(Origin); // origin of radial impulse, in world space
		PxVec3 PDelta = PCOMPos - POrigin; // vector from

		float Mag = PDelta.magnitude(); // Distance from COM to origin, in Unreal scale : @todo: do we still need conversion scale?

		// If COM is outside radius, do nothing.
		if (Mag > Radius)
		{
			return;
		}

		PDelta.normalize();

		// If using linear falloff, scale with distance.
		float ForceMag = Strength;
		if (Falloff == RIF_Linear)
		{
			ForceMag *= (1.0f - (Mag / Radius));
		}

		// Apply force
		PxVec3 PImpulse = PDelta * ForceMag;
		PRigidBody.addForce(PImpulse, bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE);
	}
#endif // WITH_PHYSX
}
Example #5
0
void Enemy::CheckFutureCollision(int attempts)
{
	attempts++;
	if(attempts > 10) return;
	PxVec3 pos = actor->getGlobalPose().p;
	PxVec3 dirMove = PxVec3(moveDir.x,0,moveDir.z);
	while(dirMove.isZero())
	{
		float xspeed = rand()% (int)ceil(movementSpeed); //getal van 0 tot 10
		float xfSpeed = xspeed - (int)ceil(movementSpeed)/2; // getal van -5 tot 5
		float zspeed = rand()%(int)ceil(movementSpeed); //getal van 0 tot 10
		float zfSpeed = zspeed -(int)ceil( movementSpeed)/2; // getal van -5 tot 5
		dirMove = PxVec3(xfSpeed, 0, zfSpeed);
	}
	dirMove.normalize();
	int numHits;
	PxRaycastHit* hit = physics->RaycastMultiple(pos-PxVec3(0,1.5f,0),dirMove,3.5f,&numHits,PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC);
	for(unsigned int i= 0; i < numHits; i++)
	{
		if(hit[i].actor != actor && hit[i].actor != NULL)
		{
			currentMoveTime = 0;	
			float xspeed = rand()% (int)ceil(movementSpeed);		//number from 0 to movementSpeed
			float xfSpeed = xspeed - (int)ceil(movementSpeed)/2;	// number from -movementSpeed/2 to movementSpeed/2
			float zspeed = rand()%(int)ceil(movementSpeed);			
			float zfSpeed = zspeed -(int)ceil( movementSpeed)/2;	
			moveDir = D3DXVECTOR3(xfSpeed, 0, zfSpeed);
			i = 999;
			CheckFutureCollision(attempts);
		}
		
	}
}
Example #6
0
void Enemy::CheckShooting(float dist, float deltaTime)
{

	PxExtendedVec3 tpPos = physics->player->getPosition();
	PxVec3 pPos = playerPos;
	PxVec3 ori = actor->getGlobalPose().p;
	PxVec3 dir = pPos - ori;
	dir.normalize();
	int numHits = 0;
	PxRaycastHit* hit = physics->RaycastMultiple(ori,dir,dist,&numHits, PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC);
	for(unsigned int i = 1; i < numHits; i++)
	{
		if(hit[i-1].actor == actor && hit[i].actor == physics->player->getActor())
		{
			sawPlayer = true;
			lastTimeShot+=deltaTime;
			if(lastTimeShot > shootDelay)
			{
				obj->PlayAnimation("Shoot",true);
				moveDir *= 0.1f;
				if(obj->GetCurrentAnim()->doAction)
				{
					CreateBullet(ori+dir*2,dir);
					currentMoveTime = 9999.0f;
					lastTimeShot = 0;
					resources->GetSoundHandler()->PlayWaveFile("piew");
					obj->GetCurrentAnim()->doAction = false;
				}
			}
		}
	}
}
Example #7
0
        int RayCastManagerImpl::CastRayAgainstCharacterController(const DirectX::XMFLOAT3& p_origin, const DirectX::XMFLOAT3& p_direction, const float& p_range)
        {
            if(p_range <= 0.0f)
            {
                // TODOKO log error
                return -1;
            }
            // Cast directx things to physx
            PxVec3 origin = PxVec3(p_origin.x, p_origin.y, p_origin.z);
            PxVec3 direction = PxVec3(p_direction.x, p_direction.y, p_direction.z);
            direction.normalize();
            PxRaycastBuffer hit; // Used to save the hit
            // casts a ray vs the physics scene. various hit information is saved in the hit variable. For now we only care about the object we hit
            // eMESH_BOTH_SIDES specifices that no culling should be used, shouldnt need to be there but let's be safe
            bool status = m_utils.m_worldScene->raycast(origin, direction, p_range, hit, PxHitFlag::eMESH_BOTH_SIDES);
            // hit.block.position;
            if(!status && !hit.hasBlock)
            {
                // No hit detected, return -1 TODOKO Maybee i should return something better?
                return -1;
            }

            // Now comes the difficult task of checking vs character controllers
            unordered_map<PxController*, int> idsByCharacterController = m_utils.m_characterControlManager->GetIdsByControllers();
            for(auto pairs : idsByCharacterController) // Loop through every pair in the list
            {
                if(pairs.first->getActor() == hit.block.actor) // The first part contains the actor pointer
                {
                    return pairs.second; // If this is true we found a hit vs character controller, second contains ID
                }
            }

            return -1;
        }
Example #8
0
        int RayCastManagerImpl::CastSweep(const XMFLOAT3& p_origin, XMFLOAT3& p_direction, float p_width, const float& p_range, int& o_flag)
        {
            if(p_range <= 0.0f)
            {
                cout << "Physcs. Raytracer. Sweep. Range of sweep was zero or below" << endl;
                return -1;
            }
            // Cast directx things to physx
            PxVec3 origin = PxVec3(p_origin.x, p_origin.y, p_origin.z);
            PxVec3 direction = PxVec3(p_direction.x, p_direction.y, p_direction.z);
            direction.normalize();
            PxSweepBuffer hit; // Used to save the hit
            /// Paramters for the sweep
            // PxGeometry* geometry
            bool status = m_utils.m_worldScene->sweep(PxSphereGeometry(p_width), PxTransform(origin), direction, p_range, hit, PxHitFlag::eMESH_BOTH_SIDES);
            // hit.block.position;
            if(!status && !hit.hasBlock)
            {
                // No hit detected, return -1 TODOKO Maybee i should return something better?
                return -1;
            }

            // Start with checking static and dynamic rigid bodies
            unordered_map<PxRigidActor*, int> idsByRigidBody = m_utils.m_rigidBodyManager->GetIDsByBodies();
            if(idsByRigidBody.find(hit.block.actor) != idsByRigidBody.end())
            {
                PxRigidActor* actorAsRigic = (PxRigidActor*)hit.block.actor;
                if(actorAsRigic->isRigidDynamic())
                {
                    PxRigidDynamic* actorsAsDynamic = (PxRigidDynamic*)hit.block.actor;
                    if(actorsAsDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)
                    {
                        o_flag = 0;
                    }
                }
                else if(actorAsRigic->isRigidStatic())
                {
                    o_flag = 3;
                }
                return idsByRigidBody.find(hit.block.actor)->second;
            }
            else
            {
                // Nothing
            }
            // Now comes the difficult task of checking vs character controllers
            unordered_map<PxController*, int> idsByCharacterController = m_utils.m_characterControlManager->GetIdsByControllers();
            for(auto pairs : idsByCharacterController) // Loop through every pair in the list
            {
                if(pairs.first->getActor() == hit.block.actor) // The first part contains the actor pointer
                {
                    o_flag = 1;
                    return pairs.second; // If this is true we found a hit vs character controller, second contains ID
                }
            }

            return -1;
        }
// -------------------------------------------------------------------------------------
void PolygonTriangulator::importPoints(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal, bool &isConvex)
{
	// find projection 3d -> 2d;
	PxVec3 n;

	isConvex = true;

	if (planeNormal) 
		n = *planeNormal;
	else {
		PX_ASSERT(numPoints >= 3);
		n = PxVec3(0.0f, 0.0f, 0.0f);

		for (int i = 1; i < numPoints-1; i++) {
			int i0 = 0;
			int i1 = i;
			int i2 = i+1;
			if (indices) {
				i0 = indices[i0];
				i1 = indices[i1];
				i2 = indices[i2];
			}
			const PxVec3 &p0 = points[i0];
			const PxVec3 &p1 = points[i1];
			const PxVec3 &p2 = points[i2];
			PxVec3 ni = (p1-p0).cross(p2-p0);
			if (i > 1 && ni.dot(n) < 0.0f)
				isConvex = false;
			n += ni;
		}
	}

	n.normalize();
	PxVec3 t0,t1;

	if (fabs(n.x) < fabs(n.y) && fabs(n.x) < fabs(n.z))
		t0 = PxVec3(1.0f, 0.0f, 0.0f);
	else if (fabs(n.y) < fabs(n.z))
		t0 = PxVec3(0.0f, 1.0f, 0.0f);
	else
		t0 = PxVec3(0.0f, 0.0f, 1.0f);
	t1 = n.cross(t0);
	t1.normalize();
	t0 = t1.cross(n);
	
	mPoints.resize((uint32_t)numPoints);
	if (indices == NULL) {
		for (uint32_t i = 0; i < (uint32_t)numPoints; i++) 
			mPoints[i] = PxVec3(points[i].dot(t0), points[i].dot(t1), 0.0f);
	}
	else {
		for (uint32_t i = 0; i < (uint32_t)numPoints; i++) {
			const PxVec3 &p = points[(uint32_t)indices[i]];
			mPoints[i] = PxVec3(p.dot(t0), p.dot(t1), 0.0f);
		}
	}
}
Example #10
0
PxTransform Camera::getTransform() const
{
	PxVec3 viewY = mDir.cross(PxVec3(0, 1, 0));

	if (viewY.normalize() < 1e-6f)
		return PxTransform(mEye);

	PxMat33 m(mDir.cross(viewY), viewY, -mDir);
	return PxTransform(mEye, PxQuat(m));
}
Example #11
0
static void normalToTangents(const PxVec3& n, PxVec3& t1, PxVec3& t2)
{
	const PxReal m_sqrt1_2 = PxReal(0.7071067811865475244008443621048490);
	if(fabsf(n.z) > m_sqrt1_2)
	{
		const PxReal a = n.y*n.y + n.z*n.z;
		const PxReal k = PxReal(1.0)/PxSqrt(a);
		t1 = PxVec3(0,-n.z*k,n.y*k);
		t2 = PxVec3(a*k,-n.x*t1.z,n.x*t1.y);
	}
	else 
	{
		const PxReal a = n.x*n.x + n.y*n.y;
		const PxReal k = PxReal(1.0)/PxSqrt(a);
		t1 = PxVec3(-n.y*k,n.x*k,0);
		t2 = PxVec3(-n.z*t1.y,n.z*t1.x,a*k);
	}
	t1.normalize();
	t2.normalize();
}
Example #12
0
void RandomVelocities(PhysXObject* object, int powerMax, int seedMultiplier)
{
    PxVec3 dir = CreateRandomVector(powerMax, seedMultiplier);

    srand((time(NULL) * seedMultiplier) + time(NULL));

    int power = rand() % powerMax;

    dir.normalize();

    SetVelocity(dir * power, object);
}
/**
 @brief setting control diagramnode
 @date 2014-03-02
*/
void COrientationEditController::SetControlDiagram(CGenotypeNode *node)
{
	RemoveGenotypeTree(m_sample, m_rootNode);
	m_nodes.clear();
	m_rootNode = NULL;

	vector<CGenotypeNode*> nodes;
	m_genotypeController.GetDiagramsLinkto(node, nodes);
	if (nodes.empty())
		return;

	// Create Phenotype Node
	CGenotypeNode *parentNode = nodes[ 0];
	map<const genotype_parser::SExpr*, CGenotypeNode*> symbols;
	const PxTransform identTm = PxTransform::createIdentity();
	m_rootNode = CreatePhenotypeDiagram(identTm,identTm,identTm, parentNode->m_expr, symbols);

	// Camera Setting
	const PxVec3 parentPos = parentNode->GetWorldTransform().p;
	PxVec3 dir = parentPos - node->GetWorldTransform().p;
	dir.normalize();

	PxVec3 left = PxVec3(0,1,0).cross(dir);
	left.normalize();
	PxVec3 camPos = node->GetWorldTransform().p + (left*3.f) + PxVec3(0,2.5f,0);
	PxVec3 camDir = parentPos - camPos;
	camDir.normalize();
	camPos -= (camDir * .5f);

	m_sample.getCamera().lookAt(camPos, parentPos);
	const PxTransform viewTm = m_sample.getCamera().getViewMatrix();
	m_camera->init(viewTm);

	// select Orientation Control node
	if (CGenotypeNode *selectNode = m_rootNode->GetConnectNode(node->m_name))
	{
		selectNode->SetHighLight(true);
		SelectNode(selectNode);
	}
}
void Jumper::RunningJump::update(float dt)
{
    updateAnimation( dt );
    _clump->getFrame()->getLTM();

    if( _actionTime < _blendTime ) 
    {
        Vector3f dir = _clump->getFrame()->getAt();
        dir.normalize();
        _clump->getFrame()->setPos( _clump->getFrame()->getPos() + dir * dt * _vel );            
        return;
    }

    if( _phActor->isSleeping() )
    {
        // setup physics
        Matrix4f sampleLTM = Jumper::getCollisionFF( _clump )->getFrame()->getLTM();
        _phActor->setGlobalPose(PxTransform(wrap( sampleLTM )));
        _phActor->wakeUp();
        PxVec3 velH = wrap( _clump->getFrame()->getAt() );
        velH.normalize();
        velH *= _vel * 0.01f;
        PxVec3 velV = wrap( _clump->getFrame()->getUp() );
        velV.normalize();
        velV *= 1.5f;
        _phActor->setLinearVelocity( velH + velV + wrap(_clump->getFrame()->getAt() * 600.0f * dt)) ;
        _jumper->initOverburdenCalculator( velH + velV );


    }
    else
    {
        _clump->getFrame()->setMatrix( _matrixConversion->convert( wrap( _phActor->getGlobalPose() ) ) );
    }

    if( _clump->getAnimationController()->isEndOfAnimation( 0 ) )
    {
        _endOfAction = true;
    }
}
/**
 @brief generate triangle index buffer
 @date 2014-01-30
*/
void SampleRenderer::GenerateTriangleFrom3Vector( void *positions, void *normals, PxU32 stride, 
	const PxVec3 &center, const vector<PxU16> &triangle, OUT vector<PxU16> &outTriangle )
{
	const PxVec3 p0 = *(PxVec3*)(((PxU8*)positions) + (stride * triangle[ 0]));
	const PxVec3 p1 = *(PxVec3*)(((PxU8*)positions) + (stride * triangle[ 1]));
	const PxVec3 p2 = *(PxVec3*)(((PxU8*)positions) + (stride * triangle[ 2]));

	PxVec3 faceCenter = (p0 + p1 + p2) / 3.f;
	PxVec3 n = faceCenter - center;
	n.normalize();

	// ccw check
	//
	//            p0
	//          /   \
	//        /        \
	//    p2  ------  p1
	//

	PxVec3 v10 = p1 - p0;
	v10.normalize();
	PxVec3 v20 = p2 - p0;
	v20.normalize();

	PxVec3 crossV = v10.cross(v20);
	crossV.normalize();

	if (n.dot(crossV) >= 0)
	{
		outTriangle.push_back( triangle[ 0] );
		outTriangle.push_back( triangle[ 2] );
		outTriangle.push_back( triangle[ 1] );
	}
	else
	{
		outTriangle.push_back( triangle[ 0] );
		outTriangle.push_back( triangle[ 1] );
		outTriangle.push_back( triangle[ 2] );
	}
}
void SampleNorthPoleCameraController::update(Camera& camera, PxReal dtime)
{
	// Update CCT
	if(!mBase.isPaused())
	{
		PxVec3 targetKeyDisplacement(0);
		PxVec3 targetPadDisplacement(0);

		PxVec3 forward = camera.getViewDir();
		forward.y = 0;
		forward.normalize();
		PxVec3 up = PxVec3(0,1,0);
		PxVec3 right = forward.cross(up);

		if(mFwd)	targetKeyDisplacement += forward;
		if(mBwd)	targetKeyDisplacement -= forward;

		if(mRight)	targetKeyDisplacement += right;
		if(mLeft)	targetKeyDisplacement -= right;

		targetKeyDisplacement *= mKeyShiftDown ? mRunningSpeed : mWalkingSpeed;
		targetKeyDisplacement += PxVec3(0,-9.81,0);
		targetKeyDisplacement *= dtime;

		targetPadDisplacement += forward * mGamepadForwardInc * mRunningSpeed;
		targetPadDisplacement += right * mGamepadLateralInc * mRunningSpeed;
		targetPadDisplacement += PxVec3(0,-9.81,0);
		targetPadDisplacement *= dtime;

		PxU32 flags = mCCT.move(targetKeyDisplacement + targetPadDisplacement, 0.001f, dtime, PxControllerFilters(0));
		PX_UNUSED(flags);
	}
	// Update camera
	{
		mTargetYaw		+= mGamepadYawInc * dtime;
		mTargetPitch	+= mGamepadPitchInc * dtime;
		
		// Clamp pitch
		if(mTargetPitch<mPitchMin)	mTargetPitch = mPitchMin;
		if(mTargetPitch>mPitchMax)	mTargetPitch = mPitchMax;
		
		camera.setRot(PxVec3(-mTargetPitch,-mTargetYaw,0));

		PxExtendedVec3 camTarget = computeCameraTarget();
		const float filteredHeight = feedbackFilter((float)camTarget.y, mFilterMemory, dtime*6.0f);
		camTarget.y = filteredHeight;

		const PxF32 distanceToTarget = 0.0f;
		const PxVec3 target = toVec3(camTarget) - camera.getViewDir()*distanceToTarget;
		camera.setPos(target);
	}
}
Example #17
0
void Camera::lookAt(const PxVec3& position, const PxVec3& target)
{
	PxVec3 dir = target - position;
	dir.normalize();

	PxVec3 right, up;
	computeBasis(dir, right, up);

	PxTransform view;
	view.p	= position;
	view.q	= PxQuat(PxMat33(-right, up, -dir));
	setView(view);
}
Example #18
0
void ApplyOrbitVelocity(PxRigidActor* box, float power)
{
    for(int i = 0; i < planets.size(); i++)
    {
        PxVec3 dir = planets[i]->actor->getGlobalPose().p - box->getGlobalPose().p;

        dir.normalize();

        PxVec3 velocity = RandomOrthogonalVector(dir) * power;

        box->isRigidDynamic()->addForce(velocity,PxForceMode::eACCELERATION);
    }
}
bool ParticleEmitterPressure::stepEmissionSite(
	SiteData& siteData,
	ParticleData& spawnData,
	PxU32& spawnNum, 
	const PxU32 spawnMax,
	const PxVec3 &sitePos, 
	const PxVec3 &siteVel,
	const PxReal dt)
{
	PxReal maxDistanceMoved = 5.0f * mSpacingZ;	// don't generate long particle beams

	/**
	 * Find displacement vector of the particle's motion this frame
	 * this is not necessarily v*stepSize because a collision might have occured
	 */
	PxVec3 displacement = siteData.position - sitePos;
	PxVec3 normal = displacement;
	PxReal distanceMoved = normal.normalize();

	if (distanceMoved > maxDistanceMoved)
		distanceMoved = maxDistanceMoved;
	
	/**
	 * Place particles along line between emission point and new position
	 * starting backwards from the new position
	 * spacing between the particles is the rest spacing of the fluid 
	 */
	PxReal lastPlaced = 0.0f;
	while((lastPlaced + mSpacingZ) <= distanceMoved)
	{
		PxVec3 pos = sitePos + normal * (distanceMoved - (lastPlaced + mSpacingZ));

		PxVec3 posNoise;
		posNoise.x = randInRange(-mRandomPos.x, mRandomPos.x);
		posNoise.y = randInRange(-mRandomPos.y, mRandomPos.y);		
		
		pos += mAxisX*posNoise.x + mAxisY*posNoise.y;

		bool isSpawned = spawnParticle(spawnData, spawnNum, spawnMax, pos, siteVel);
		if(isSpawned)
		{
			updatePredecessor(siteData, pos, siteVel);
			lastPlaced += mSpacingZ;
		}
		else
		{
			return false;
		}
	}
	return true;
}
void TParticleData::ForcesCircle(std::vector<PxVec3>* forces, CParticlesEmitter* emitter)
{
	float r = emitter->m_shape_emitter.radius;
	auto forces_vec = *forces;
	for (int idx = 0; idx < forces_vec.size(); idx++) {
		PxVec3 dir = positionBuffer[idx] - positionInitBuffer[idx];
		float w = 2 * PI / sinf(shader_ctes_globals.world_time);
		float a = w*w*r;
		dir.normalize();
		forces_vec[idx] = dir * a;
	}

	*forces = forces_vec;
}
bool Gu::sweepSphereSphere(const PxVec3& center0, PxReal radius0, const PxVec3& center1, PxReal radius1, const PxVec3& motion, PxReal& d, PxVec3& nrm)
{
	const PxVec3 movedCenter = center1 + motion;

	PxReal tmp;
	if(!sphereSphereSweep(radius0, center0, center0, radius1, center1, movedCenter, d, tmp))
		return false;

	// Compute normal
	// PT: if spheres initially overlap, the convention is that returned normal = -sweep direction
	if(d==0.0f)
		nrm = -motion;
	else
		nrm = (center1 + d * motion) - center0;
	nrm.normalize();
	return true;
}
Example #22
0
PxVec3 Scene::getWindAtPoint(const PxVec3& point)
{
    if( !database::LocationInfo::getRecord( _location->getDatabaseId() )->wind )
    {
        return PxVec3( 0,0,0 );
    }

    float windAmbient   = _location->getWindAmbient();
    float windBlast     = _location->getWindBlast();
    float windAmplitude = ( windBlast - windAmbient ) / 2;

    float windMagnitude = windAmbient + windAmplitude + windAmplitude * blast( _windTime );

    PxVec3 windN = wrap( _location->getWindDirection() );
    windN.normalize();

    return windN * windMagnitude;
}
bool Character::setForward(void)
{
	PxVec3 p = mCharacterPose.p;

	PxVec3 dir = mGoalPosition - p;
	dir.normalize();

	dir = mCharacterPose.q.rotate(dir);

	PxU32 nbFrames = mCurrentMotion->mNbFrames;
	PxReal distance = mCurrentMotion->mDistance;

	PxReal frameDelta = distance / PxReal(nbFrames);

	mTargetPosition = p + frameDelta * dir;

	return true;
}
	bool ParticleChain::checkPenetration(const Ogre::Vector3 &position, Ogre::Vector3 &closestSurfacePos, Ogre::Vector3 &collisionNormal)
	{
		PxShape *hit = nullptr;
		PxVec3 pxPos = Convert::toPx(position);
		if (mPhysXScene->getPxScene()->overlapAny(PxSphereGeometry(0.05f), PxTransform(pxPos), hit))
		{
			PxVec3 actorCenter = hit->getActor().getWorldBounds().getCenter();
			PxVec3 rayDir = actorCenter - pxPos;
			rayDir.normalize();
			PxVec3 rayOrigin = pxPos - rayDir.multiply(PxVec3(0.2f, 0.2f, 0.2f));
			if (mPhysXScene->getPxScene()->overlapAny(PxSphereGeometry(0.05f), PxTransform(rayOrigin), hit)) return false;
			PxRaycastHit rayHit;
			if (mPhysXScene->getPxScene()->raycastSingle(rayOrigin, rayDir,  0.2f, PxSceneQueryFlag::eIMPACT|PxSceneQueryFlag::eNORMAL|PxSceneQueryFlag::eDISTANCE, rayHit))
			{
				closestSurfacePos = Convert::toOgre(rayHit.impact);
				collisionNormal = Convert::toOgre(rayHit.normal);
				return true;
			}
		}
		return false;
	}
Example #25
0
void ParticleEmitter::computeSiteVelocity(PxVec3& siteVel, const PxVec3& sitePos)
{
	//velocity dir noise
	PxReal noiseXYAngle = randInRange(0.0f, PxTwoPi);
	PxReal noiseZAngle  = randInRange(0.0f, mRandomAngle);

	PxVec3 noiseDirVec = mAxisX * PxCos(noiseXYAngle) + mAxisY * PxSin(noiseXYAngle);
	noiseDirVec.normalize();
	noiseDirVec = mAxisZ * PxCos(noiseZAngle) + noiseDirVec * PxSin(noiseZAngle);

	siteVel = noiseDirVec * mVelocity;

	//add emitter repulsion
	if (mParticleMass > 0.0f)
	{
		mLinMomentum -= siteVel;
		mAngMomentum -= (sitePos - mBodyCenter).cross(siteVel);
	}

	if (mFrameBody)
		siteVel += mBodyLinVel + (mBodyAngVel.cross(sitePos - mBodyCenter)); 
}
Example #26
0
void SampleSubmarine::explode(PxRigidActor* actor, const PxVec3& explosionPos, const PxReal explosionStrength)
{
	size_t numRenderActors = mRenderActors.size();
	for(PxU32 i = 0; i < numRenderActors; i++)
	{
		if(&(mRenderActors[i]->getPhysicsShape()->getActor()) == actor)
		{
			PxShape* shape = mRenderActors[i]->getPhysicsShape();
			PxTransform pose = PxShapeExt::getGlobalPose(*shape);
			
			PxGeometryHolder geom = shape->getGeometry();

			// create new actor from shape (to split compound)
			PxRigidDynamic* newActor = mPhysics->createRigidDynamic(pose);
			if(!newActor) fatalError("createRigidDynamic failed!");

			PxShape* newShape = newActor->createShape(geom.any(), *mMaterial);
			newShape->userData = mRenderActors[i];
			mRenderActors[i]->setPhysicsShape(newShape);
			
			newActor->setActorFlag(PxActorFlag::eVISUALIZATION, true);
			newActor->setLinearDamping(10.5f);
			newActor->setAngularDamping(0.5f);
			PxRigidBodyExt::updateMassAndInertia(*newActor, 1.0f);
			mScene->addActor(*newActor);
			mPhysicsActors.push_back(newActor);
			
			PxVec3 explosion = pose.p - explosionPos;
			PxReal len = explosion.normalize();
			explosion *= (explosionStrength / len);
			newActor->setLinearVelocity(explosion);
			newActor->setAngularVelocity(PxVec3(1,2,3));

		}
	}

	removeActor(actor);
}
Example #27
0
void PxSetJointGlobalFrame(PxJoint& joint, const PxVec3* wsAnchor, const PxVec3* axisIn)
{
	PxRigidActor* actors[2];
	joint.getActors(actors[0], actors[1]);

	PxTransform localPose[2];
	for(PxU32 i=0; i<2; i++)
		localPose[i] = PxTransform::createIdentity();

	// 1) global anchor
	if(wsAnchor)
	{
		//transform anchorPoint to local space
		for(PxU32 i=0; i<2; i++)
			localPose[i].p = actors[i] ? actors[i]->getGlobalPose().transformInv(*wsAnchor) : *wsAnchor;
	}

	// 2) global axis
	if(axisIn)
	{
		PxVec3 localAxis[2], localNormal[2];

		//find 2 orthogonal vectors.
		//gotta do this in world space, if we choose them
		//separately in local space they won't match up in worldspace.
		PxVec3 axisw = *axisIn;
		axisw.normalize();

		PxVec3 normalw, binormalw;
		::normalToTangents(axisw, binormalw, normalw);
		//because axis is supposed to be the Z axis of a frame with the other two being X and Y, we need to negate
		//Y to make the frame right handed. Note that the above call makes a right handed frame if we pass X --> Y,Z, so 
		//it need not be changed.

		for(PxU32 i=0; i<2; i++)
		{
			if(actors[i])
			{
				const PxTransform& m = actors[i]->getGlobalPose();
				PxMat33Legacy mM(m.q);
				localAxis[i]   = mM % axisw;
				localNormal[i] = mM % normalw;
			}
			else
			{
				localAxis[i] = axisw;
				localNormal[i] = normalw;
			}

			PxMat33Legacy rot;
			rot.setColumn(0, localAxis[i]);
			rot.setColumn(1, localNormal[i]);
			rot.setColumn(2, localAxis[i].cross(localNormal[i]));

			localPose[i].q = rot.toQuat();
			localPose[i].q.normalize();
		}
	}

	for(PxU32 i=0; i<2; i++)
		joint.setLocalPose(static_cast<PxJointActorIndex::Enum>( i ), localPose[i]);
}
void GOCCharacterController::ReceiveMessage(Msg &msg)
{
    GOComponent::ReceiveMessage(msg);
    if (msg.typeID == GlobalMessageIDs::PHYSICS_SUBSTEP && !mFreezed)
    {
        GameObjectPtr owner = mOwnerGO.lock();

        float time = msg.params.GetFloat("TIME");
        Ogre::Vector3 finalDir = Ogre::Vector3(0,0,0);
        Ogre::Vector3 userDir = owner->GetGlobalOrientation() * mDirection;

        if (mActor.getPxActor()->isSleeping())
            mActor.getPxActor()->wakeUp();		//Gravity fix

        Ogre::Vector3 playerHalfSize = mDimensions * 0.5f;

        PxTransform transform(OgrePhysX::toPx(owner->GetGlobalPosition()), OgrePhysX::toPx(owner->GetGlobalOrientation()));
        transform.p.y += playerHalfSize.y;

        //sweep filter data - only check against shapes with filter data DYNAMICBODY or STATICBODY
        PxSceneQueryFilterData filterData;
        filterData.data.word0 = CollisionGroups::DYNAMICBODY|CollisionGroups::STATICBODY;
        filterData.flags = PxSceneQueryFilterFlag::eDYNAMIC|PxSceneQueryFilterFlag::eSTATIC;

        //touches ground check
        PxBoxGeometry playerGeometry(playerHalfSize.x, playerHalfSize.y+0.1f, playerHalfSize.z);
        PxShape *outShape;
        mTouchesGround = Main::Instance().GetPhysXScene()->getPxScene()->overlapAny(playerGeometry, transform, outShape, filterData);

        //stair maxStepHeight
        float maxStepHeight = 0.6f;
        PxVec3 currPos = OgrePhysX::Convert::toPx(owner->GetGlobalPosition());

        //feet capsule
        PxBoxGeometry feetVolume(playerHalfSize.x, maxStepHeight*0.5f, playerHalfSize.z);

        //body capsule
        float bodyHeight = mDimensions.y-maxStepHeight;
        PxBoxGeometry bodyVolume(playerHalfSize.x, bodyHeight*0.5f, playerHalfSize.z);

        PxVec3 sweepDirection = OgrePhysX::toPx(userDir);
        float userDirLength = sweepDirection.normalize();

        /*
        We perform two sweeps:
         O    ==> bodyHit?
         |    ==> bodyHit?
        / \   ==> feetHit?

        If there are no hits character can walk in the desired direction.
        If there is a feetHit but no bodyHit player can climb stairs (we add an y-Offset).
        If there is a bodyHit the player can not move.
        */
        PxSweepHit sweepHit;
        transform.p.y = owner->GetGlobalPosition().y + maxStepHeight + bodyHeight*0.5f;
        bool bodyHit = Main::Instance().GetPhysXScene()->getPxScene()->sweepSingle(bodyVolume, transform, sweepDirection, time*userDirLength, PxSceneQueryFlags(), sweepHit, filterData);
        transform.p.y = owner->GetGlobalPosition().y + maxStepHeight*0.5f;
        bool feetHit = Main::Instance().GetPhysXScene()->getPxScene()->sweepSingle(feetVolume, transform, sweepDirection, time*userDirLength, PxSceneQueryFlags(), sweepHit, filterData);

        if (!bodyHit)
        {
            finalDir += userDir;	//add player movement
            if (feetHit)
                finalDir += Ogre::Vector3(0,3,0); //climb stairs
        }

        if (finalDir != Ogre::Vector3(0,0,0))
            mActor.getPxActor()->setGlobalPose(PxTransform(currPos + OgrePhysX::Convert::toPx(finalDir*time)));

        if (mJumping && mTouchesGround && (timeGetTime() - mJumpStartTime > 400))
        {
            mJumping = false;
            Msg jump_response;
            jump_response.typeID = ObjectMessageIDs::END_JUMP;
            BroadcastObjectMessage(jump_response);
        }
    }
    if (msg.typeID == GlobalMessageIDs::PHYSICS_END && !mFreezed)
    {
        SetOwnerPosition(mActor.getGlobalPosition());
        //SetOwnerOrientation(mActor->getGlobalOrientation());
    }


    if (msg.typeID == ObjectMessageIDs::UPDATE_CHARACTER_MOVEMENTSTATE)
    {
        mDirection = Ogre::Vector3(0,0,0);
        int movementFlags = msg.params.GetInt("CharacterMovementState");
        if (movementFlags & CharacterMovement::FORWARD) mDirection.z += 1;
        if (movementFlags & CharacterMovement::BACKWARD) mDirection.z -= 1;
        if (movementFlags & CharacterMovement::LEFT) mDirection.x += 1;
        if (movementFlags & CharacterMovement::RIGHT) mDirection.x -= 1;

        mDirection.normalise();
        mDirection*=(mMovementSpeed*mSpeedFactor);
    }
    if (msg.typeID == ObjectMessageIDs::INPUT_START_JUMP)
    {
        if (mTouchesGround && !mJumping)
        {
            mJumping = true;
            mJumpStartTime = timeGetTime();
            mActor.getPxActor()->addForce(PxVec3(0, mActor.getPxActor()->getMass()*8, 0), PxForceMode::eIMPULSE);
            Msg startJumpMsg;
            startJumpMsg.typeID = ObjectMessageIDs::START_JUMP;
            BroadcastObjectMessage(startJumpMsg);
        }
    }
    if (msg.typeID == ObjectMessageIDs::CHARACTER_KILL)
    {
        mFreezed = true;
    }
}
// PT: ray-capsule intersection code, originally from the old Magic Software library.
PxU32 Gu::intersectRayCapsuleInternal(const PxVec3& origin, const PxVec3& dir, const PxVec3& p0, const PxVec3& p1, float radius, PxReal s[2])
{
	// set up quadratic Q(t) = a*t^2 + 2*b*t + c
	PxVec3 kW = p1 - p0;
	const float fWLength = kW.magnitude();
	if(fWLength!=0.0f)
		kW /= fWLength;

	// PT: if the capsule is in fact a sphere, switch back to dedicated sphere code.
	// This is not just an optimization, the rest of the code fails otherwise.
	if(fWLength<=1e-6f)
	{
		const float d0 = (origin - p0).magnitudeSquared();
		const float d1 = (origin - p1).magnitudeSquared();
		const float approxLength = (PxMax(d0, d1) + radius)*2.0f;
		return PxU32(Gu::intersectRaySphere(origin, dir, approxLength, p0, radius, s[0]));
	}

	// generate orthonormal basis
	PxVec3 kU(0.0f);

	if (fWLength > 0.0f)
	{
		PxReal fInvLength;
		if ( PxAbs(kW.x) >= PxAbs(kW.y) )
		{
			// W.x or W.z is the largest magnitude component, swap them
			fInvLength = PxRecipSqrt(kW.x*kW.x + kW.z*kW.z);
			kU.x = -kW.z*fInvLength;
			kU.y = 0.0f;
			kU.z = kW.x*fInvLength;
		}
		else
		{
			// W.y or W.z is the largest magnitude component, swap them
			fInvLength = PxRecipSqrt(kW.y*kW.y + kW.z*kW.z);
			kU.x = 0.0f;
			kU.y = kW.z*fInvLength;
			kU.z = -kW.y*fInvLength;
		}
	}

	PxVec3 kV = kW.cross(kU);
	kV.normalize();	// PT: fixed november, 24, 2004. This is a bug in Magic.

	// compute intersection

	PxVec3 kD(kU.dot(dir), kV.dot(dir), kW.dot(dir));
	const float fDLength = kD.magnitude();
	const float fInvDLength = fDLength!=0.0f ? 1.0f/fDLength : 0.0f;
	kD *= fInvDLength;

	const PxVec3 kDiff = origin - p0;
	const PxVec3 kP(kU.dot(kDiff), kV.dot(kDiff), kW.dot(kDiff));
	const PxReal fRadiusSqr = radius*radius;

	// Is the velocity parallel to the capsule direction? (or zero)
	if ( PxAbs(kD.z) >= 1.0f - PX_EPS_REAL || fDLength < PX_EPS_REAL )
	{
		const float fAxisDir = dir.dot(kW);

		const PxReal fDiscr = fRadiusSqr - kP.x*kP.x - kP.y*kP.y;
		if ( fAxisDir < 0 && fDiscr >= 0.0f )
		{
			// Velocity anti-parallel to the capsule direction
			const PxReal fRoot = PxSqrt(fDiscr);
			s[0] = (kP.z + fRoot)*fInvDLength;
			s[1] = -(fWLength - kP.z + fRoot)*fInvDLength;
			return 2;
		}
		else if ( fAxisDir > 0  && fDiscr >= 0.0f )
		{
			// Velocity parallel to the capsule direction
			const PxReal fRoot = PxSqrt(fDiscr);
			s[0] = -(kP.z + fRoot)*fInvDLength;
			s[1] = (fWLength - kP.z + fRoot)*fInvDLength;
			return 2;
		}
		else
		{
			// sphere heading wrong direction, or no velocity at all
			return 0;
		}   
	}

	// test intersection with infinite cylinder
	PxReal fA = kD.x*kD.x + kD.y*kD.y;
	PxReal fB = kP.x*kD.x + kP.y*kD.y;
	PxReal fC = kP.x*kP.x + kP.y*kP.y - fRadiusSqr;
	PxReal fDiscr = fB*fB - fA*fC;
	if ( fDiscr < 0.0f )
	{
		// line does not intersect infinite cylinder
		return 0;
	}

	PxU32 iQuantity = 0;

	if ( fDiscr > 0.0f )
	{
		// line intersects infinite cylinder in two places
		const PxReal fRoot = PxSqrt(fDiscr);
		const PxReal fInv = 1.0f/fA;
		PxReal fT = (-fB - fRoot)*fInv;
		PxReal fTmp = kP.z + fT*kD.z;
		const float epsilon = 1e-3f;	// PT: see TA35174
		if ( fTmp >= -epsilon && fTmp <= fWLength+epsilon )
			s[iQuantity++] = fT*fInvDLength;

		fT = (-fB + fRoot)*fInv;
		fTmp = kP.z + fT*kD.z;
		if ( fTmp >= -epsilon && fTmp <= fWLength+epsilon )
			s[iQuantity++] = fT*fInvDLength;

		if ( iQuantity == 2 )
		{
			// line intersects capsule wall in two places
			return 2;
		}
	}
	else
	{
		// line is tangent to infinite cylinder
		const PxReal fT = -fB/fA;
		const PxReal fTmp = kP.z + fT*kD.z;
		if ( 0.0f <= fTmp && fTmp <= fWLength )
		{
			s[0] = fT*fInvDLength;
			return 1;
		}
	}

	// test intersection with bottom hemisphere
	// fA = 1
	fB += kP.z*kD.z;
	fC += kP.z*kP.z;
	fDiscr = fB*fB - fC;
	if ( fDiscr > 0.0f )
	{
		const PxReal fRoot = PxSqrt(fDiscr);
		PxReal fT = -fB - fRoot;
		PxReal fTmp = kP.z + fT*kD.z;
		if ( fTmp <= 0.0f )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}

		fT = -fB + fRoot;
		fTmp = kP.z + fT*kD.z;
		if ( fTmp <= 0.0f )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}
	}
	else if ( fDiscr == 0.0f )
	{
		const PxReal fT = -fB;
		const PxReal fTmp = kP.z + fT*kD.z;
		if ( fTmp <= 0.0f )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}
	}

	// test intersection with top hemisphere
	// fA = 1
	fB -= kD.z*fWLength;
	fC += fWLength*(fWLength - 2.0f*kP.z);

	fDiscr = fB*fB - fC;
	if ( fDiscr > 0.0f )
	{
		const PxReal fRoot = PxSqrt(fDiscr);
		PxReal fT = -fB - fRoot;
		PxReal fTmp = kP.z + fT*kD.z;
		if ( fTmp >= fWLength )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}

		fT = -fB + fRoot;
		fTmp = kP.z + fT*kD.z;
		if ( fTmp >= fWLength )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}
	}
	else if ( fDiscr == 0.0f )
	{
		const PxReal fT = -fB;
		const PxReal fTmp = kP.z + fT*kD.z;
		if ( fTmp >= fWLength )
		{
			s[iQuantity++] = fT*fInvDLength;
			if ( iQuantity == 2 )
				return 2;
		}
	}
	return iQuantity;
}
/**
 @brief vector 4개로 triangle 2개를 그리는 index buffer를 생성한다.
 @date 2014-01-30
*/
void SampleRenderer::GenerateTriangleFrom4Vector2( void *positions, void *normals, void *bones, void *colors, 
	PxU32 stride, PxU32 startVtxIdx, PxU16 *indices, PxU32 startIndexIdx, const PxVec3 &center, 
	const vector<PxU16> &faceIndices, OUT vector<PxU16> &outfaceIndices )
{
	vector<PxU16> triangle0; triangle0.reserve(3);
	vector<PxU16> triangle1; triangle1.reserve(3);
	triangle0.push_back( faceIndices[ 0] );
	triangle0.push_back( faceIndices[ 2] );
	triangle0.push_back( faceIndices[ 3] );

	triangle1.push_back( faceIndices[ 0] );
	triangle1.push_back( faceIndices[ 1] );
	triangle1.push_back( faceIndices[ 3] );

	GenerateTriangleFrom3Vector(positions, normals, stride, center, triangle0, outfaceIndices);
	GenerateTriangleFrom3Vector(positions, normals, stride, center, triangle1, outfaceIndices);

	if (outfaceIndices.size() != 6)
		return; // error occur
	
	for (u_int i=0; i < outfaceIndices.size();)
	{
		const PxVec3 p0 = *(PxVec3*)(((PxU8*)positions) + (stride * outfaceIndices[ i]));
		const PxVec3 p1 = *(PxVec3*)(((PxU8*)positions) + (stride * outfaceIndices[ i+1]));
		const PxVec3 p2 = *(PxVec3*)(((PxU8*)positions) + (stride * outfaceIndices[ i+2]));

		*(PxVec3*)(((PxU8*)positions) + (stride * startVtxIdx)) = p0;
		*(PxVec3*)(((PxU8*)positions) + (stride * (startVtxIdx+1))) = p1;
		*(PxVec3*)(((PxU8*)positions) + (stride * (startVtxIdx+2))) = p2;

		if (bones)
		{
			const PxU32 b0 = *(PxU32*)(((PxU8*)bones) + (stride * outfaceIndices[ i]));
			const PxU32 b1 = *(PxU32*)(((PxU8*)bones) + (stride * outfaceIndices[ i+1]));
			const PxU32 b2 = *(PxU32*)(((PxU8*)bones) + (stride * outfaceIndices[ i+2]));

			*(PxU32*)(((PxU8*)bones) + (stride * startVtxIdx)) = b0;
			*(PxU32*)(((PxU8*)bones) + (stride * (startVtxIdx+1))) = b1;
			*(PxU32*)(((PxU8*)bones) + (stride * (startVtxIdx+2))) = b2;
		}

		if (colors)
		{
			const PxU32 c0 = *(PxU32*)(((PxU8*)colors) + (stride * outfaceIndices[ i]));
			const PxU32 c1 = *(PxU32*)(((PxU8*)colors) + (stride * outfaceIndices[ i+1]));
			const PxU32 c2 = *(PxU32*)(((PxU8*)colors) + (stride * outfaceIndices[ i+2]));

			*(PxU32*)(((PxU8*)colors) + (stride * startVtxIdx)) = c0;
			*(PxU32*)(((PxU8*)colors) + (stride * (startVtxIdx+1))) = c1;
			*(PxU32*)(((PxU8*)colors) + (stride * (startVtxIdx+2))) = c2;
		}

		if (normals)
		{
			PxVec3 v01 = p1 - p0;
			PxVec3 v02 = p2 - p0;
			v01.normalize();
			v02.normalize();
			PxVec3 n = v01.cross(v02);
			n.normalize();
			n = -n;

			*(PxVec3*)(((PxU8*)normals) + (stride * startVtxIdx)) = n;
			*(PxVec3*)(((PxU8*)normals) + (stride * (startVtxIdx+1))) = n;
			*(PxVec3*)(((PxU8*)normals) + (stride * (startVtxIdx+2))) = n;
		}		

		indices[ startIndexIdx] = startVtxIdx;
		indices[ startIndexIdx+1] = startVtxIdx+1;
		indices[ startIndexIdx+2] = startVtxIdx+2;

		startIndexIdx += 3;
		startVtxIdx += 3;
		i += 3;
	}
}