bool TurretShape::getWorldNodeTransform(S32 node, MatrixF& mat) { MatrixF nodeMat; if (!getNodeTransform(node, nodeMat)) return false; nodeMat.affineInverse(); mat = nodeMat; return true; }
void TurretShape::getImageTransform(U32 imageSlot,S32 node,MatrixF* mat) { // Same as ShapeBase::getImageTransform() other than getRenderWeaponMountTransform() below // Image transform in world space MountedImage& image = mMountedImageList[imageSlot]; if (image.dataBlock) { if (node != -1) { ShapeBaseImageData& data = *image.dataBlock; U32 shapeIndex = getImageShapeIndex(image); MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node]; MatrixF mmat; if (data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1) { // We need to animate, even on the server, to make sure the nodes are in the correct location. image.shapeInstance[shapeIndex]->animate(); MatrixF emat; getEyeBaseTransform(&emat, mDataBlock->mountedImagesBank); MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]]; mountTransform.affineInverse(); mmat.mul(emat, mountTransform); } else if (data.useEyeOffset && isFirstPerson()) { MatrixF emat; getEyeTransform(&emat); mmat.mul(emat,data.eyeOffset); } else { MatrixF emat; getWeaponMountTransform( imageSlot, MatrixF::Identity, &emat ); mmat.mul(emat,data.mountTransform[shapeIndex]); } mat->mul(mmat, nmat); } else getImageTransform(imageSlot,mat); } else *mat = mObjToWorld; }
void TerrainCellMaterial::setTransformAndEye( const MatrixF &modelXfm, const MatrixF &viewXfm, const MatrixF &projectXfm, F32 farPlane ) { PROFILE_SCOPE( TerrainCellMaterial_SetTransformAndEye ); MatrixF modelViewProj = projectXfm * viewXfm * modelXfm; MatrixF invViewXfm( viewXfm ); invViewXfm.inverse(); Point3F eyePos = invViewXfm.getPosition(); MatrixF invModelXfm( modelXfm ); invModelXfm.inverse(); Point3F objEyePos = eyePos; invModelXfm.mulP( objEyePos ); VectorF vEye = invViewXfm.getForwardVector(); vEye.normalize( 1.0f / farPlane ); for ( U32 i=0; i < mPasses.size(); i++ ) { Pass &pass = mPasses[i]; pass.consts->setSafe( pass.modelViewProjConst, modelViewProj ); if( pass.viewToObj->isValid() || pass.worldViewOnly->isValid() ) { MatrixF worldViewOnly = viewXfm * modelXfm; pass.consts->setSafe( pass.worldViewOnly, worldViewOnly ); if( pass.viewToObj->isValid() ) { worldViewOnly.affineInverse(); pass.consts->set( pass.viewToObj, worldViewOnly); } } pass.consts->setSafe( pass.eyePosWorldConst, eyePos ); pass.consts->setSafe( pass.eyePosConst, objEyePos ); pass.consts->setSafe( pass.objTransConst, modelXfm ); pass.consts->setSafe( pass.worldToObjConst, invModelXfm ); pass.consts->setSafe( pass.vEyeConst, vEye ); } }
void AITurretShape::_trackTarget(F32 dt) { // Only on server if (isClientObject()) return; // We can only track a target if we have one if (!mTarget.isValid()) return; Point3F targetPos = mTarget.target->getBoxCenter(); // Can we see the target? MatrixF aimMat; getAimTransform(aimMat); Point3F start; aimMat.getColumn(3, &start); RayInfo ri; Point3F sightPoint; disableCollision(); bool los = _testTargetLineOfSight(start, mTarget.target, sightPoint); enableCollision(); if (!los) { // Target is blocked. Should we try to track from its last // known position and velocity? SimTime curTime = Sim::getCurrentTime(); if ( (curTime - mTarget.lastSightTime) > (mDataBlock->trackLostTargetTime * 1000.0f) ) { // Time's up. Stop tracking. _cleanupTargetAndTurret(); return; } // Use last known information to attempt to // continue to track target for a while. targetPos = mTarget.lastPos + mTarget.lastVel * F32(curTime - mTarget.lastSightTime) / 1000.0f; } else { // Target is visible // We only track targets that are alive if (mTarget.target->getDamageState() != Enabled) { // We can't track any more _cleanupTargetAndTurret(); return; } targetPos = sightPoint; // Store latest target info mTarget.lastPos = targetPos; mTarget.lastVel = mTarget.target->getVelocity(); mTarget.lastSightTime = Sim::getCurrentTime(); } // Calculate angles to face the target, specifically the part that we can see VectorF toTarget; MatrixF mat; S32 node = mDataBlock->aimNode; if (node != -1) { // Get the current position of our node MatrixF* nodeTrans = &mShapeInstance->mNodeTransforms[node]; Point3F currentPos; nodeTrans->getColumn(3, ¤tPos); // Turn this into a matrix we can use to put the target // position into our space. MatrixF nodeMat(true); nodeMat.setColumn(3, currentPos); mat.mul(mObjToWorld, nodeMat); mat.affineInverse(); } else { mat = mWorldToObj; } mat.mulP(targetPos, &toTarget); // lead the target F32 timeToTargetSquared = (mWeaponLeadVelocitySquared > 0) ? toTarget.lenSquared() / mWeaponLeadVelocitySquared : 0; if (timeToTargetSquared > 1.0) { targetPos = targetPos + (mTarget.lastVel * mSqrt(timeToTargetSquared)); mat.mulP(targetPos, &toTarget); } F32 yaw, pitch; MathUtils::getAnglesFromVector(toTarget, yaw, pitch); if (yaw > M_PI_F) yaw = yaw - M_2PI_F; //if (pitch > M_PI_F) // pitch = -(pitch - M_2PI_F); Point3F rot(-pitch, 0.0f, yaw); // If we have a rotation rate make sure we follow it if (mHeadingRate > 0) { F32 rate = mHeadingRate * dt; F32 rateCheck = mFabs(rot.z - mRot.z); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.z = mClampF(rot.z, mRot.z-rate, mRot.z+rate); } } if (mPitchRate > 0) { F32 rate = mPitchRate * dt; F32 rateCheck = mFabs(rot.x - mRot.x); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.x = mClampF(rot.x, mRot.x-rate, mRot.x+rate); } } // Test if the rotation to the target is outside of our limits if (_outsideLimits(rot)) { // We can't track any more _cleanupTargetAndTurret(); return; } // Test if the target is out of weapons range if (toTarget.lenSquared() > mWeaponRangeSquared) { // We can't track any more _cleanupTargetAndTurret(); return; } mRot = rot; _setRotation( mRot ); setMaskBits(TurretUpdateMask); }