Compare commits

...

19 Commits

Author SHA1 Message Date
Chris Laurel 47a792e83c Integrated change #5189 to sensor-dev branch: Initialized cullingRadius member of Body class. Leaving it uninitialized meant that it could end up set to NaN, resulting in odd behavior. 2012-02-25 02:21:11 +00:00
Chris Laurel 07f2c2bf30 Fixed resource name generation for sensor geometry to ensure that the
name is always unique for a body.
2012-02-25 01:52:46 +00:00
Chris Laurel 7653e220ce Propagated leap second change to sensor-dev branch. 2012-02-11 17:05:16 +00:00
Chris Laurel 3d3e3372bc Improvements for sensor frusta:
- Disable back face culling
- Draw adjacent faces of rectangular frusta with different opacities
2011-05-04 07:24:31 +00:00
Chris Laurel 0cc013f1e8 sensor-dev branch: Fixed bug with model animations in non-GL2 path. Solves problem with sensor frustum geometry being drawn incorrectly. 2011-04-09 02:18:10 +00:00
Chris Laurel 4b0350b9e3 Added script command to set and query visibility of named geometry components.
Currently, just the sensor geometry exposes components.
2010-12-22 01:11:30 +00:00
Chris Laurel 7512d65311 Updated SensorGeometry so that frustum base color may be set separately in
in an SSC file.
2010-12-21 23:54:45 +00:00
Chris Laurel 3617dd6e94 Integrated change 5091 to sensor-dev branch: fix for crash on systems with
Intel GPUs.
2010-12-21 18:19:44 +00:00
Chris Laurel d2d7ab8181 Fixed calculation of sensor frustum angles. 2010-12-13 22:41:05 +00:00
Chris Laurel edbcec6ff8 Fixed clipping of large multidraw geometry at very close range. 2010-12-07 22:55:42 +00:00
Chris Laurel 0dabce8884 Fixed clipping bug with multidraw geometry. 2010-12-06 23:39:32 +00:00
Chris Laurel 6139ea9b4d Fixed occasional crash when viewing sensors at close range. 2010-12-03 19:40:35 +00:00
Chris Laurel b286ad7274 Introduced 'multidraw' geometry that can extend across multiple depth
intervals. This is currently used to prevent clipping of sensor geometry, but
is a more generally useful feature.
2010-12-03 02:07:08 +00:00
Chris Laurel bff08a31dc Added Shape parameter for Sensor geometry--options are elliptical and
rectangular. Switched to exponential arrangement of slices in sensor
frustum.
2010-12-02 08:24:07 +00:00
Chris Laurel 9d8a301551 Fixed rendering of sensor geometry:
- Account for geometry orientation in intersection calculation
- Draw sensor out to its range when it doesn't intersect the target body
2010-11-30 20:54:22 +00:00
Chris Laurel 9840a67473 Enabled grid and appearance attributes for sensor frusta. 2010-11-30 00:04:02 +00:00
Chris Laurel 9d35943b50 Improved rendering of sensor frusta. 2010-11-29 23:07:07 +00:00
Chris Laurel 3616bdf92d Implemented horizontal and vertical FOV properties for sensor frustum geometry. 2010-11-26 19:04:53 +00:00
Chris Laurel 56d3466bc1 Skeleton implementation of sensor geometry. Parsing of Sensor geometry in
ssc files, but code currently currently just draws a line.
2010-11-24 04:27:28 +00:00
10 changed files with 729 additions and 47 deletions

View File

@ -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
};

View File

@ -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)),

View File

@ -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_

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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_

View File

@ -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

View File

@ -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);