Compare commits
19 Commits
spacecruft
...
sensor-dev
Author | SHA1 | Date |
---|---|---|
Chris Laurel | 47a792e83c | |
Chris Laurel | 07f2c2bf30 | |
Chris Laurel | 7653e220ce | |
Chris Laurel | 3d3e3372bc | |
Chris Laurel | 0cc013f1e8 | |
Chris Laurel | 4b0350b9e3 | |
Chris Laurel | 7512d65311 | |
Chris Laurel | 3617dd6e94 | |
Chris Laurel | d2d7ab8181 | |
Chris Laurel | edbcec6ff8 | |
Chris Laurel | 0dabce8884 | |
Chris Laurel | 6139ea9b4d | |
Chris Laurel | b286ad7274 | |
Chris Laurel | bff08a31dc | |
Chris Laurel | 9d8a301551 | |
Chris Laurel | 9840a67473 | |
Chris Laurel | 9d35943b50 | |
Chris Laurel | 3616bdf92d | |
Chris Laurel | 56d3466bc1 |
|
@ -111,6 +111,7 @@ static const LeapSecondRecord LeapSeconds[] =
|
|||
{ 32, 2451179.5 }, // 1 Jan 1999
|
||||
{ 33, 2453736.5 }, // 1 Jan 2006
|
||||
{ 34, 2454832.5 }, // 1 Jan 2009
|
||||
{ 35, 2456109.5 }, // 1 Jan 2012
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ Body::Body(PlanetarySystem* _system, const string& _name) :
|
|||
mass(0.0f),
|
||||
albedo(0.5f),
|
||||
geometryOrientation(Quaternionf::Identity()),
|
||||
cullingRadius(0.0f),
|
||||
geometry(InvalidResource),
|
||||
geometryScale(1.0f),
|
||||
surface(Color(1.0f, 1.0f, 1.0f)),
|
||||
|
|
|
@ -53,6 +53,39 @@ public:
|
|||
virtual void loadTextures()
|
||||
{
|
||||
}
|
||||
|
||||
/*! Return true if the geometry can be drawn multiple times in
|
||||
* different depth ranges to avoid clipping and precision problems.
|
||||
* Drawing multiple times is expensive, so this method should only
|
||||
* return true for geometries that are simple and which need to
|
||||
* be drawn correctly when the camera is positioned very close
|
||||
* (relative to the size of the object.)
|
||||
*/
|
||||
virtual bool isMultidraw() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Set the visibility flag for the named component of this geometry.
|
||||
* Subclasses of Geometry should customize this method if they have
|
||||
* components with visibility that can be controlled independently.
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
virtual void setPartVisible(const std::string& partName, bool visible)
|
||||
{
|
||||
}
|
||||
|
||||
/** Check the visibility flag for the named component of this geometry.
|
||||
* Subclasses of Geometry should customize this method if they have
|
||||
* components with visibility that can be controlled independently.
|
||||
* The default implementation always returns false. Implementations
|
||||
* of isPartVisible by subclasses should also return false for
|
||||
* non-existent parts.
|
||||
*/
|
||||
virtual bool isPartVisible(const std::string& partName) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _CELENGINE_GEOMETRY_H_
|
||||
|
|
|
@ -123,6 +123,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
|||
mesh->getVertexCount() * vertexDesc.stride,
|
||||
mesh->getVertexData(),
|
||||
GL_STATIC_DRAW_ARB);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2848,6 +2848,7 @@ void Renderer::draw(const Observer& observer,
|
|||
// large enough to have discernible surface detail are also placed in
|
||||
// renderList.
|
||||
renderList.clear();
|
||||
multidrawRenderList.clear();
|
||||
orbitPathList.clear();
|
||||
lightSourceList.clear();
|
||||
secondaryIlluminators.clear();
|
||||
|
@ -3464,16 +3465,43 @@ void Renderer::draw(const Observer& observer,
|
|||
nearZ = -nearZ * (float) cos(degToRad(fov / 2)) *
|
||||
((float) windowHeight / maxSpan);
|
||||
#endif
|
||||
if (nearZ > -MinNearPlaneDistance)
|
||||
iter->nearZ = -max(MinNearPlaneDistance, radius / 2000.0f);
|
||||
// Handle multidraw items; these are placed into a separate list. Items in the multidraw
|
||||
// list may be drawn in multiple depth intervals.
|
||||
bool isMultidraw = false;
|
||||
if (iter->renderableType == RenderListEntry::RenderableBody && iter->body->getGeometry() != InvalidResource)
|
||||
{
|
||||
Geometry* geom = GetGeometryManager()->find(iter->body->getGeometry());
|
||||
if (geom && geom->isMultidraw())
|
||||
{
|
||||
isMultidraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMultidraw)
|
||||
{
|
||||
iter->nearZ = min(-MinNearPlaneDistance, nearZ);
|
||||
}
|
||||
else
|
||||
iter->nearZ = nearZ;
|
||||
{
|
||||
if (nearZ > -MinNearPlaneDistance)
|
||||
{
|
||||
iter->nearZ = -max(MinNearPlaneDistance, radius / 2000.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->nearZ = nearZ;
|
||||
}
|
||||
}
|
||||
|
||||
if (!convex)
|
||||
{
|
||||
iter->farZ = center.z() - radius;
|
||||
if (iter->farZ / iter->nearZ > MaxFarNearRatio * 0.5f)
|
||||
iter->nearZ = iter->farZ / (MaxFarNearRatio * 0.5f);
|
||||
|
||||
if (!isMultidraw)
|
||||
{
|
||||
if (iter->farZ / iter->nearZ > MaxFarNearRatio * 0.5f)
|
||||
iter->nearZ = iter->farZ / (MaxFarNearRatio * 0.5f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3509,8 +3537,15 @@ void Renderer::draw(const Observer& observer,
|
|||
}
|
||||
}
|
||||
|
||||
*notCulled = *iter;
|
||||
notCulled++;
|
||||
if (isMultidraw)
|
||||
{
|
||||
multidrawRenderList.push_back(*iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
*notCulled = *iter;
|
||||
notCulled++;
|
||||
}
|
||||
#ifdef USE_HDR
|
||||
if (iter->discSizeInPixels > 1.0f &&
|
||||
iter->appMag < starMaxMag)
|
||||
|
@ -3601,6 +3636,14 @@ void Renderer::draw(const Observer& observer,
|
|||
// overlapping objects. If two objects overlap in depth, we must
|
||||
// assign them to the same interval.
|
||||
|
||||
// The code here is more complicated than it should be because there are
|
||||
// three separate sources for renderable objects:
|
||||
// - the main render list (renderList)
|
||||
// - the list of multidraw items (multidrawRenderList)
|
||||
// - the list of orbits
|
||||
// It would be good reduce the complexity by merging the orbit list into
|
||||
// the multidraw list, but this would require significant refactoring of
|
||||
// the renderer code.
|
||||
depthPartitions.clear();
|
||||
int nIntervals = 0;
|
||||
float prevNear = -1e12f; // ~ 1 light year
|
||||
|
@ -3665,7 +3708,21 @@ void Renderer::draw(const Observer& observer,
|
|||
if (minNearDistance > zNearest)
|
||||
zNearest = minNearDistance;
|
||||
}
|
||||
|
||||
|
||||
// Scan the list of multidraw items and find the closest one. We'll need
|
||||
// adjust the nearest interval to accommodate it.
|
||||
float zFurthest = 0.0;
|
||||
for (i = 0; i < (int) multidrawRenderList.size(); i++)
|
||||
{
|
||||
const RenderListEntry& rle = multidrawRenderList[i];
|
||||
float minNearDistance = min(-MinNearPlaneDistance, rle.nearZ);
|
||||
|
||||
if (minNearDistance > zNearest)
|
||||
zNearest = minNearDistance;
|
||||
if (rle.farZ < zFurthest)
|
||||
zFurthest = rle.farZ;
|
||||
}
|
||||
|
||||
// Adjust the nearest interval to include the closest marker (if it's
|
||||
// closer to the observer than anything else
|
||||
if (!depthSortedAnnotations.empty())
|
||||
|
@ -3689,8 +3746,10 @@ void Renderer::draw(const Observer& observer,
|
|||
if (zNearest == prevNear)
|
||||
zNearest = 0.0f;
|
||||
|
||||
// Add one last interval for the span from 0 to the front of the
|
||||
// nearest object
|
||||
// Add intervals for the span from 0 to the front of the
|
||||
// nearest object. Keep the far/near ratios of the intervals
|
||||
// reasonable so that we don't end up with depth buffer precision
|
||||
// problems when rendering multidraw items.
|
||||
{
|
||||
// TODO: closest object may not be at entry 0, since objects are
|
||||
// sorted by far distance.
|
||||
|
@ -3707,17 +3766,30 @@ void Renderer::draw(const Observer& observer,
|
|||
closest = renderList[0].nearZ * 0.01f;
|
||||
}
|
||||
}
|
||||
closest = min(closest, -MinNearPlaneDistance);
|
||||
|
||||
DepthBufferPartition partition;
|
||||
partition.index = nIntervals;
|
||||
partition.nearZ = closest;
|
||||
partition.farZ = prevNear;
|
||||
depthPartitions.push_back(partition);
|
||||
while (prevNear < closest)
|
||||
{
|
||||
float n = std::min(closest, prevNear / 2000.0f);
|
||||
|
||||
nIntervals++;
|
||||
// Prevent the creation of extremely small depth intervals
|
||||
if (-n / MinNearPlaneDistance < 1.1f)
|
||||
{
|
||||
n = -MinNearPlaneDistance;
|
||||
}
|
||||
|
||||
DepthBufferPartition partition;
|
||||
partition.index = nIntervals;
|
||||
partition.nearZ = n;
|
||||
partition.farZ = prevNear;
|
||||
depthPartitions.push_back(partition);
|
||||
nIntervals++;
|
||||
|
||||
prevNear = n;
|
||||
}
|
||||
}
|
||||
|
||||
// If orbits are enabled, adjust the farthest partition so that it
|
||||
// If orbits are enabled, adjust the farthest interval so that it
|
||||
// can contain the orbit.
|
||||
if (!orbitPathList.empty())
|
||||
{
|
||||
|
@ -3726,6 +3798,13 @@ void Renderer::draw(const Observer& observer,
|
|||
orbitPathList[orbitPathList.size() - 1].radius);
|
||||
}
|
||||
|
||||
// Extend the farthest depth interval to include all multidraw items.
|
||||
if (!multidrawRenderList.empty())
|
||||
{
|
||||
depthPartitions[0].farZ = min(depthPartitions[0].farZ, zFurthest);
|
||||
}
|
||||
|
||||
|
||||
// We want to avoid overpartitioning the depth buffer. In this stage, we coalesce
|
||||
// partitions that have small spans in the depth buffer.
|
||||
// TODO: Implement this step!
|
||||
|
@ -3816,6 +3895,16 @@ void Renderer::draw(const Observer& observer,
|
|||
i--;
|
||||
}
|
||||
|
||||
// Render all multidraw items
|
||||
for (unsigned int j = 0; j < multidrawRenderList.size(); ++j)
|
||||
{
|
||||
const RenderListEntry& rle = multidrawRenderList[j];
|
||||
if (rle.discSizeInPixels > 1.0f && rle.farZ < depthPartitions[interval].nearZ && rle.nearZ > depthPartitions[interval].farZ)
|
||||
{
|
||||
renderItem(rle, observer, m_cameraOrientation, nearPlaneDistance, farPlaneDistance);
|
||||
}
|
||||
}
|
||||
|
||||
// Render orbit paths
|
||||
if (!orbitPathList.empty())
|
||||
{
|
||||
|
@ -5014,7 +5103,8 @@ static void setLightParameters_VP(VertexProcessor& vproc,
|
|||
static void renderModelDefault(Geometry* geometry,
|
||||
const RenderInfo& ri,
|
||||
bool lit,
|
||||
ResourceHandle texOverride)
|
||||
ResourceHandle texOverride,
|
||||
double tsec)
|
||||
{
|
||||
FixedFunctionRenderContext rc;
|
||||
Material m;
|
||||
|
@ -5046,7 +5136,7 @@ static void renderModelDefault(Geometry* geometry,
|
|||
rc.lock();
|
||||
}
|
||||
|
||||
geometry->render(rc);
|
||||
geometry->render(rc, tsec);
|
||||
if (geometry->usesTextureType(Material::EmissiveMap))
|
||||
{
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -5056,7 +5146,7 @@ static void renderModelDefault(Geometry* geometry,
|
|||
rc.setRenderPass(RenderContext::EmissivePass);
|
||||
rc.setMaterial(NULL);
|
||||
|
||||
geometry->render(rc);
|
||||
geometry->render(rc, tsec);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
}
|
||||
|
@ -7140,7 +7230,7 @@ void Renderer::renderObject(const Vector3f& pos,
|
|||
}
|
||||
else
|
||||
{
|
||||
renderModelDefault(geometry, ri, lit, texOverride);
|
||||
renderModelDefault(geometry, ri, lit, texOverride, astro::daysToSecs(now - astro::J2000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -653,6 +653,7 @@ class Renderer
|
|||
PointStarVertexBuffer* pointStarVertexBuffer;
|
||||
PointStarVertexBuffer* glareVertexBuffer;
|
||||
std::vector<RenderListEntry> renderList;
|
||||
std::vector<RenderListEntry> multidrawRenderList;
|
||||
std::vector<SecondaryIlluminator> secondaryIlluminators;
|
||||
std::vector<DepthBufferPartition> depthPartitions;
|
||||
std::vector<Particle> glareParticles;
|
||||
|
@ -683,32 +684,6 @@ class Renderer
|
|||
|
||||
int currentIntervalIndex;
|
||||
|
||||
|
||||
public:
|
||||
#if 0
|
||||
struct OrbitSample
|
||||
{
|
||||
double t;
|
||||
Point3d pos;
|
||||
|
||||
OrbitSample(const Eigen::Vector3d& _pos, double _t) : t(_t), pos(_pos.x(), _pos.y(), _pos.z()) { }
|
||||
OrbitSample() { }
|
||||
};
|
||||
|
||||
struct OrbitSection
|
||||
{
|
||||
Capsuled boundingVolume;
|
||||
uint32 firstSample;
|
||||
};
|
||||
|
||||
struct CachedOrbit
|
||||
{
|
||||
std::vector<OrbitSample> trajectory;
|
||||
std::vector<OrbitSection> sections;
|
||||
uint32 lastUsed;
|
||||
};
|
||||
#endif
|
||||
|
||||
private:
|
||||
typedef std::map<const Orbit*, CurvePlot*> OrbitCache;
|
||||
OrbitCache orbitCache;
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
// sensorgeometry.cpp
|
||||
//
|
||||
// Copyright (C) 2010, Celestia Development Team
|
||||
// Original version by Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#include "sensorgeometry.h"
|
||||
#include "rendcontext.h"
|
||||
#include "texmanager.h"
|
||||
#include "astro.h"
|
||||
#include "body.h"
|
||||
#include "vecgl.h"
|
||||
#include "celmath/mathlib.h"
|
||||
#include "celmath/intersect.h"
|
||||
#include <Eigen/Core>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
||||
|
||||
SensorGeometry::SensorGeometry() :
|
||||
m_observer(NULL),
|
||||
m_target(NULL),
|
||||
m_range(0.0),
|
||||
m_horizontalFov(degToRad(5.0)),
|
||||
m_verticalFov(degToRad(5.0)),
|
||||
m_frustumColor(1.0f, 1.0f, 1.0f),
|
||||
m_frustumBaseColor(1.0f, 1.0f, 1.0f),
|
||||
m_frustumOpacity(0.25f),
|
||||
m_gridOpacity(1.0f),
|
||||
m_shape(EllipticalShape),
|
||||
m_frustumVisible(true),
|
||||
m_frustumBaseVisible(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SensorGeometry::~SensorGeometry()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SensorGeometry::pick(const Ray3d& /* r */, double& /* distance */) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SensorGeometry::setFOVs(double horizontalFov, double verticalFov)
|
||||
{
|
||||
m_horizontalFov = horizontalFov;
|
||||
m_verticalFov = verticalFov;
|
||||
}
|
||||
|
||||
|
||||
/** Render the sensor geometry.
|
||||
*/
|
||||
void
|
||||
SensorGeometry::render(RenderContext& rc, double tsec)
|
||||
{
|
||||
if (m_target == NULL || m_observer == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double jd = astro::secsToDays(tsec) + astro::J2000;
|
||||
|
||||
UniversalCoord obsPos = m_observer->getPosition(jd);
|
||||
UniversalCoord targetPos = m_target->getPosition(jd);
|
||||
|
||||
Vector3d pos = targetPos.offsetFromKm(obsPos);
|
||||
|
||||
Quaterniond q = m_observer->getOrientation(jd);
|
||||
|
||||
const unsigned int sectionCount = 40; // Must be a multiple of 4
|
||||
const unsigned int sliceCount = 10;
|
||||
Vector3d profile[sectionCount];
|
||||
Vector3d footprint[sectionCount];
|
||||
|
||||
Quaterniond obsOrientation = m_observer->getOrientation(jd).conjugate() * m_observer->getGeometryOrientation().cast<double>().conjugate();
|
||||
Quaterniond targetOrientation = m_target->getOrientation(jd).conjugate();
|
||||
Vector3d origin = targetOrientation.conjugate() * -pos;
|
||||
Ellipsoidd targetEllipsoid(m_target->getSemiAxes().cast<double>());
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// 'Undo' the rotation of the parent body. We are assuming that the observer is
|
||||
// the body to which the sensor geometry is attached.
|
||||
glRotate(obsOrientation.conjugate());
|
||||
|
||||
Matrix3d obsRotation = obsOrientation.toRotationMatrix();
|
||||
|
||||
double horizontalSize = tan(m_horizontalFov);
|
||||
double verticalSize = tan(m_verticalFov);
|
||||
|
||||
// Compute the profile of the frustum; the profile is extruded over the range
|
||||
// of the sensor (or to the intersection) when rendering.
|
||||
if (m_shape == EllipticalShape)
|
||||
{
|
||||
for (unsigned int i = 0; i < sectionCount; ++i)
|
||||
{
|
||||
double t = double(i) / double(sectionCount);
|
||||
double theta = t * PI * 2.0;
|
||||
|
||||
// Note: -sin() is used here to reverse the vertex order so that the _outside_
|
||||
// of the frustum is drawn.
|
||||
profile[i] = obsRotation * Vector3d(cos(theta) * horizontalSize, -sin(theta) * verticalSize, 1.0).normalized();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < sectionCount; ++i)
|
||||
{
|
||||
double t = double(i) / double(sectionCount);
|
||||
double theta = t * PI * 2.0;
|
||||
|
||||
double u = double((i + sectionCount / 8) % (sectionCount / 4)) / double(sectionCount / 4);
|
||||
double phi = (u - 0.5) * PI / 2;
|
||||
|
||||
// Note: -sin() is used here to reverse the vertex order so that the _outside_
|
||||
// of the frustum is drawn.
|
||||
double l = 1.0 / cos(phi);
|
||||
profile[i] = obsRotation * Vector3d(cos(theta) * horizontalSize * l, -sin(theta) * verticalSize * l, 1.0).normalized();
|
||||
}
|
||||
}
|
||||
|
||||
// Set to true if alternate sides of the frustum should be drawn with different
|
||||
// opacities.
|
||||
bool alternateShading = m_shape == RectangularShape;
|
||||
|
||||
// Compute the 'footprint' of the sensor by finding the intersection of all rays with
|
||||
// the target body. The rendering will not be correct unless the sensor frustum
|
||||
for (unsigned int i = 0; i < sectionCount; ++i)
|
||||
{
|
||||
Vector3d direction = profile[i];
|
||||
Vector3d testDirection = targetOrientation.conjugate() * direction;
|
||||
|
||||
// Draw the sensor frustum out to either the range or the point of
|
||||
// intersection with the target body--whichever is closer.
|
||||
double distance = 0.0;
|
||||
if (testIntersection(Ray3d(origin, testDirection), targetEllipsoid, distance))
|
||||
{
|
||||
distance = std::min(distance, m_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = m_range;
|
||||
}
|
||||
|
||||
footprint[i] = distance * direction;
|
||||
}
|
||||
|
||||
if (alternateShading)
|
||||
{
|
||||
glShadeModel(GL_FLAT);
|
||||
}
|
||||
|
||||
// Draw the frustum
|
||||
if (m_frustumVisible)
|
||||
{
|
||||
unsigned int sectionsPerRectSide = sectionCount / 4;
|
||||
|
||||
glColor4f(m_frustumColor.red(), m_frustumColor.green(), m_frustumColor.blue(), m_frustumOpacity);
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3d(0.0, 0.0, 0.0);
|
||||
for (unsigned int i = 0; i <= sectionCount; ++i)
|
||||
{
|
||||
if (alternateShading)
|
||||
{
|
||||
// Use different opacities for adjacent faces of rectangular frusta; this
|
||||
// makes the geometry easier to understand visually.
|
||||
float alpha = m_frustumOpacity;
|
||||
if (((i + sectionsPerRectSide / 2 - 1) / sectionsPerRectSide) % 2 == 1)
|
||||
{
|
||||
alpha *= 0.5f;
|
||||
}
|
||||
glColor4f(m_frustumColor.red(), m_frustumColor.green(), m_frustumColor.blue(), alpha);
|
||||
}
|
||||
glVertex3dv(footprint[i % sectionCount].data());
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if (alternateShading)
|
||||
{
|
||||
glShadeModel(GL_SMOOTH);
|
||||
}
|
||||
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
// Draw the footprint outline
|
||||
if (m_frustumBaseVisible)
|
||||
{
|
||||
glColor4f(m_frustumBaseColor.red(), m_frustumBaseColor.green(), m_frustumBaseColor.blue(), m_gridOpacity);
|
||||
glLineWidth(2.0f);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (unsigned int i = 0; i < sectionCount; ++i)
|
||||
{
|
||||
glVertex3dv(footprint[i].data());
|
||||
}
|
||||
glEnd();
|
||||
glLineWidth(1.0f);
|
||||
}
|
||||
|
||||
if (m_frustumVisible)
|
||||
{
|
||||
glColor4f(m_frustumColor.red(), m_frustumColor.green(), m_frustumColor.blue(), m_frustumOpacity);
|
||||
for (unsigned int slice = 1; slice < sliceCount; ++slice)
|
||||
{
|
||||
// Linear arrangement of slices
|
||||
//double t = double(slice) / double(sliceCount);
|
||||
|
||||
// Exponential arrangement looks better
|
||||
double t = pow(2.0, -double(slice));
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (unsigned int i = 0; i < sectionCount; ++i)
|
||||
{
|
||||
Vector3d v = footprint[i] * t;
|
||||
glVertex3dv(v.data());
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// NOTE: section count should be evenly divisible by 8
|
||||
glBegin(GL_LINES);
|
||||
if (m_shape == EllipticalShape)
|
||||
{
|
||||
unsigned int rayCount = 8;
|
||||
unsigned int step = sectionCount / rayCount;
|
||||
for (unsigned int i = 0; i < sectionCount; i += step)
|
||||
{
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3dv(footprint[i].data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int step = sectionCount / 4;
|
||||
for (unsigned int i = sectionCount / 8; i < sectionCount; i += step)
|
||||
{
|
||||
glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex3dv(footprint[i].data());
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SensorGeometry::isOpaque() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SensorGeometry::isNormalized() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SensorGeometry::setPartVisible(const std::string& partName, bool visible)
|
||||
{
|
||||
std::clog << "setPartVisible: " << partName << std::endl;
|
||||
if (partName == "Frustum")
|
||||
{
|
||||
m_frustumVisible = visible;
|
||||
}
|
||||
else if (partName == "FrustumBase")
|
||||
{
|
||||
m_frustumBaseVisible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SensorGeometry::isPartVisible(const std::string& partName) const
|
||||
{
|
||||
if (partName == "Frustum")
|
||||
{
|
||||
return m_frustumVisible;
|
||||
}
|
||||
else if (partName == "FrustumBase")
|
||||
{
|
||||
return m_frustumBaseVisible;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// sensorgeometry.h
|
||||
//
|
||||
// Copyright (C) 2010, Celestia Development Team
|
||||
// Original version by Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#ifndef _CELENGINE_SENSOR_GEOMETRY_H_
|
||||
#define _CELENGINE_SENSOR_GEOMETRY_H_
|
||||
|
||||
#include "geometry.h"
|
||||
#include <celutil/color.h>
|
||||
#include <celutil/resmanager.h>
|
||||
|
||||
class Body;
|
||||
|
||||
class SensorGeometry : public Geometry
|
||||
{
|
||||
public:
|
||||
SensorGeometry();
|
||||
~SensorGeometry();
|
||||
|
||||
enum SensorShape
|
||||
{
|
||||
EllipticalShape,
|
||||
RectangularShape,
|
||||
};
|
||||
|
||||
virtual bool pick(const Ray3d& r, double& distance) const;
|
||||
|
||||
//! Render the model in the current OpenGL context
|
||||
virtual void render(RenderContext&, double t = 0.0);
|
||||
|
||||
virtual bool isOpaque() const;
|
||||
virtual bool isNormalized() const;
|
||||
|
||||
virtual bool isMultidraw() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void setPartVisible(const std::string& partName, bool visible);
|
||||
virtual bool isPartVisible(const std::string& partName) const;
|
||||
|
||||
Body* observer() const
|
||||
{
|
||||
return m_observer;
|
||||
}
|
||||
|
||||
void setObserver(Body* observer)
|
||||
{
|
||||
m_observer = observer;
|
||||
}
|
||||
|
||||
Body* target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
void setTarget(Body* target)
|
||||
{
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
double range() const
|
||||
{
|
||||
return m_range;
|
||||
}
|
||||
|
||||
void setRange(double range)
|
||||
{
|
||||
m_range = range;
|
||||
}
|
||||
|
||||
SensorShape shape() const
|
||||
{
|
||||
return m_shape;
|
||||
}
|
||||
|
||||
void setShape(SensorShape shape)
|
||||
{
|
||||
m_shape = shape;
|
||||
}
|
||||
|
||||
Color frustumColor() const
|
||||
{
|
||||
return m_frustumColor;
|
||||
}
|
||||
|
||||
void setFrustumColor(const Color& color)
|
||||
{
|
||||
m_frustumColor = color;
|
||||
}
|
||||
|
||||
Color frustumBaseColor() const
|
||||
{
|
||||
return m_frustumBaseColor;
|
||||
}
|
||||
|
||||
void setFrustumBaseColor(const Color& color)
|
||||
{
|
||||
m_frustumBaseColor = color;
|
||||
}
|
||||
|
||||
float frustumOpacity() const
|
||||
{
|
||||
return m_frustumOpacity;
|
||||
}
|
||||
|
||||
void setFrustumOpacity(float opacity)
|
||||
{
|
||||
m_frustumOpacity = opacity;
|
||||
}
|
||||
|
||||
float gridOpacity() const
|
||||
{
|
||||
return m_gridOpacity;
|
||||
}
|
||||
|
||||
void setGridOpacity(float opacity)
|
||||
{
|
||||
m_gridOpacity = opacity;
|
||||
}
|
||||
|
||||
void setFOVs(double horizontalFov, double verticalFov);
|
||||
|
||||
|
||||
private:
|
||||
Body* m_observer;
|
||||
Body* m_target;
|
||||
double m_range;
|
||||
double m_horizontalFov;
|
||||
double m_verticalFov;
|
||||
Color m_frustumColor;
|
||||
Color m_frustumBaseColor;
|
||||
float m_frustumOpacity;
|
||||
float m_gridOpacity;
|
||||
SensorShape m_shape;
|
||||
bool m_frustumVisible;
|
||||
bool m_frustumBaseVisible;
|
||||
};
|
||||
|
||||
#endif // !_CELENGINE_SENSOR_GEOMETRY_H_
|
|
@ -29,6 +29,7 @@
|
|||
#include "parser.h"
|
||||
#include "texmanager.h"
|
||||
#include "meshmanager.h"
|
||||
#include "sensorgeometry.h"
|
||||
#include "universe.h"
|
||||
#include "multitexture.h"
|
||||
#include "parseobject.h"
|
||||
|
@ -894,6 +895,72 @@ static Body* CreateBody(const string& name,
|
|||
body->setGeometry(geometryHandle);
|
||||
body->setGeometryScale(geometryScale);
|
||||
}
|
||||
else if (planetData->getValue("Sensor"))
|
||||
{
|
||||
Hash* sensorData = planetData->getValue("Sensor")->getHash();
|
||||
if (sensorData)
|
||||
{
|
||||
SensorGeometry* sensor = new SensorGeometry();
|
||||
sensor->setObserver(body);
|
||||
|
||||
string targetName;
|
||||
if (sensorData->getString("Target", targetName))
|
||||
{
|
||||
Body* target = universe.findPath(targetName).body();
|
||||
if (target)
|
||||
{
|
||||
sensor->setTarget(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Can't find target for sensor.\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "No target specified for sensor.\n";
|
||||
}
|
||||
|
||||
double range = 1.0;
|
||||
sensorData->getNumber("Range", range);
|
||||
sensor->setRange(range);
|
||||
|
||||
double horizontalFov = 5.0;
|
||||
double verticalFov = 5.0;
|
||||
sensorData->getNumber("HorizontalFOV", horizontalFov);
|
||||
sensorData->getNumber("VerticalFOV", verticalFov);
|
||||
sensor->setFOVs(degToRad(horizontalFov), degToRad(verticalFov));
|
||||
|
||||
// Appearance attributes
|
||||
Color frustumColor(1.0f, 1.0f, 1.0f);
|
||||
Color frustumBaseColor(1.0f, 1.0f, 1.0f);
|
||||
float frustumOpacity = 0.25f;
|
||||
float gridOpacity = 1.0f;
|
||||
sensorData->getColor("FrustumColor", frustumColor);
|
||||
sensorData->getColor("FrustumBaseColor", frustumBaseColor);
|
||||
sensorData->getNumber("FrustumOpacity", frustumOpacity);
|
||||
sensorData->getNumber("GridOpacity", gridOpacity);
|
||||
sensor->setFrustumColor(frustumColor);
|
||||
sensor->setFrustumBaseColor(frustumBaseColor);
|
||||
sensor->setFrustumOpacity(frustumOpacity);
|
||||
sensor->setGridOpacity(gridOpacity);
|
||||
|
||||
string shape = "elliptical";
|
||||
sensorData->getString("Shape", shape);
|
||||
if (compareIgnoringCase(shape, "rectangular") == 0)
|
||||
{
|
||||
sensor->setShape(SensorGeometry::RectangularShape);
|
||||
}
|
||||
|
||||
string resName = string("sensor") + targetName + Selection(body).getName();
|
||||
GeometryInfo info(resName, path, Vector3f::Zero(), 1.0f, false);
|
||||
info.resource = sensor;
|
||||
info.state = ResourceLoaded;
|
||||
ResourceHandle geometryHandle = GetGeometryManager()->getHandle(info);
|
||||
body->setGeometry(geometryHandle);
|
||||
body->setGeometryScale(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read the atmosphere
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <celengine/axisarrow.h>
|
||||
#include <celengine/visibleregion.h>
|
||||
#include <celengine/planetgrid.h>
|
||||
#include <celengine/meshmanager.h>
|
||||
#include "celestiacore.h"
|
||||
|
||||
using namespace Eigen;
|
||||
|
@ -131,6 +132,56 @@ static int object_setvisible(lua_State* l)
|
|||
}
|
||||
|
||||
|
||||
// Check the visibility flag for an object component; returns false if the object doesn't
|
||||
// have a component with the specified name
|
||||
static int object_partvisible(lua_State* l)
|
||||
{
|
||||
CelxLua celx(l);
|
||||
celx.checkArgs(2, 2, "One argument expected to object:setpartvisible()");
|
||||
|
||||
Selection* sel = this_object(l);
|
||||
string partName = celx.safeGetString(2, AllErrors, "Argument of object:setpartvisible() must be a string");
|
||||
|
||||
bool visible = false;
|
||||
|
||||
if (sel->body() != NULL && sel->body()->getGeometry() != InvalidResource)
|
||||
{
|
||||
Geometry* geom = GetGeometryManager()->find(sel->body()->getGeometry());
|
||||
if (geom)
|
||||
{
|
||||
visible = geom->isPartVisible(partName);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushboolean(l, visible ? 1 : 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Set the visibility flag for an object component; has no effect if the object doesn't
|
||||
// have any defined components.
|
||||
static int object_setpartvisible(lua_State* l)
|
||||
{
|
||||
CelxLua celx(l);
|
||||
celx.checkArgs(3, 3, "Two argument expected to object:setpartvisible()");
|
||||
|
||||
Selection* sel = this_object(l);
|
||||
string partName = celx.safeGetString(2, AllErrors, "Argument 1 of object:setpartvisible() must be a string");
|
||||
|
||||
bool visible = celx.safeGetBoolean(3, AllErrors, "Argument 2 of object:setpartvisible() must be a boolean");
|
||||
if (sel->body() != NULL && sel->body()->getGeometry() != InvalidResource)
|
||||
{
|
||||
Geometry* geom = GetGeometryManager()->find(sel->body()->getGeometry());
|
||||
if (geom)
|
||||
{
|
||||
geom->setPartVisible(partName, visible);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int object_setorbitcolor(lua_State* l)
|
||||
{
|
||||
CelxLua celx(l);
|
||||
|
@ -1306,6 +1357,8 @@ void CreateObjectMetaTable(lua_State* l)
|
|||
celx.registerMethod("__tostring", object_tostring);
|
||||
celx.registerMethod("visible", object_visible);
|
||||
celx.registerMethod("setvisible", object_setvisible);
|
||||
celx.registerMethod("partvisible", object_partvisible);
|
||||
celx.registerMethod("setpartvisible", object_setpartvisible);
|
||||
celx.registerMethod("orbitcoloroverridden", object_orbitcoloroverridden);
|
||||
celx.registerMethod("setorbitcoloroverridden", object_setorbitcoloroverridden);
|
||||
celx.registerMethod("setorbitcolor", object_setorbitcolor);
|
||||
|
|
Loading…
Reference in New Issue