void Projectile::prepBatchRender( SceneRenderState *state ) { if ( !mProjectileShape ) return; GFXTransformSaver saver; // Set up our TS render state. TSRenderState rdata; rdata.setSceneState( state ); // We might have some forward lit materials // so pass down a query to gather lights. LightQuery query; query.init( getWorldSphere() ); rdata.setLightQuery( &query ); MatrixF mat = getRenderTransform(); mat.scale( mObjScale ); mat.scale( mDataBlock->scale ); GFX->setWorldMatrix( mat ); mProjectileShape->setDetailFromPosAndScale( state, mat.getPosition(), mObjScale ); mProjectileShape->animate(); mProjectileShape->render( rdata ); }
void TSShapeLoader::generateGroundAnimation(TSShape::Sequence& seq, const AppSequence* appSeq) { seq.firstGroundFrame = shape->groundTranslations.size(); seq.numGroundFrames = 0; if (!boundsNode) return; // Check if the bounds node is animated by this sequence seq.numGroundFrames = (S32)((seq.duration + 0.25f/AppGroundFrameRate) * AppGroundFrameRate); seq.flags |= TSShape::MakePath; // Get ground transform at the start of the sequence MatrixF invStartMat = boundsNode->getNodeTransform(appSeq->getStart()); zapScale(invStartMat); invStartMat.inverse(); for (int iFrame = 0; iFrame < seq.numGroundFrames; iFrame++) { F32 time = appSeq->getStart() + seq.duration * iFrame / getMax(1, seq.numGroundFrames - 1); // Determine delta bounds node transform at 't' MatrixF mat = boundsNode->getNodeTransform(time); zapScale(mat); mat = invStartMat * mat; // Add ground transform Quat16 rotation; rotation.set(QuatF(mat)); shape->groundTranslations.push_back(mat.getPosition()); shape->groundRotations.push_back(rotation); } }
MatrixF PlaneReflector::getCameraReflection( const MatrixF &camTrans ) { Point3F normal = refplane; // Figure out new cam position Point3F camPos = camTrans.getPosition(); F32 dist = refplane.distToPlane( camPos ); Point3F newCamPos = camPos - normal * dist * 2.0; // Figure out new look direction Point3F i, j, k; camTrans.getColumn( 0, &i ); camTrans.getColumn( 1, &j ); camTrans.getColumn( 2, &k ); i = MathUtils::reflect( i, normal ); j = MathUtils::reflect( j, normal ); k = MathUtils::reflect( k, normal ); //mCross( i, j, &k ); MatrixF newTrans(true); newTrans.setColumn( 0, i ); newTrans.setColumn( 1, j ); newTrans.setColumn( 2, k ); newTrans.setPosition( newCamPos ); return newTrans; }
void TurretShape::getRenderWeaponMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat ) { // Returns mount point to world space transform if ( mountPoint >= 0 && mountPoint < SceneObject::NumMountPoints) { S32 ni = mDataBlock->weaponMountNode[mountPoint]; if (ni != -1) { MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; mountTransform.mul( xfm ); const Point3F& scale = getScale(); // The position of the mount point needs to be scaled. Point3F position = mountTransform.getPosition(); position.convolve( scale ); mountTransform.setPosition( position ); // Also we would like the object to be scaled to the model. mountTransform.scale( scale ); outMat->mul(getRenderTransform(), mountTransform); return; } } // Then let SceneObject handle it. GrandParent::getRenderMountTransform( delta, mountPoint, xfm, outMat ); }
Frustum::Frustum( bool isOrtho, F32 nearLeft, F32 nearRight, F32 nearTop, F32 nearBottom, F32 nearDist, F32 farDist, const MatrixF &transform ) { mTransform = transform; mPosition = transform.getPosition(); mNearLeft = nearLeft; mNearRight = nearRight; mNearTop = nearTop; mNearBottom = nearBottom; mNearDist = nearDist; mFarDist = farDist; mIsOrtho = isOrtho; mNumTiles = 1; mCurrTile.set(0,0); mTileOverlap.set(0.0f, 0.0f); mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); }
void OrientedBox3F::set( const MatrixF& transform, const Point3F& extents ) { mCenter = transform.getPosition(); mAxes[ RightVector ] = transform.getRightVector(); mAxes[ ForwardVector ] = transform.getForwardVector(); mAxes[ UpVector ] = transform.getUpVector(); mHalfExtents = extents * 0.5f; _initPoints(); }
bool AIPlayer::onAdd() { if (!Parent::onAdd()) return false; // Use the eye as the current position (see getAIMove) MatrixF eye; getEyeTransform(&eye); mLastLocation = eye.getPosition(); return true; }
void SkyBox::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi ) { GFXDEBUGEVENT_SCOPE( SkyBox_RenderObject, ColorF::WHITE ); GFXTransformSaver saver; GFX->setVertexBuffer( mVB ); MatrixF worldMat = MatrixF::Identity; worldMat.setPosition( state->getCameraPosition() ); SceneData sgData; sgData.init( state ); sgData.objTrans = &worldMat; mMatrixSet->restoreSceneViewProjection(); mMatrixSet->setWorld( worldMat ); if ( state->isReflectPass() ) mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() ); while ( mMatInstance->setupPass( state, sgData ) ) { mMatInstance->setTransforms( *mMatrixSet, state ); mMatInstance->setSceneInfo( state, sgData ); GFX->drawPrimitive( GFXTriangleList, 0, mPrimCount ); } // Draw render band. if ( mFogBandHeight > 0 && mFogBandMatInst ) { const FogData &fog = state->getSceneManager()->getFogData(); if ( mLastFogColor != fog.color ) { mLastFogColor = fog.color; _initRender(); } // Just need it to follow the camera... no rotation. MatrixF camPosMat( MatrixF::Identity ); camPosMat.setPosition( worldMat.getPosition() ); sgData.objTrans = &camPosMat; mMatrixSet->setWorld( *sgData.objTrans ); while ( mFogBandMatInst->setupPass( state, sgData ) ) { mFogBandMatInst->setTransforms( *mMatrixSet, state ); mFogBandMatInst->setSceneInfo( state, sgData ); GFX->setVertexBuffer( mFogBandVB ); GFX->drawPrimitive( GFXTriangleList, 0, 16 ); } } }
//---------------------------------------------------------------------------- // Explode //---------------------------------------------------------------------------- void Splash::spawnExplosion() { if( !mDataBlock->explosion ) return; Explosion* pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion, false); MatrixF trans = getTransform(); trans.setPosition( getPosition() ); pExplosion->setTransform( trans ); pExplosion->setInitialState( trans.getPosition(), VectorF(0,0,1), 1); if (!pExplosion->registerObject()) delete pExplosion; }
/** * Sets the location for the bot to run to * * @param location Point to run to */ void AIPlayer::setMoveDestination( const Point3F &location, bool slowdown ) { //.logicking >> hack to avoid stopping right after // beginning of the move MatrixF eye; getEyeTransform(&eye); Point3F pos = eye.getPosition(); mLastLocation = pos; mLastLocation.z += mMoveTolerance * 2; //.logicking << mMoveDestination = location; mMoveState = ModeMove; mMoveSlowdown = slowdown; mMoveStuckTestCountdown = mMoveStuckTestDelay; }
void SFX3DObject::getReferenceCenter( F32 position[ 3 ] ) const { MatrixF transform; getEarTransform( transform ); Point3F pos = transform.getPosition(); AssertFatal( TypeTraits< F32 >::MIN <= pos.x && pos.x <= TypeTraits< F32 >::MAX, "SFX3DObject::getReferenceCenter - invalid float in reference center X position" ); AssertFatal( TypeTraits< F32 >::MIN <= pos.y && pos.y <= TypeTraits< F32 >::MAX, "SFX3DObject::getReferenceCenter - invalid float in reference center Y position" ); AssertFatal( TypeTraits< F32 >::MIN <= pos.z && pos.z <= TypeTraits< F32 >::MAX, "SFX3DObject::getReferenceCenter - invalid float in reference center Z position" ); dMemcpy( position, &pos.x, sizeof( F32 ) * 3 ); }
bool TurretShape::getNodeTransform(S32 node, MatrixF& mat) { if (node == -1) return false; MatrixF nodeTransform = mShapeInstance->mNodeTransforms[node]; const Point3F& scale = getScale(); // The position of the node needs to be scaled. Point3F position = nodeTransform.getPosition(); position.convolve( scale ); nodeTransform.setPosition( position ); mat.mul(mObjToWorld, nodeTransform); return true; }
void RigidBody::setTransform(const MatrixF& newMat) { Parent::setTransform(newMat); // for GMK editor, when physics simulation is frozen //if(gFreezeSim) { if(mPhysShape) mPhysShape->setTransform(newMat); mDelta.pos = newMat.getPosition(); mDelta.rot[0] = QuatF(newMat); mDelta.rot[1] = mDelta.rot[0]; mPhysPosition = mDelta.pos; mPhysRotation = mDelta.rot[0]; } }
void SoftBody::setTransform(const MatrixF& mat) { PhysBody::setTransform(mat); if(gFreezeSim || m_stopSimulation) { m_initTransform = mat; if(mPhysShape) mPhysShape->setTransform(mat); mDelta.pos = mat.getPosition(); mDelta.rot[0] = QuatF(mat); mDelta.rot[1] = mDelta.rot[0]; mPhysPosition = mDelta.pos; mPhysRotation = mDelta.rot[0]; mDelta.posVec = VectorF::Zero; } }
void PxSingleActor::applyCorrection( const MatrixF& mat, const NxVec3& linVel, const NxVec3& angVel ) { // Sometimes the actor hasn't been // created yet during the call from unpackUpdate. if ( !mActor || !mWorld ) return; mWorld->releaseWriteLock(); NxVec3 newPos = mat.getPosition(); NxVec3 currPos = getPosition(); NxVec3 offset = newPos - currPos; // If the difference isn't large enough, // just set the new transform, no correction. if ( offset.magnitude() > 0.3f ) { // If we're going to set the linear or angular velocity, // we do it before we add a corrective force, since it would be overwritten otherwise. NxVec3 currLinVel, currAngVel; currLinVel = mActor->getLinearVelocity(); currAngVel = mActor->getAngularVelocity(); // Scale the corrective force by half, // otherwise it will over correct and oscillate. NxVec3 massCent = mActor->getCMassGlobalPosition(); mActor->addForceAtPos( offset, massCent, NX_VELOCITY_CHANGE ); // If the linear velocity is divergent enough, change to server linear velocity. if ( (linVel - currLinVel).magnitude() > 0.3f ) mActor->setLinearVelocity( linVel ); // Same for angular. if ( (angVel - currAngVel).magnitude() > 0.3f ) mActor->setAngularVelocity( angVel ); } Parent::setTransform( mat ); }
void Projectile::prepBatchRender( SceneState *state ) { GFXTransformSaver saver; // Set up our TS render state. TSRenderState rdata; rdata.setSceneState( state ); MatrixF mat = getRenderTransform(); mat.scale( mObjScale ); mat.scale( mDataBlock->scale ); GFX->setWorldMatrix( mat ); if(mProjectileShape) { AssertFatal(mProjectileShape != NULL, "Projectile::renderObject: Error, projectile shape should always be present in renderObject"); mProjectileShape->setDetailFromPosAndScale( state, mat.getPosition(), mObjScale ); mProjectileShape->animate(); mProjectileShape->render( rdata ); } }
void BtBody::getState( PhysicsState *outState ) { AssertFatal( isDynamic(), "BtBody::getState - This call is only for dynamics!" ); // TODO: Fix this to do what we intended... to return // false so that the caller can early out of the state // hasn't changed since the last tick. MatrixF trans; if ( mInvCenterOfMass ) trans.mul( btCast<MatrixF>( mActor->getCenterOfMassTransform() ), *mInvCenterOfMass ); else trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() ); outState->position = trans.getPosition(); outState->orientation.set( trans ); outState->linVelocity = btCast<Point3F>( mActor->getLinearVelocity() ); outState->angVelocity = btCast<Point3F>( mActor->getAngularVelocity() ); outState->sleeping = !mActor->isActive(); // Bullet doesn't keep the momentum... recalc it. outState->momentum = ( 1.0f / mActor->getInvMass() ) * outState->linVelocity; }
void WaterPlane::setTransform( const MatrixF &mat ) { // We only accept the z value from the new transform. MatrixF newMat( true ); Point3F newPos = getPosition(); newPos.z = mat.getPosition().z; newMat.setPosition( newPos ); Parent::setTransform( newMat ); // Parent::setTransforms ends up setting our worldBox to something other than // global, so we have to set it back... but we can't actually call setGlobalBounds // again because it does extra work adding and removing us from the container. mGlobalBounds = true; mObjBox.minExtents.set(-1e10, -1e10, -1e10); mObjBox.maxExtents.set( 1e10, 1e10, 1e10); // Keep mWaterPlane up to date. mWaterFogData.plane.set( 0, 0, 1, -getPosition().z ); }
void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat ) { // Returns mount point to world space transform if ( index >= 0 && index < SceneObject::NumMountPoints) { S32 ni = mDataBlock->weaponMountNode[index]; if (ni != -1) { MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; mountTransform.mul( xfm ); const Point3F& scale = getScale(); // The position of the mount point needs to be scaled. Point3F position = mountTransform.getPosition(); position.convolve( scale ); mountTransform.setPosition( position ); // Also we would like the object to be scaled to the model. outMat->mul(mObjToWorld, mountTransform); return; } } // Then let SceneObject handle it. GrandParent::getMountTransform( index, xfm, outMat ); }
Point3F PhysShape::getPosition() { MatrixF res = getTransform(); return res.getPosition(); }
/** * This method calculates the moves for the AI player * * @param movePtr Pointer to move the move list into */ bool AIPlayer::getAIMove(Move *movePtr) { *movePtr = NullMove; // Use the eye as the current position. MatrixF eye; getEyeTransform(&eye); Point3F location = eye.getPosition(); Point3F rotation = getRotation(); // Orient towards the aim point, aim object, or towards // our destination. if (mAimObject || mAimLocationSet || mMoveState != ModeStop) { // Update the aim position if we're aiming for an object if (mAimObject) mAimLocation = mAimObject->getPosition() + mAimOffset; else if (!mAimLocationSet) mAimLocation = mMoveDestination; F32 xDiff = mAimLocation.x - location.x; F32 yDiff = mAimLocation.y - location.y; if (!mIsZero(xDiff) || !mIsZero(yDiff)) { // First do Yaw // use the cur yaw between -Pi and Pi F32 curYaw = rotation.z; while (curYaw > M_2PI_F) curYaw -= M_2PI_F; while (curYaw < -M_2PI_F) curYaw += M_2PI_F; // find the yaw offset F32 newYaw = mAtan2( xDiff, yDiff ); F32 yawDiff = newYaw - curYaw; // make it between 0 and 2PI if( yawDiff < 0.0f ) yawDiff += M_2PI_F; else if( yawDiff >= M_2PI_F ) yawDiff -= M_2PI_F; // now make sure we take the short way around the circle if( yawDiff > M_PI_F ) yawDiff -= M_2PI_F; else if( yawDiff < -M_PI_F ) yawDiff += M_2PI_F; movePtr->yaw = yawDiff; // Next do pitch. if (!mAimObject && !mAimLocationSet) { // Level out if were just looking at our next way point. Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } else { // This should be adjusted to run from the // eye point to the object's center position. Though this // works well enough for now. F32 vertDist = mAimLocation.z - location.z; F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff); F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f ); if (mFabs(newPitch) > 0.01f) { Point3F headRotation = getHeadRotation(); movePtr->pitch = newPitch - headRotation.x; } } } } else { // Level out if we're not doing anything else Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } // Move towards the destination if (mMoveState != ModeStop) { F32 xDiff = mMoveDestination.x - location.x; F32 yDiff = mMoveDestination.y - location.y; // Check if we should mMove, or if we are 'close enough' if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) { mMoveState = ModeStop; throwCallback("onReachDestination"); } else { // Build move direction in world space if (mIsZero(xDiff)) movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; else if (mIsZero(yDiff)) movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; else if (mFabs(xDiff) > mFabs(yDiff)) { F32 value = mFabs(yDiff / xDiff); movePtr->y = (location.y > mMoveDestination.y) ? -value : value; movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; } else { F32 value = mFabs(xDiff / yDiff); movePtr->x = (location.x > mMoveDestination.x) ? -value : value; movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; } // Rotate the move into object space (this really only needs // a 2D matrix) Point3F newMove; MatrixF moveMatrix; moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw))); moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove ); movePtr->x = newMove.x; movePtr->y = newMove.y; // Set movement speed. We'll slow down once we get close // to try and stop on the spot... if (mMoveSlowdown) { F32 speed = mMoveSpeed; F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff); F32 maxDist = 5.0f; if (dist < maxDist) speed *= dist / maxDist; movePtr->x *= speed; movePtr->y *= speed; mMoveState = ModeSlowing; } else { movePtr->x *= mMoveSpeed; movePtr->y *= mMoveSpeed; mMoveState = ModeMove; } if (mMoveStuckTestCountdown > 0) --mMoveStuckTestCountdown; else { // We should check to see if we are stuck... F32 locationDelta = (location - mLastLocation).len(); if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) { // If we are slowing down, then it's likely that our location delta will be less than // our move stuck tolerance. Because we can be both slowing and stuck // we should TRY to check if we've moved. This could use better detection. if ( mMoveState != ModeSlowing || locationDelta == 0 ) { mMoveState = ModeStuck; throwCallback("onMoveStuck"); } } } } } // Test for target location in sight if it's an object. The LOS is // run from the eye position to the center of the object's bounding, // which is not very accurate. if (mAimObject) { MatrixF eyeMat; getEyeTransform(&eyeMat); eyeMat.getColumn(3,&location); Point3F targetLoc = mAimObject->getBoxCenter(); // This ray ignores non-static shapes. Cast Ray returns true // if it hit something. RayInfo dummy; if (getContainer()->castRay( location, targetLoc, StaticShapeObjectType | StaticObjectType | TerrainObjectType, &dummy)) { if (mTargetInLOS) { throwCallback( "onTargetExitLOS" ); mTargetInLOS = false; } } else if (!mTargetInLOS) { throwCallback( "onTargetEnterLOS" ); mTargetInLOS = true; } } // Replicate the trigger state into the move so that // triggers can be controlled from scripts. for( int i = 0; i < MaxTriggerKeys; i++ ) movePtr->trigger[i] = getImageTriggerState(i); mLastLocation = location; return true; }
void PxCloth::unpackUpdate( NetConnection *conn, BitStream *stream ) { Parent::unpackUpdate( conn, stream ); // TransformMask if ( stream->readFlag() ) { MatrixF mat; mathRead( *stream, &mat ); // start jc if(mCloth) { NxVec3 delta(mat.getPosition() - getTransform().getPosition()); if(mCloth->isSleeping()) mCloth->wakeUp(); if ( mAttachmentMask & BIT( 0 ) ) mCloth->attachVertexToGlobalPosition( 0, mCloth->getPosition( 0 ) + delta ); if ( mAttachmentMask & BIT( 1 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x-1, mCloth->getPosition( mPatchVerts.x-1 ) + delta ); if ( mAttachmentMask & BIT( 2 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x, mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x ) + delta ); if ( mAttachmentMask & BIT( 3 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - 1, mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - 1 ) + delta ); if ( mAttachmentMask & BIT( 4 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2), mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2) ) + delta ); if ( mAttachmentMask & BIT( 5 ) ) mCloth->attachVertexToGlobalPosition( (mPatchVerts.x/2), mCloth->getPosition( (mPatchVerts.x/2) ) + delta ); if ( mAttachmentMask & BIT( 6 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2), mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) ) + delta ); if ( mAttachmentMask & BIT( 7 ) ) mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1), mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1) ) + delta ); if ( mAttachmentMask & BIT( 8 ) ) for ( U32 i = mPatchVerts.x * mPatchVerts.y - mPatchVerts.x; i < mPatchVerts.x * mPatchVerts.y; i++ ) mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) + delta ); if ( mAttachmentMask & BIT( 9 ) ) for ( U32 i = 0; i < mPatchVerts.x; i++ ) mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) + delta ); if ( mAttachmentMask & BIT( 10 ) ) for ( U32 i = 0; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x ) mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) + delta ); if ( mAttachmentMask & BIT( 11 ) ) for ( U32 i = mPatchVerts.x-1; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x ) mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) + delta ); } // end jc setTransform( mat ); } // start jc // ScaleAttachmentPointsMask if ( stream->readFlag() ) { Point3F attachmentPointScale; mathRead( *stream, &attachmentPointScale ); if(mCloth) { Point3F scale(Point3F::One); scale.convolveInverse(mAttachmentPointScale); scale.convolve(attachmentPointScale); NxVec3 delta(scale); if(mCloth->isSleeping()) mCloth->wakeUp(); static NxVec3 delta2; if ( mAttachmentMask & BIT( 0 ) ) { delta2.arrayMultiply(mCloth->getPosition( 0 ),delta); mCloth->attachVertexToGlobalPosition( 0, delta2); } if ( mAttachmentMask & BIT( 1 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x-1 ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x-1, delta2); } if ( mAttachmentMask & BIT( 2 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x, delta2); } if ( mAttachmentMask & BIT( 3 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - 1 ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - 1, delta2); } if ( mAttachmentMask & BIT( 4 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2) ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2), delta2); } if ( mAttachmentMask & BIT( 5 ) ) { delta2.arrayMultiply(mCloth->getPosition( (mPatchVerts.x/2) ), delta); mCloth->attachVertexToGlobalPosition( (mPatchVerts.x/2), delta2); } if ( mAttachmentMask & BIT( 6 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2), delta2); } if ( mAttachmentMask & BIT( 7 ) ) { delta2.arrayMultiply(mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1) ), delta); mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1), delta2); } if ( mAttachmentMask & BIT( 8 ) ) for ( U32 i = mPatchVerts.x * mPatchVerts.y - mPatchVerts.x; i < mPatchVerts.x * mPatchVerts.y; i++ ) { delta2.arrayMultiply(mCloth->getPosition( i ), delta); mCloth->attachVertexToGlobalPosition( i, delta2); } if ( mAttachmentMask & BIT( 9 ) ) for ( U32 i = 0; i < mPatchVerts.x; i++ ) { delta2.arrayMultiply(mCloth->getPosition( i ), delta); mCloth->attachVertexToGlobalPosition( i, delta2); } if ( mAttachmentMask & BIT( 10 ) ) for ( U32 i = 0; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x ) { delta2.arrayMultiply(mCloth->getPosition( i ), delta); mCloth->attachVertexToGlobalPosition( i, delta2); } if ( mAttachmentMask & BIT( 11 ) ) for ( U32 i = mPatchVerts.x-1; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x ) { delta2.arrayMultiply(mCloth->getPosition( i ), delta); mCloth->attachVertexToGlobalPosition( i, delta2); } } mAttachmentPointScale = attachmentPointScale; } // end jc // MaterialMask if ( stream->readFlag() ) { stream->read( &mMaterialName ); SAFE_DELETE( mMatInst ); } // ClothMask if ( stream->readFlag() ) { Point2I patchVerts; Point2F patchSize; mathRead( *stream, &patchVerts ); mathRead( *stream, &patchSize ); if ( patchVerts != mPatchVerts || !patchSize.equal( mPatchSize ) ) { mPatchVerts = patchVerts; mPatchSize = patchSize; _releaseMesh(); } U32 attachMask; stream->read( &attachMask ); if ( attachMask != mAttachmentMask ) { mAttachmentMask = attachMask; _releaseCloth(); } mBendingEnabled = stream->readFlag(); mDampingEnabled = stream->readFlag(); mTriangleCollisionEnabled = stream->readFlag(); mSelfCollisionEnabled = stream->readFlag(); stream->read( &mThickness ); stream->read( &mFriction ); stream->read( &mBendingStiffness ); stream->read( &mDampingCoefficient ); F32 density; stream->read( &density ); if ( density != mDensity ) { mDensity = density; _releaseCloth(); } if ( isClientObject() && isProperlyAdded() && mWorld && !mCloth ) { _createClothPatch(); } _updateClothProperties(); } }
/** * This method calculates the moves for the AI player * * @param movePtr Pointer to move the move list into */ bool AIPlayer::getAIMove(Move *movePtr) { *movePtr = NullMove; // Use the eye as the current position. MatrixF eye; getEyeTransform(&eye); Point3F location = eye.getPosition(); Point3F rotation = getRotation(); #ifdef TORQUE_NAVIGATION_ENABLED if(mDamageState == Enabled) { if(mMoveState != ModeStop) updateNavMesh(); if(!mFollowData.object.isNull()) { if(mPathData.path.isNull()) { if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius) followObject(mFollowData.object, mFollowData.radius); } else { if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius) repath(); else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius) { clearPath(); mMoveState = ModeStop; throwCallback("onTargetInRange"); } else if((getPosition() - mFollowData.object->getPosition()).len() < mAttackRadius) { throwCallback("onTargetInFiringRange"); } } } } #endif // TORQUE_NAVIGATION_ENABLED // Orient towards the aim point, aim object, or towards // our destination. if (mAimObject || mAimLocationSet || mMoveState != ModeStop) { // Update the aim position if we're aiming for an object if (mAimObject) mAimLocation = mAimObject->getPosition() + mAimOffset; else if (!mAimLocationSet) mAimLocation = mMoveDestination; F32 xDiff = mAimLocation.x - location.x; F32 yDiff = mAimLocation.y - location.y; if (!mIsZero(xDiff) || !mIsZero(yDiff)) { // First do Yaw // use the cur yaw between -Pi and Pi F32 curYaw = rotation.z; while (curYaw > M_2PI_F) curYaw -= M_2PI_F; while (curYaw < -M_2PI_F) curYaw += M_2PI_F; // find the yaw offset F32 newYaw = mAtan2( xDiff, yDiff ); F32 yawDiff = newYaw - curYaw; // make it between 0 and 2PI if( yawDiff < 0.0f ) yawDiff += M_2PI_F; else if( yawDiff >= M_2PI_F ) yawDiff -= M_2PI_F; // now make sure we take the short way around the circle if( yawDiff > M_PI_F ) yawDiff -= M_2PI_F; else if( yawDiff < -M_PI_F ) yawDiff += M_2PI_F; movePtr->yaw = yawDiff; // Next do pitch. if (!mAimObject && !mAimLocationSet) { // Level out if were just looking at our next way point. Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } else { // This should be adjusted to run from the // eye point to the object's center position. Though this // works well enough for now. F32 vertDist = mAimLocation.z - location.z; F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff); F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f ); if (mFabs(newPitch) > 0.01f) { Point3F headRotation = getHeadRotation(); movePtr->pitch = newPitch - headRotation.x; } } } } else { // Level out if we're not doing anything else Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } // Move towards the destination if (mMoveState != ModeStop) { F32 xDiff = mMoveDestination.x - location.x; F32 yDiff = mMoveDestination.y - location.y; // Check if we should mMove, or if we are 'close enough' if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) { mMoveState = ModeStop; onReachDestination(); } else { // Build move direction in world space if (mIsZero(xDiff)) movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; else if (mIsZero(yDiff)) movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; else if (mFabs(xDiff) > mFabs(yDiff)) { F32 value = mFabs(yDiff / xDiff); movePtr->y = (location.y > mMoveDestination.y) ? -value : value; movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; } else { F32 value = mFabs(xDiff / yDiff); movePtr->x = (location.x > mMoveDestination.x) ? -value : value; movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; } // Rotate the move into object space (this really only needs // a 2D matrix) Point3F newMove; MatrixF moveMatrix; moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw))); moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove ); movePtr->x = newMove.x; movePtr->y = newMove.y; // Set movement speed. We'll slow down once we get close // to try and stop on the spot... if (mMoveSlowdown) { F32 speed = mMoveSpeed; F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff); F32 maxDist = mMoveTolerance*2; if (dist < maxDist) speed *= dist / maxDist; movePtr->x *= speed; movePtr->y *= speed; mMoveState = ModeSlowing; } else { movePtr->x *= mMoveSpeed; movePtr->y *= mMoveSpeed; mMoveState = ModeMove; } if (mMoveStuckTestCountdown > 0) --mMoveStuckTestCountdown; else { // We should check to see if we are stuck... F32 locationDelta = (location - mLastLocation).len(); if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) { // If we are slowing down, then it's likely that our location delta will be less than // our move stuck tolerance. Because we can be both slowing and stuck // we should TRY to check if we've moved. This could use better detection. if ( mMoveState != ModeSlowing || locationDelta == 0 ) { mMoveState = ModeStuck; onStuck(); } } } } } // Test for target location in sight if it's an object. The LOS is // run from the eye position to the center of the object's bounding, // which is not very accurate. if (mAimObject) { if (checkInLos(mAimObject.getPointer())) { if (!mTargetInLOS) { throwCallback( "onTargetEnterLOS" ); mTargetInLOS = true; } } else if (mTargetInLOS) { throwCallback( "onTargetExitLOS" ); mTargetInLOS = false; } } Pose desiredPose = mPose; if ( mSwimming ) desiredPose = SwimPose; else if ( mAiPose == 1 && canCrouch() ) desiredPose = CrouchPose; else if ( mAiPose == 2 && canProne() ) desiredPose = PronePose; else if ( mAiPose == 3 && canSprint() ) desiredPose = SprintPose; else if ( canStand() ) desiredPose = StandPose; setPose( desiredPose ); // Replicate the trigger state into the move so that // triggers can be controlled from scripts. for( U32 i = 0; i < MaxTriggerKeys; i++ ) movePtr->trigger[ i ] = getImageTriggerState( i ); #ifdef TORQUE_NAVIGATION_ENABLED if(mJump == Now) { movePtr->trigger[2] = true; mJump = None; } else if(mJump == Ledge) { // If we're not touching the ground, jump! RayInfo info; if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info)) { movePtr->trigger[2] = true; mJump = None; } } #endif // TORQUE_NAVIGATION_ENABLED mLastLocation = location; return true; }
//----------------------------------------------------------------------------- // // VActorPhysicsController::postTickUpdate( pDelta ); // // ... // //----------------------------------------------------------------------------- void VActorPhysicsController::postTickUpdate( const F32 &pDelta ) { switch( mControlState ) { case k_PathControlState : { AssertFatal( isPathing(), "VActorPhysicsController::postTickUpdate() - Invalid Path State." ); // Fetch Mount Transform. MatrixF transform; mMountedPath->getMountTransform( mObject->getMountNode(), getTransform(), &transform ); // Fetch Mount Position. const Point3F &mountPosition = transform.getPosition(); // Update X & Y Position. Point3F position = getPosition(); position.x = mountPosition.x; position.y = mountPosition.y; // In Water? bool underWater = false; if ( isInWater() ) { // Fetch Body of Water. WaterObject *waterBody = getWaterObject(); // Fetch Surface Position. const F32 &waterSurfacePosition = waterBody->getSurfaceHeight( Point2F( position.x, position.y ) ); // Fetch Submersion Position. const F32 sumbersionPosition = waterSurfacePosition - ( mObject->getWorldBox().len_z() * mObject->getDataBlock()->getSumbergeCoverage() ); // Choose a Z Value. // Note: This is done so that the Actor will either path under the // water, or it will swim along the water's surface. position.z = getMin( mountPosition.z, sumbersionPosition ); // Under Water? underWater = ( position.z < sumbersionPosition ); } // Under Water? if ( !underWater ) { // Fetch Y Column. VectorF forwardVector; transform.getColumn( 1, &forwardVector ); // Determine Angle. const F32 &angle = -mAtan2( -forwardVector.x, forwardVector.y ); // Reset Transform. transform.set( EulerF( 0.f, 0.f, angle ) ); // In the air? if ( !isOnGround() ) { // Apply z-axis force. position.z += ( getVelocity().z * pDelta ); } } // Update Transform. transform.setPosition( position ); // Apply Update. setTransform( transform ); } break; default : { // Fetch Transform. MatrixF transform = getTransform(); // Determine the Post-Tick Position. Point3F postTickPosition = getPosition() + ( getVelocity() * pDelta ); // Set the Post Tick Position. transform.setPosition( postTickPosition ); // Apply the Transform. setTransform( transform ); } break; } // Push Delta. mInterpController.pushDelta( getTransform() ); }
void PxSingleActor::processTick( const Move *move ) { PROFILE_SCOPE( PxSingleActor_ProcessTick ); if ( !mActor ) return; // Set the last pos/rot to the // values of the previous tick for interpolateTick. mLastPos = mNextPos; mLastRot = mNextRot; if ( mActor->isSleeping() || mActor->readBodyFlag( NX_BF_FROZEN ) ) { /* if ( !mSleepingLastTick ) { // TODO: We cannot use a warp when we sleep. The warp // can cause interpenetration with other actors which // then cause explosions on the next simulation tick. // // Instead lets have the sleep mask itself send the sleep // position and let it set the actor in a safe manner // that is specific to sleeping. setMaskBits( WarpMask | SleepMask ); } */ mSleepingLastTick = true; return; } mSleepingLastTick = false; // Container buoyancy & drag _updateContainerForces(); // Set the Torque transform to the dynamic actor's transform. MatrixF mat; mActor->getGlobalPose().getRowMajor44( mat ); Parent::setTransform( mat ); // Set the next pos/rot to the current values. mNextPos = mat.getPosition(); mNextRot.set( mat ); // TODO: We removed passing move updates to the client // on every tick because it was a waste of bandwidth. The // client is correct or within limits the vast majority of // the time. // // Still it can get out of sync. To correct this when the // actor sleeps can cause large ugly jumps in position. One // thought here was to hide the correction by waiting until // the object and its new position are offscreen. Short of // that we have to apply corrections gradually over the time // of movement if we want corrections to work well. // // Lets consider some techniques for future improvement. // // First lets send updates to all non-sleeping actors in some // sort of round robin fashion, so that the bandwidth used is // limited by the number of actors moving. If 1 actor is moving // it sends updates every tick... if 10 actors are moving each // actor gets an update every 10 ticks. Lets say a really ugly // case... 100 moving actors... every actor is updated every // 3.2 seconds... thats probably acceptable. // // Second lets also consider the idea of sending a velocity only // correction more regularly. If the actors are in the same start // position, a correct velocity would do as much good as a position. // Plus the linear velocity can me compressed really well.. less // than 64 bits. Maybe sending velocity regularly and positions // less regular would work? // // A more radical idea would be to have a special scene object that // manages all the packUpdates for all actors. This object would // ensure that the right actors are updated and break up the updates // in a way to limit bandwidth usage. // Set the MoveMask so this will be updated to the client. //setMaskBits( MoveMask ); }
void ConvexShape::_renderDebug( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mat ) { GFXDrawUtil *drawer = GFX->getDrawUtil(); GFX->setTexture( 0, NULL ); // Render world box. if ( false ) { Box3F wbox( mWorldBox ); //if ( getServerObject() ) // Box3F wbox = static_cast<ConvexShape*>( getServerObject() )->mWorldBox; GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); desc.setFillModeWireframe(); drawer->drawCube( desc, wbox, ColorI::RED ); } const Vector< Point3F > &pointList = mGeometry.points; const Vector< ConvexShape::Face > &faceList = mGeometry.faces; // Render Edges. if ( false ) { GFXTransformSaver saver; //GFXFrustumSaver fsaver; MatrixF xfm( getRenderTransform() ); xfm.scale( getScale() ); GFX->multWorld( xfm ); GFXStateBlockDesc desc; desc.setZReadWrite( true, false ); desc.setBlend( true ); GFX->setStateBlockByDesc( desc ); //MathUtils::getZBiasProjectionMatrix( 0.01f, state->getFrustum(), ) const Point3F &camFvec = state->getCameraTransform().getForwardVector(); for ( S32 i = 0; i < faceList.size(); i++ ) { const ConvexShape::Face &face = faceList[i]; const Vector< ConvexShape::Edge > &edgeList = face.edges; const Vector< U32 > &facePntList = face.points; PrimBuild::begin( GFXLineList, edgeList.size() * 2 ); PrimBuild::color( ColorI::WHITE * 0.8f ); for ( S32 j = 0; j < edgeList.size(); j++ ) { PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] - camFvec * 0.001f ); PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] - camFvec * 0.001f ); } PrimBuild::end(); } } ColorI faceColorsx[4] = { ColorI( 255, 0, 0 ), ColorI( 0, 255, 0 ), ColorI( 0, 0, 255 ), ColorI( 255, 0, 255 ) }; MatrixF objToWorld( mObjToWorld ); objToWorld.scale( mObjScale ); // Render faces centers/colors. if ( false ) { GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); Point3F size( 0.1f ); for ( S32 i = 0; i < faceList.size(); i++ ) { ColorI color = faceColorsx[ i % 4 ]; S32 div = ( i / 4 ) * 4; if ( div > 0 ) color /= div; color.alpha = 255; Point3F pnt; objToWorld.mulP( faceList[i].centroid, &pnt ); drawer->drawCube( desc, size, pnt, color, NULL ); } } // Render winding order. if ( false ) { GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); desc.setZReadWrite( true, false ); GFX->setStateBlockByDesc( desc ); U32 pointCount = 0; for ( S32 i = 0; i < faceList.size(); i++ ) pointCount += faceList[i].winding.size(); PrimBuild::begin( GFXLineList, pointCount * 2 ); for ( S32 i = 0; i < faceList.size(); i++ ) { for ( S32 j = 0; j < faceList[i].winding.size(); j++ ) { Point3F p0 = pointList[ faceList[i].points[ faceList[i].winding[j] ] ]; Point3F p1 = p0 + mSurfaces[ faceList[i].id ].getUpVector() * 0.75f * ( Point3F::One / mObjScale ); objToWorld.mulP( p0 ); objToWorld.mulP( p1 ); ColorI color = faceColorsx[ j % 4 ]; S32 div = ( j / 4 ) * 4; if ( div > 0 ) color /= div; color.alpha = 255; PrimBuild::color( color ); PrimBuild::vertex3fv( p0 ); PrimBuild::color( color ); PrimBuild::vertex3fv( p1 ); } } PrimBuild::end(); } // Render Points. if ( false ) { /* GFXTransformSaver saver; MatrixF xfm( getRenderTransform() ); xfm.scale( getScale() ); GFX->multWorld( xfm ); GFXStateBlockDesc desc; Point3F size( 0.05f ); */ } // Render surface transforms. if ( false ) { GFXStateBlockDesc desc; desc.setBlend( false ); desc.setZReadWrite( true, true ); Point3F scale(mNormalLength); for ( S32 i = 0; i < mSurfaces.size(); i++ ) { MatrixF objToWorld( mObjToWorld ); objToWorld.scale( mObjScale ); MatrixF renderMat; renderMat.mul( objToWorld, mSurfaces[i] ); renderMat.setPosition( renderMat.getPosition() + renderMat.getUpVector() * 0.001f ); drawer->drawTransform( desc, renderMat, &scale, NULL ); } } }
void Projectile::emitParticles(const Point3F& from, const Point3F& to, const Point3F& vel, const U32 ms) { if ( mHasExploded ) return; Point3F axis = -vel; if( axis.isZero() ) axis.set( 0.0, 0.0, 1.0 ); else axis.normalize(); bool fromWater = pointInWater(from); bool toWater = pointInWater(to); if (!fromWater && !toWater && bool(mParticleEmitter)) // not in water mParticleEmitter->emitParticles(from, to, axis, vel, ms); else if (fromWater && toWater && bool(mParticleWaterEmitter)) // in water mParticleWaterEmitter->emitParticles(from, to, axis, vel, ms); else if (!fromWater && toWater && mDataBlock->splash) // entering water { // cast the ray to get the surface point of the water RayInfo rInfo; if (gClientContainer.castRay(from, to, WaterObjectType, &rInfo)) { MatrixF trans = getTransform(); trans.setPosition(rInfo.point); Splash *splash = new Splash(); splash->onNewDataBlock(mDataBlock->splash, false); splash->setTransform(trans); splash->setInitialState(trans.getPosition(), Point3F(0.0, 0.0, 1.0)); if (!splash->registerObject()) { delete splash; splash = NULL; } // create an emitter for the particles out of water and the particles in water if (mParticleEmitter) mParticleEmitter->emitParticles(from, rInfo.point, axis, vel, ms); if (mParticleWaterEmitter) mParticleWaterEmitter->emitParticles(rInfo.point, to, axis, vel, ms); } } else if (fromWater && !toWater && mDataBlock->splash) // leaving water { // cast the ray in the opposite direction since that point is out of the water, otherwise // we hit water immediately and wont get the appropriate surface point RayInfo rInfo; if (gClientContainer.castRay(to, from, WaterObjectType, &rInfo)) { MatrixF trans = getTransform(); trans.setPosition(rInfo.point); Splash *splash = new Splash(); splash->onNewDataBlock(mDataBlock->splash,false); splash->setTransform(trans); splash->setInitialState(trans.getPosition(), Point3F(0.0, 0.0, 1.0)); if (!splash->registerObject()) { delete splash; splash = NULL; } // create an emitter for the particles out of water and the particles in water if (mParticleEmitter) mParticleEmitter->emitParticles(rInfo.point, to, axis, vel, ms); if (mParticleWaterEmitter) mParticleWaterEmitter->emitParticles(from, rInfo.point, axis, vel, ms); } } }