I am working on an interactive ISS - space shuttle docking simulator, and am having problems with how the ISS and shuttle are rendered when the two get close together -- sometimes the iss is completely on top of the shuttle, and sometimes it's the other way around. It really only seems to be a problem once the shuttle moves inside the ISS's bounding sphere.
I noticed in the render.cpp file that each object is allocated its own small section of the Z-buffer (by using the glDepthRange function), and that the comments mention letting "overlapping objects share a depth buffer range." I believe that I have implemented this change as so:
int nDepthBuckets = 1;
int i;
int issBucket = -1;
int orbBucket = -1;
for (i = 0; i < nEntries; i++)
{
if (renderList[i].discSizeInPixels > 1)
{
nDepthBuckets++;
if( renderList[i].body != NULL )
{
// save the bucket indeces for the ISS and shuttle - the +1
// is added because the objects are rendered from last
// to first below, but are ordered first to last in this loop
if( renderList[i].body->getName() == "ISS" )
issBucket = i+1;
if( renderList[i].body->getName() == "Shuttle" )
orbBucket = i+1;
}
}
}
.
.
.
and whenever the bucket is changed in any subsequent call to glDepthRange, I have used the following code:
if( (depthBucket == orbBucket || depthBucket == issBucket) &&
(orbBucket == (issBucket-1) || orbBucket == (issBucket+1)) )
{
if( orbBucket < issBucket )
glDepthRange( orbBucket * depthRange,
(issBucket + 1) * depthRange );
else
glDepthRange( issBucket * depthRange,
(orbBucket + 1) * depthRange );
}
else
// the original call
glDepthRange(depthBucket * depthRange,
(depthBucket + 1) * depthRange);
I did make the assumption that the shuttle will be rendered immediately after the ISS (or vice versa) -- this assumption holds true for all instances of my simulator.
Does anyone know how/why the Z-buffer is being split up like this, and how I might even be able to fix this overlapping problem?
Thanks in advance,
Dan
ISS - Shuttle Docking Simulation
-
- Site Admin
- Posts: 4211
- Joined: 28.01.2002
- With us: 22 years 10 months
- Location: Seattle, Washington, USA
The depth buffer is split up because there aren't enough bits of depth precision to handle rendering a scene with both human and planet scale objects in the same scene. I've done some preliminary work on an algorithm that would merge depth buckets for objects that overlap in z and are roughly the same size . . . A final implementation is a ways off, but the fix will appear in 1.3.2.
--Chris
--Chris
-
Topic authorGuest
OK, I've solved my problem. For the sake of future Celestia development, I'll post my results
In addition to sharing the same depth buckets, the ISS and Shuttle must both share the same near and far clip planes. Here's some code:
And now when the near and far plane variables are calculated...
With the addition of the depth buffer bucket switching code from my first post, the shuttle always appears in the correct position relative to the ISS (wish I could post a screenshot...)
My solution is too limited for exact use in Celestia, but a variation could be used, perhaps by modifying the RenderListEntry structure to include a "overlapping" flag, as well as a pointer to the body it overlaps with. Just a thought...
Good luck with the future development of Celestia. It is an incredible program.
In addition to sharing the same depth buckets, the ISS and Shuttle must both share the same near and far clip planes. Here's some code:
Code: Select all
double issNearPlane = 1e6;
double issFarPlane = 1e-6;
double orbNearPlane = 1e6;
double orbFarPlane = 1e-6;
for (i = 0; i < nEntries; i++)
{
if (renderList[i].discSizeInPixels > 1)
{
nDepthBuckets++;
// while looping through the render list, test each entry to see if they
// represent the ISS or Shuttle. if so, calculate the near and far clip
// planes (exactly like what is done below), and save the bucket index
if( renderList[i].body != NULL )
{
if( renderList[i].body->getName() == "ISS" )
{
issNearPlane = renderList[i].nearZ * -0.9f;
issFarPlane = renderList[i].farZ * -1.1f;
if( issNearPlane < MinNearPlaneDistance )
issNearPlane = MinNearPlaneDistance;
if( issFarPlane / issNearPlane > MaxFarNearRatio )
issFarPlane = issNearPlane * MaxFarNearRatio;
issBucket = i+1;
}
if( renderList[i].body->getName() == "Shuttle" )
{
orbNearPlane = renderList[i].nearZ * -0.9f;
orbFarPlane = renderList[i].farZ * -1.1f;
if( orbNearPlane < MinNearPlaneDistance )
orbNearPlane = MinNearPlaneDistance;
if( orbFarPlane / orbNearPlane > MaxFarNearRatio )
orbFarPlane = orbNearPlane * MaxFarNearRatio;
orbBucket = i+1;
}
}
}
}
// ensure that both near clip planes are the lesser of the two possible
// clip plane values, and vice versa for the far clip planes. this just
// gets rid of more if() statements below
issNearPlane = issNearPlane < orbNearPlane ? issNearPlane : orbNearPlane;
issFarPlane = issFarPlane < orbFarPlane ? orbFarPlane : issFarPlane;
orbNearPlane = issNearPlane < orbNearPlane ? issNearPlane : orbNearPlane;
orbFarPlane = issFarPlane < orbFarPlane ? orbFarPlane : issFarPlane;
And now when the near and far plane variables are calculated...
Code: Select all
// if the object that is being rendered is the ISS or Shuttle, then we need to update the
// near and far clip planes. if not, then use the default near and far plane calculations
if( renderList[i].body != NULL && renderList[i].body->getName() != "ISS" && renderList[i].body->getName() != "Shuttle" )
{
// the defaults
nearPlaneDistance = renderList[i].nearZ * -0.9f;
farPlaneDistance = renderList[i].farZ * -1.1f;
if (nearPlaneDistance < MinNearPlaneDistance)
nearPlaneDistance = MinNearPlaneDistance;
if (farPlaneDistance / nearPlaneDistance > MaxFarNearRatio)
farPlaneDistance = nearPlaneDistance * MaxFarNearRatio;
}
else // setting either ISS or orbiter near/far planes
{
nearPlaneDistance = issNearPlane;
farPlaneDistance = issFarPlane;
}
With the addition of the depth buffer bucket switching code from my first post, the shuttle always appears in the correct position relative to the ISS (wish I could post a screenshot...)
My solution is too limited for exact use in Celestia, but a variation could be used, perhaps by modifying the RenderListEntry structure to include a "overlapping" flag, as well as a pointer to the body it overlaps with. Just a thought...
Good luck with the future development of Celestia. It is an incredible program.