Constraining camera to terrain / interiors
by Keith Johnston · 12/13/2002 (3:08 pm) · 9 comments
This code stops the camera in observer mode from entering interiors and the terrain by maintaining a fixed distance from the terrain and walls. As the camera collides with the terrain / walls, it 'skims' along the surface, continuing to move in the directions that it can move - just not in the direction where the collision occurs.
Note: if the camera moves too quickly this code does not catch the collisions. I'm hoping someone can help me figure out why. Also - I have only tested this on windows, and only with the 1.1.2 revision.
In camera.h, add this function:
In camera.cc, add the implementation:
In processTick(), right before the setPosition when not in orbit mode,
add a call to updatePos.
...
Also added the same call in interpolateTick:
Note: if the camera moves too quickly this code does not catch the collisions. I'm hoping someone can help me figure out why. Also - I have only tested this on windows, and only with the 1.1.2 revision.
In camera.h, add this function:
Point3F updatePos(const Point3F& oldPos,const Point3F& newPos, F32 testLen);
In camera.cc, add the implementation:
Point3F Camera::updatePos(const Point3F& oldPos,const Point3F& newPos, F32 testLen)
{
if (oldPos==newPos || gEditingMission)
return newPos;
Point3F test=newPos-oldPos;
F32 len = test.len();
test.normalize();
Point3F testPos = oldPos+(test*(len+testLen));
RayInfo rinfo;
if (getContainer()!=NULL) {
if (getContainer()->castRay(oldPos, testPos, (InteriorObjectType | TerrainObjectType), &rinfo)) {
float dot = mDot(test,rinfo.normal);
if (dot < 0) {
// Get a vector for the direction and distance the test point overshot
Point3F oops = testPos - rinfo.point;
// Get the length we shot past
F32 newLen = mDot(oops,rinfo.normal);
if (newLen > testLen)
newLen=testLen;
// Subtract the vector that took us past the collision point
return (newPos - newLen*rinfo.normal);
} else
return newPos;
}
else {
return newPos;
}
} else {
return newPos;
}
}In processTick(), right before the setPosition when not in orbit mode,
add a call to updatePos.
...
if(mode == OrbitObjectMode || mode == OrbitPointMode)
{
if(mode == OrbitObjectMode && bool(mOrbitObject))
mOrbitObject->getWorldBox().getCenter(&mPosition);
setPosition(mPosition, mRot);
validateEyePoint(1.0f, &mObjToWorld);
pos = mPosition;
}
else
{
// Update pos
bool faster = move->trigger[0] || move->trigger[1];
F32 scale = mMovementSpeed * (faster + 1);
mObjToWorld.getColumn(3,&pos);
mObjToWorld.getColumn(0,&vec);
pos += vec * move->x * TickSec * scale;
mObjToWorld.getColumn(1,&vec);
pos += vec * move->y * TickSec * scale;
mObjToWorld.getColumn(2,&vec);
pos += vec * move->z * TickSec * scale;
pos = updatePos(getTransform().getPosition(),pos,5.0); // <- added call
setPosition(pos,mRot);
}Also added the same call in interpolateTick:
void Camera::interpolateTick(F32 dt)
{
Parent::interpolateTick(dt);
Point3F rot = delta.rot + delta.rotVec * dt;
if(mode == OrbitObjectMode || mode == OrbitPointMode)
{
if(mode == OrbitObjectMode && bool(mOrbitObject))
mOrbitObject->getRenderWorldBox().getCenter(&mPosition);
setPosition(mPosition, rot);
validateEyePoint(1.0f, &mObjToWorld);
}
else {
Point3F pos = delta.pos + delta.posVec * dt;
pos = updatePos(getTransform().getPosition(),pos,5.0); // <-- added call
setPosition(pos,rot);
}
}
#2
12/14/2002 (7:10 am)
Possibly - unfortunately I've modified things so much that I can't easily test that (I don't have a player model - just a camera).
#3
12/16/2002 (1:39 pm)
Works great Keith! I want to also look at disabling this when editing though
#4
12/20/2002 (7:14 am)
Desmond - thanks for the feedback! I just updated the function updatePos in this resource to do as you suggested: the camera now works as normal when editing the mission.
#5
02/20/2003 (12:16 am)
Does anyone else have a problem with the camera being extremely jittery when sliding along a wall? When it's in a corner and is being moved against it, it jitters and shakes like a chihuahua on caffeine. Did I screw this up somehow?
#6
In multiplayer if you are not the server and if you die and wait till body desapears. The camera is then thrown somwhere below the map and you cannot move from that spot. You can respawn and play normaly tho.
03/07/2003 (1:17 pm)
Well this thing still works in current head (7. march 2003) however I found a bug.In multiplayer if you are not the server and if you die and wait till body desapears. The camera is then thrown somwhere below the map and you cannot move from that spot. You can respawn and play normaly tho.
#7
12/14/2003 (3:44 pm)
James, I have the jittery problem when sliding along walls.
#8
12/10/2007 (6:56 pm)
this code works with 1.5.x ?
#9
05/28/2009 (3:15 am)
i tried this resource for TGEA1.8.1 , but it is still going inside of the interiors and terrain. the collision is not working properly. can you tell any solution to implement this for TGEA1.8.1?? thanks in Advance.. 
Associate Ken Finney
Tubetti World