Implemented secondary illumination (e.g. planetshine.) Rewrote much of the code that contructs render lists to make it possible to do compute secondary illumination efficiently. This patch fixes two other bugs. The orbit of barycenters is shown when they have children that are planets, moons, or asteroids. And, an incorrect frame release was fixed in solarsys.cpp.

ver1_6_1
Chris Laurel 2008-04-03 17:46:45 +00:00
parent 9017964c44
commit d216a98755
7 changed files with 904 additions and 445 deletions

View File

@ -48,9 +48,11 @@ Body::Body(PlanetarySystem* _system, const string& _name) :
clickable(1),
visibleAsPoint(1),
overrideOrbitColor(0),
orbitVisibility(UseClassVisibility)
orbitVisibility(UseClassVisibility),
secondaryIlluminator(true)
{
setName(_name);
recomputeCullingRadius();
system->addBody(this);
}
@ -99,6 +101,7 @@ void Body::setDefaultProperties()
visibleAsPoint = 1;
overrideOrbitColor = 0;
orbitVisibility = UseClassVisibility;
recomputeCullingRadius();
}
@ -192,9 +195,17 @@ const RotationModel* Body::getRotationModel(double tdb) const
}
// For an irregular object, the radius is defined to be the largest semi-axis
// of the axis-aligned bounding box. The radius of the smallest sphere
// containing the object is potentially larger by a factor of sqrt(3)
/*! Get the radius of a sphere large enough to contain the primary
* geometry of the object: either a mesh or an ellipsoid.
* For an irregular (mesh) object, the radius is defined to be
* the largest semi-axis of the axis-aligned bounding box. The
* radius of the smallest sphere containing the object is potentially
* larger by a factor of sqrt(3).
*
* This method does not consider additional object features
* such as rings, atmospheres, or reference marks; use
* getCullingRadius() for that.
*/
float Body::getBoundingRadius() const
{
if (model == InvalidResource)
@ -204,6 +215,16 @@ float Body::getBoundingRadius() const
}
/*! Return the radius of sphere large enough to contain any geometry
* associated with this object: the primary geometry, comet tail,
* rings, atmosphere shell, cloud layers, or reference marks.
*/
float Body::getCullingRadius() const
{
return cullingRadius;
}
float Body::getMass() const
{
return mass;
@ -248,6 +269,7 @@ void Body::setSemiAxes(const Vec3f& _semiAxes)
// Radius will always be the largest of the three semi axes
radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
recomputeCullingRadius();
}
@ -344,6 +366,7 @@ void Body::setRings(const RingSystem& _rings)
rings = new RingSystem(_rings);
else
*rings = _rings;
recomputeCullingRadius();
}
@ -362,6 +385,7 @@ void Body::setAtmosphere(const Atmosphere& _atmosphere)
if (atmosphere == NULL)
atmosphere = new Atmosphere();
*atmosphere = _atmosphere;
recomputeCullingRadius();
}
@ -678,6 +702,42 @@ int Body::getClassification() const
void Body::setClassification(int _classification)
{
classification = _classification;
recomputeCullingRadius();
markChanged();
}
/*! Return the effective classification of this body used when rendering
* orbits. Normally, this is just the classification of the object, but
* invisible objects are treated specially: they behave as if they have
* the classification of their child objects. This fixes annoyances when
* planets are defined with orbits relative to their system barycenters.
* For example, Pluto's orbit can seen in a solar system scale view, even
* though its orbit is defined relative to the Pluto-Charon barycenter
* and is this just a few hundred kilometers in size.
*/
int Body::getOrbitClassification() const
{
if (classification != Invisible || frameTree == NULL)
{
return classification;
}
else
{
int orbitClass = frameTree->childClassMask();
if (orbitClass & Planet)
return Planet;
else if (orbitClass & DwarfPlanet)
return DwarfPlanet;
else if (orbitClass & Moon)
return Moon;
else if (orbitClass & Asteroid)
return Asteroid;
else if (orbitClass & Spacecraft)
return Spacecraft;
else
return Invisible;
}
}
@ -838,6 +898,7 @@ Body::addReferenceMark(ReferenceMark* refMark)
if (referenceMarks == NULL)
referenceMarks = new list<ReferenceMark*>();
referenceMarks->push_back(refMark);
recomputeCullingRadius();
}
@ -853,6 +914,7 @@ Body::removeReferenceMark(const string& tag)
{
referenceMarks->remove(refMark);
delete refMark;
recomputeCullingRadius();
}
}
}
@ -950,6 +1012,52 @@ void Body::setOrbitColor(const Color& c)
}
/*! Set whether or not the object should be considered when calculating
* secondary illumination (e.g. planetshine.)
*/
void Body::setSecondaryIlluminator(bool enable)
{
if (enable != secondaryIlluminator)
{
markChanged();
secondaryIlluminator = enable;
}
}
void Body::recomputeCullingRadius()
{
float r = getBoundingRadius();
if (rings != NULL)
r = max(r, rings->outerRadius);
if (atmosphere != NULL)
{
r = max(r, atmosphere->height);
r = max(r, atmosphere->cloudHeight);
}
if (referenceMarks != NULL)
{
for (std::list<ReferenceMark*>::const_iterator iter = referenceMarks->begin();
iter != referenceMarks->end(); iter++)
{
r = max(r, (*iter)->boundingSphereRadius());
}
}
if (classification == Body::Comet)
r = max(r, astro::AUtoKilometers(1.0f));
if (r != cullingRadius)
{
cullingRadius = r;
markChanged();
}
}
/**** Implementation of PlanetarySystem ****/
/*! Return the equatorial frame for this object. This frame is used as

View File

@ -166,6 +166,7 @@ class Body
void setSatellites(PlanetarySystem*);
float getBoundingRadius() const;
float getCullingRadius() const;
RingSystem* getRings() const;
void setRings(const RingSystem&);
@ -237,12 +238,17 @@ class Body
void setVisibleAsPoint(bool _visibleAsPoint);
bool isOrbitColorOverridden() const { return overrideOrbitColor == 1; }
void setOrbitColorOverridden(bool override);
bool isSecondaryIlluminator() const { return secondaryIlluminator; }
void setSecondaryIlluminator(bool enable);
VisibilityPolicy getOrbitVisibility() const { return orbitVisibility; }
void setOrbitVisibility(VisibilityPolicy _orbitVisibility);
Color getOrbitColor() const { return orbitColor; }
void setOrbitColor(const Color&);
int getOrbitClassification() const;
enum
{
BodyAxes = 0x01,
@ -266,6 +272,9 @@ class Body
void markChanged();
void markUpdated();
private:
void recomputeCullingRadius();
private:
std::string name;
std::string i18nName;
@ -285,6 +294,8 @@ class Body
float albedo;
Quatf orientation;
float cullingRadius;
ResourceHandle model;
Surface surface;
@ -311,6 +322,7 @@ class Body
unsigned int visibleAsPoint : 1;
unsigned int overrideOrbitColor : 1;
VisibilityPolicy orbitVisibility : 3;
bool secondaryIlluminator : 1;
};
#endif // _CELENGINE_BODY_H_

View File

@ -84,110 +84,117 @@ FrameTree::getDefaultReferenceFrame() const
/*! Mark this node of the frame hierarchy as changed. The changed flag
* is propagated up toward the root of the tree.
*/
void
FrameTree::markChanged()
{
if (!m_changed)
{
m_changed = true;
if (bodyParent != NULL)
bodyParent->markChanged();
}
}
/*! Mark this node of the frame hierarchy as updated. The changed flag
* is marked false in this node and in all child nodes that
* were marked changed.
*/
void
FrameTree::markUpdated()
{
if (m_changed)
{
m_changed = false;
for (vector<TimelinePhase*>::iterator iter = children.begin();
iter != children.end(); iter++)
{
(*iter)->body()->markUpdated();
}
}
}
/*! Recompute the bounding sphere for this tree and all subtrees marked
* as having changed. The bounding sphere is large enough to accommodate
* the orbits (and radii) of all child bodies. This method also recomputes
* the maximum child radius.
*/
void
FrameTree::recomputeBoundingSphere()
{
if (m_changed)
{
m_boundingSphereRadius = 0.0;
m_maxChildRadius = 0.0;
for (vector<TimelinePhase*>::iterator iter = children.begin();
iter != children.end(); iter++)
{
TimelinePhase* phase = *iter;
double bodyRadius = phase->body()->getRadius();
double r = bodyRadius + phase->orbit()->getBoundingRadius();
m_maxChildRadius = max(m_maxChildRadius, bodyRadius);
FrameTree* tree = phase->body()->getFrameTree();
if (tree != NULL)
{
tree->recomputeBoundingSphere();
r += tree->m_boundingSphereRadius;
m_maxChildRadius = max(m_maxChildRadius, tree->m_maxChildRadius);
}
m_boundingSphereRadius = max(m_boundingSphereRadius, r);
}
}
}
/*! Add a new phase to this tree.
*/
void
FrameTree::addChild(TimelinePhase* phase)
{
phase->addRef();
children.push_back(phase);
markChanged();
}
/*! Remove a phase from the tree. This method does nothing if the specified
* phase doesn't exist in the tree.
*/
void
FrameTree::removeChild(TimelinePhase* phase)
{
vector<TimelinePhase*>::iterator iter = find(children.begin(), children.end(), phase);
if (iter != children.end())
{
(*iter)->release();
children.erase(iter);
markChanged();
}
}
/*! Return the child at the specified index. */
TimelinePhase*
FrameTree::getChild(unsigned int n) const
{
return children[n];
}
/*! Get the number of immediate children of this tree. */
unsigned int
FrameTree::childCount() const
{
return children.size();
}
void
FrameTree::markChanged()
{
if (!m_changed)
{
m_changed = true;
if (bodyParent != NULL)
bodyParent->markChanged();
}
}
/*! Mark this node of the frame hierarchy as updated. The changed flag
* is marked false in this node and in all child nodes that
* were marked changed.
*/
void
FrameTree::markUpdated()
{
if (m_changed)
{
m_changed = false;
for (vector<TimelinePhase*>::iterator iter = children.begin();
iter != children.end(); iter++)
{
(*iter)->body()->markUpdated();
}
}
}
/*! Recompute the bounding sphere for this tree and all subtrees marked
* as having changed. The bounding sphere is large enough to accommodate
* the orbits (and radii) of all child bodies. This method also recomputes
* the maximum child radius, secondary illuminator status, and child
* class mask.
*/
void
FrameTree::recomputeBoundingSphere()
{
if (m_changed)
{
m_boundingSphereRadius = 0.0;
m_maxChildRadius = 0.0;
m_containsSecondaryIlluminators = false;
m_childClassMask = 0;
for (vector<TimelinePhase*>::iterator iter = children.begin();
iter != children.end(); iter++)
{
TimelinePhase* phase = *iter;
double bodyRadius = phase->body()->getRadius();
double r = phase->body()->getCullingRadius() + phase->orbit()->getBoundingRadius();
m_maxChildRadius = max(m_maxChildRadius, bodyRadius);
m_containsSecondaryIlluminators = m_containsSecondaryIlluminators || phase->body()->isSecondaryIlluminator();
m_childClassMask |= phase->body()->getClassification();
FrameTree* tree = phase->body()->getFrameTree();
if (tree != NULL)
{
tree->recomputeBoundingSphere();
r += tree->m_boundingSphereRadius;
m_maxChildRadius = max(m_maxChildRadius, tree->m_maxChildRadius);
m_containsSecondaryIlluminators = m_containsSecondaryIlluminators || tree->containsSecondaryIlluminators();
m_childClassMask |= tree->childClassMask();
}
m_boundingSphereRadius = max(m_boundingSphereRadius, r);
}
}
}
/*! Add a new phase to this tree.
*/
void
FrameTree::addChild(TimelinePhase* phase)
{
phase->addRef();
children.push_back(phase);
markChanged();
}
/*! Remove a phase from the tree. This method does nothing if the specified
* phase doesn't exist in the tree.
*/
void
FrameTree::removeChild(TimelinePhase* phase)
{
vector<TimelinePhase*>::iterator iter = find(children.begin(), children.end(), phase);
if (iter != children.end())
{
(*iter)->release();
children.erase(iter);
markChanged();
}
}
/*! Return the child at the specified index. */
TimelinePhase*
FrameTree::getChild(unsigned int n) const
{
return children[n];
}
/*! Get the number of immediate children of this tree. */
unsigned int
FrameTree::childCount() const
{
return children.size();
}

View File

@ -36,17 +36,17 @@ public:
return starParent;
}
ReferenceFrame* getDefaultReferenceFrame() const;
void addChild(TimelinePhase* phase);
void removeChild(TimelinePhase* phase);
TimelinePhase* getChild(unsigned int n) const;
unsigned int childCount() const;
void markChanged();
void markUpdated();
void recomputeBoundingSphere();
ReferenceFrame* getDefaultReferenceFrame() const;
void addChild(TimelinePhase* phase);
void removeChild(TimelinePhase* phase);
TimelinePhase* getChild(unsigned int n) const;
unsigned int childCount() const;
void markChanged();
void markUpdated();
void recomputeBoundingSphere();
bool isRoot() const
{
return bodyParent == NULL;
@ -72,6 +72,22 @@ public:
return m_maxChildRadius;
}
/*! Return whether any of the children of this frame
* are secondary illuminators.
*/
bool containsSecondaryIlluminators() const
{
return m_containsSecondaryIlluminators;
}
/*! Return a bitmask with the classifications of all children
* in this tree.
*/
int childClassMask() const
{
return m_childClassMask;
}
private:
Star* starParent;
Body* bodyParent;
@ -79,7 +95,9 @@ private:
double m_boundingSphereRadius;
double m_maxChildRadius;
bool m_containsSecondaryIlluminators;
bool m_changed;
int m_childClassMask;
ReferenceFrame* defaultFrame;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// render.h
//
// Copyright (C) 2001-2007, Celestia Development Team
// Copyright (C) 2001-2008, Celestia Development Team
// Contact: Chris Laurel <claurel@gmail.com>
//
// This program is free software; you can redistribute it and/or
@ -30,7 +30,7 @@ class ReferenceMark;
struct LightSource
{
Point3d position;
Vec3d position;
Color color;
float luminosity;
float radius;
@ -65,7 +65,16 @@ struct RenderListEntry
float appMag;
RenderableType renderableType;
bool isOpaque;
std::vector<LightSource>* lightSourceList;
//std::vector<LightSource>* lightSourceList;
};
struct SecondaryIlluminator
{
const Body* body;
Vec3d position_v; // viewer relative position
float radius; // radius in km
float reflectedIrradiance; // albedo times total irradiance from direct sources
};
@ -423,10 +432,22 @@ class Renderer
void renderCelestialSphere(const Observer& observer);
void buildRenderLists(const Point3d& astrocentricObserverPos,
const Frustum& viewFrustum,
const Vec3d& viewPlaneNormal,
const FrameTree* tree,
const Observer& observer,
double now,
std::vector<LightSource>* lightSourceList);
double now);
void buildOrbitLists(const Point3d& astrocentricObserverPos,
const Quatf& observerOrientation,
const Frustum& viewFrustum,
const FrameTree* tree,
double now);
void buildLabelLists(const Frustum& viewFrustum,
double now);
void addRenderListEntries(RenderListEntry& rle,
Body& body,
bool isLabeled);
void addStarOrbitToRenderList(const Star& star,
const Observer& observer,
double now);
@ -446,7 +467,6 @@ class Renderer
float appMag,
const Observer& observer,
const Quatf& cameraOrientation,
const vector<LightSource>& lightSources,
float, float);
void renderStar(const Star& star,
@ -466,7 +486,6 @@ class Renderer
void renderCometTail(const Body& body,
Point3f pos,
double now,
const vector<LightSource>& lightSources,
float discSizeInPixels);
void renderBodyAsParticle(Point3f center,
@ -585,6 +604,7 @@ class Renderer
int windowWidth;
int windowHeight;
float fov;
float cosViewConeAngle;
int screenDpi;
float corrFac;
float pixelSize;
@ -614,6 +634,7 @@ class Renderer
PointStarVertexBuffer* pointStarVertexBuffer;
PointStarVertexBuffer* glareVertexBuffer;
std::vector<RenderListEntry> renderList;
std::vector<SecondaryIlluminator> secondaryIlluminators;
std::vector<DepthBufferPartition> depthPartitions;
std::vector<Particle> glareParticles;
std::vector<Annotation> backgroundAnnotations;
@ -623,7 +644,7 @@ class Renderer
std::vector<EclipseShadow> eclipseShadows[MaxLights];
std::vector<const Star*> nearStars;
std::list<std::vector<LightSource>* > lightSourceLists;
std::vector<LightSource> lightSourceList;
double modelMatrix[16];
double projMatrix[16];

View File

@ -302,8 +302,8 @@ TimelinePhase* CreateTimelinePhase(Body* body,
{
// No orbit frame specified; use the default frame.
orbitFrame = defaultFrame;
orbitFrame->addRef();
}
orbitFrame->addRef();
// Get the body reference frame
ReferenceFrame* bodyFrame;
@ -321,8 +321,8 @@ TimelinePhase* CreateTimelinePhase(Body* body,
{
// No body frame specified; use the default frame.
bodyFrame = defaultFrame;
bodyFrame->addRef();
}
bodyFrame->addRef();
// Use planet units (AU for semimajor axis) if the center of the orbit
// reference frame is a star.
@ -350,13 +350,19 @@ TimelinePhase* CreateTimelinePhase(Body* body,
rotationModel = new ConstantOrientation(Quatd(1.0));
}
return TimelinePhase::CreateTimelinePhase(universe,
body,
beginning, ending,
*orbitFrame,
*orbit,
*bodyFrame,
*rotationModel);
TimelinePhase* phase = TimelinePhase::CreateTimelinePhase(universe,
body,
beginning, ending,
*orbitFrame,
*orbit,
*bodyFrame,
*rotationModel);
// Frame ownership transfered to phase; release local references
orbitFrame->release();
bodyFrame->release();
return phase;
}
@ -749,6 +755,14 @@ static Body* CreatePlanet(const string& name,
body->setVisibleAsPoint(false);
}
if (classification == Body::Invisible ||
classification == Body::SurfaceFeature ||
classification == Body::Component ||
classification == Body::Spacecraft)
{
body->setSecondaryIlluminator(false);
}
string infoURL;
if (planetData->getString("InfoURL", infoURL))
{