Planets shape creation & fixed texture longitude

Instead of spheres, the planets are now created as triaxial ellipsoids
according to the corresponding radii values in the SPICE kernels (if such
values are available). Apart from being more scientifically accurate, the
planets are shaped as the intersection functions in SPICE expects.

The textures will now also be aligned in longitude as in reality (w.r.t.
UTC) when using a texture map ranging from -180 in the left end to +180 on the
right, with 0 longitude in the middle (such as Greenwich in Earth texture)
This commit is contained in:
Anton Arbring
2015-03-20 19:59:26 -04:00
parent 221db02af6
commit b79e6df763
13 changed files with 215 additions and 55 deletions

View File

@@ -66,6 +66,7 @@ private:
ghoul::opengl::Texture* _texture;
planetgeometry::PlanetGeometry* _geometry;
properties::BoolProperty _performShading;
properties::IntProperty _rotation;
glm::dmat3 _stateMatrix;

View File

@@ -74,6 +74,7 @@ private:
properties::StringProperty _colorTexturePath;
properties::StringProperty _projectionTexturePath;
properties::TriggerProperty _imageTrigger;
properties::IntProperty _rotation;
ghoul::opengl::ProgramObject* _programObject;
ghoul::opengl::ProgramObject* _fboProgramObject;

View File

@@ -50,8 +50,10 @@ public:
private:
void createSphere();
properties::Vec2Property _radius;
glm::vec2 _modRadius;
properties::Vec4Property _realRadius;
properties::IntProperty _segments;
std::string _name;
PowerScaledSphere* _sphere;
};

View File

@@ -49,9 +49,10 @@ public:
private:
void createSphere();
properties::Vec2Property _radius;
glm::vec2 _modRadius;
properties::Vec4Property _realRadius;
properties::IntProperty _segments;
std::string _name;
properties::IntProperty _vaoID;
properties::IntProperty _vBufferID;

View File

@@ -29,6 +29,7 @@
#include <ghoul/opengl/ghoul_gl.h>
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/powerscaledscalar.h>
#include <openspace/properties/vectorproperty.h>
namespace openspace {
@@ -37,6 +38,9 @@ public:
// initializers
PowerScaledSphere(const PowerScaledScalar& radius,
int segments = 8);
PowerScaledSphere(properties::Vec4Property &radius,
int segments, std::string planetName);
~PowerScaledSphere();
PowerScaledSphere(const PowerScaledSphere& cpy);

View File

@@ -648,6 +648,19 @@ public:
*/
static bool checkForError(std::string errorMessage);
/**
* This method uses the SPICE kernels to get the radii of bodies defined as a
* triaxial ellipsoid. The benefit of this is to be able to create more accurate
* planet shapes, which is desirable when projecting images with SPICE intersection
* methods
* \param planetName - the name of the body, should be recognizable by SPICE
* \param a - equatorial radius 1
* \param b - equatorial radius 2
* \param c - polar radius
* \return <code>true</code> if SPICE reports no errors
*/
bool getPlanetEllipsoid(std::string planetName, float &a, float &b, float &c);
private:
struct KernelInformation {
std::string path; /// The path from which the kernel was loaded

View File

@@ -28,7 +28,7 @@ uniform sampler2D texture1;
uniform mat4 ProjectorMatrix;
uniform mat4 ModelTransform;
uniform vec2 _scaling;
uniform vec2 radius;
uniform vec4 radius;
flat in uint vs_segments;
in vec4 vs_position;
@@ -38,7 +38,7 @@ out vec4 color;
#define M_PI 3.14159265358979323846
vec4 uvToModel( float u, float v, vec2 radius, float segments){
vec4 uvToModel( float u, float v, vec4 radius, float segments){
const float fj = u * segments;
const float fi = v * segments;
@@ -46,10 +46,10 @@ vec4 uvToModel( float u, float v, vec2 radius, float segments){
const float phi = fj * float(M_PI) * 2.0f / segments;
const float x = radius[0] * sin(phi) * sin(theta); //
const float y = radius[0] * cos(theta); // up
const float z = radius[0] * cos(phi) * sin(theta); //
const float y = radius[1] * cos(theta); // up
const float z = radius[2] * cos(phi) * sin(theta); //
return vec4(x, y, z, radius[1]);
return vec4(x, y, z, radius[3]);
}
#include "PowerScaling/powerScaling_vs.hglsl"

View File

@@ -60,6 +60,7 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary)
, _texture(nullptr)
, _geometry(nullptr)
, _performShading("performShading", "Perform Shading", true)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
std::string name;
bool success = dictionary.getValue(constants::scenegraphnode::keyName, name);
@@ -104,6 +105,8 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary)
}
addProperty(_performShading);
// Mainly for debugging purposes @AA
addProperty(_rotation);
}
RenderablePlanet::~RenderablePlanet() {
@@ -150,17 +153,15 @@ void RenderablePlanet::render(const RenderData& data)
//earth needs to be rotated for that to work.
glm::mat4 rot = glm::rotate(transform, 90.f, glm::vec3(1, 0, 0));
glm::mat4 roty = glm::rotate(transform, 90.f, glm::vec3(0, -1, 0));
glm::mat4 rotProp = glm::rotate(transform, static_cast<float>(_rotation), glm::vec3(0, 1, 0));
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
transform[i][j] = static_cast<float>(_stateMatrix[i][j]);
}
}
transform = transform* rot;
if (_frame == "IAU_JUPITER"){ //x = 0.935126
transform *= glm::scale(glm::mat4(1), glm::vec3(1, 0.93513, 1));
}
transform = transform * rot * roty * rotProp;
//glm::mat4 modelview = data.camera.viewMatrix()*data.camera.modelMatrix();
//glm::vec3 camSpaceEye = (-(modelview*data.position.vec4())).xyz;

View File

@@ -84,6 +84,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
, _texture(nullptr)
, _textureProj(nullptr)
, _geometry(nullptr)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
std::string name;
bool success = dictionary.getValue(constants::scenegraphnode::keyName, name);
@@ -149,7 +150,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary&
_projectionTexturePath = path + "/" + texturePath;
}
addPropertySubOwner(_geometry);
addProperty(_rotation);
addProperty(_imageTrigger);
_imageTrigger.onChange(std::bind(&RenderablePlanetProjection::loadTexture, this));
@@ -287,8 +288,8 @@ void RenderablePlanetProjection::imageProjectGPU(){
if (_geometry->hasProperty("radius")){
boost::any r = _geometry->property("radius")->get();
if (glm::vec2* radius = boost::any_cast<glm::vec2>(&r)){
_fboProgramObject->setUniform("radius", radius[0]);
if (glm::vec4* radius = boost::any_cast<glm::vec4>(&r)){
_fboProgramObject->setUniform("radius", radius);
}
}else{
LERROR("Geometry object needs to provide radius");
@@ -345,15 +346,16 @@ void RenderablePlanetProjection::attitudeParameters(double time){
_transform = glm::mat4(1);
//90 deg rotation w.r.t spice req.
glm::mat4 rot = glm::rotate(_transform, 90.f, glm::vec3(1, 0, 0));
glm::mat4 roty = glm::rotate(_transform, 90.f, glm::vec3(0, -1, 0));
glm::mat4 rotProp = glm::rotate(_transform, static_cast<float>(_rotation), glm::vec3(0, 1, 0));
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
_transform[i][j] = _stateMatrix[i][j];
_transform[i][j] = static_cast<float>(_stateMatrix[i][j]);
}
}
_transform = _transform* rot;
if (_target == "IAU_JUPITER"){ // tmp solution scale of jupiterX = 0.935126
_transform *= glm::scale(glm::mat4(1), glm::vec3(1, 0.935126, 1));
}
_transform = _transform * rot * roty * rotProp;
std::string shape, instrument;
std::vector<glm::dvec3> bounds;
glm::dvec3 bs;

View File

@@ -43,8 +43,8 @@ namespace planetgeometry {
SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary)
: PlanetGeometry()
, _radius("radius", "Radius", glm::vec2(1.f, 0.f), glm::vec2(-10.f, -20.f),
glm::vec2(10.f, 20.f))
, _realRadius("radius", "Radius", glm::vec4(1.f, 1.f, 1.f, 0.f), glm::vec4(-10.f, -10.f, -10.f, -20.f),
glm::vec4(10.f, 10.f, 10.f, 20.f))
, _segments("segments", "Segments", 20, 1, 50)
, _sphere(nullptr)
{
@@ -53,30 +53,37 @@ SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary)
using constants::simplespheregeometry::keySegments;
// The name is passed down from the SceneGraphNode
std::string name;
bool success = dictionary.getValue(keyName, name);
bool success = dictionary.getValue(keyName, _name);
assert(success);
glm::vec2 radius;
success = dictionary.getValue(keyRadius, radius);
glm::vec4 radius;
success = dictionary.getValue(keyRadius, _modRadius);
if (!success) {
LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '"
LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '"
<< keyRadius << "'");
}
else
_radius = radius;
else {
radius[0] = _modRadius[0];
radius[1] = _modRadius[0];
radius[2] = _modRadius[0];
radius[3] = _modRadius[1];
_realRadius = radius; // In case the kernels does not supply a real
}
double segments;
success = dictionary.getValue(keySegments, segments);
if (!success) {
LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '"
LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '"
<< keySegments << "'");
}
else
_segments = static_cast<int>(segments);
addProperty(_radius);
_radius.onChange(std::bind(&SimpleSphereGeometry::createSphere, this));
// The shader need the radii values but they are not changeable runtime
// TODO: Possibly add a scaling property @AA
addProperty(_realRadius);
// Changing the radius/scaling should affect the shader but not the geometry? @AA
//_radius.onChange(std::bind(&SimpleSphereGeometry::createSphere, this));
addProperty(_segments);
_segments.onChange(std::bind(&SimpleSphereGeometry::createSphere, this));
}
@@ -107,13 +114,13 @@ void SimpleSphereGeometry::render()
void SimpleSphereGeometry::createSphere(){
//create the power scaled scalar
PowerScaledScalar planetSize(_radius);
PowerScaledScalar planetSize(_modRadius);
_parent->setBoundingSphere(planetSize);
if(_sphere)
delete _sphere;
_sphere = new PowerScaledSphere(planetSize, _segments);
//_sphere = new PowerScaledSphere(planetSize, _segments);
_sphere = new PowerScaledSphere(_realRadius, _segments, _name);
_sphere->initialize();
}

View File

@@ -42,8 +42,8 @@ namespace planetgeometryprojection {
SimpleSphereGeometryProjection::SimpleSphereGeometryProjection(const ghoul::Dictionary& dictionary)
: PlanetGeometryProjection()
, _radius("radius", "Radius", glm::vec2(1.f, 0.f), glm::vec2(-10.f, -20.f),
glm::vec2(10.f, 20.f))
, _realRadius("radius", "Radius", glm::vec4(1.f, 1.f, 1.f, 0.f), glm::vec4(-10.f, -10.f, -10.f, -20.f),
glm::vec4(10.f, 10.f, 10.f, 20.f))
, _segments("segments", "Segments", 20, 1, 1000)
, _vaoID("vaoID", "Vao", 1, 1, 1)
, _vBufferID("vboID", "Vbo", 1, 1, 1)
@@ -55,30 +55,37 @@ SimpleSphereGeometryProjection::SimpleSphereGeometryProjection(const ghoul::Dict
using constants::simplespheregeometryprojection::keySegments;
// The name is passed down from the SceneGraphNode
std::string name;
bool success = dictionary.getValue(keyName, name);
bool success = dictionary.getValue(keyName, _name);
assert(success);
glm::vec2 radius;
success = dictionary.getValue(keyRadius, radius);
// removing "Projection"-suffix from name for SPICE compability, TODO: better solution @AA
if(_name.find("Projection"))
_name = _name.substr(0, _name.size() - 10);
glm::vec4 radius;
success = dictionary.getValue(keyRadius, _modRadius);
if (!success) {
LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '"
LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '"
<< keyRadius << "'");
}
else
_radius = radius;
else {
radius[0] = _modRadius[0];
radius[1] = _modRadius[0];
radius[2] = _modRadius[0];
radius[3] = _modRadius[1];
_realRadius = radius;
}
double segments;
success = dictionary.getValue(keySegments, segments);
if (!success) {
LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '"
LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '"
<< keySegments << "'");
}
else
_segments = static_cast<int>(segments);
addProperty(_radius);
_radius.onChange(std::bind(&SimpleSphereGeometryProjection::createSphere, this));
addProperty(_realRadius);
//_realRadius.onChange(std::bind(&SimpleSphereGeometryProjection::createSphere, this));
addProperty(_segments);
_segments.onChange(std::bind(&SimpleSphereGeometryProjection::createSphere, this));
}
@@ -117,12 +124,12 @@ void SimpleSphereGeometryProjection::createSphere()
{
//create the power scaled scalar
PowerScaledScalar planetSize(_radius);
PowerScaledScalar planetSize(_modRadius);
_parent->setBoundingSphere(planetSize);
delete _planet;
_planet = new PowerScaledSphere(planetSize, _segments);
_planet->initialize();
_planet = new PowerScaledSphere(_realRadius, _segments, _name);
_planet->initialize();
}
} // namespace planetgeometry

View File

@@ -24,7 +24,7 @@
// open space includes
#include <openspace/util/powerscaledsphere.h>
#include <openspace/util/spicemanager.h>
#include <ghoul/logging/logmanager.h>
#define _USE_MATH_DEFINES
@@ -125,6 +125,103 @@ PowerScaledSphere::PowerScaledSphere(const PowerScaledScalar& radius, int segmen
}
}
// Alternative Constructor for using accurate triaxial ellipsoid
PowerScaledSphere::PowerScaledSphere(properties::Vec4Property &radius, int segments, std::string planetName)
: _vaoID(0)
, _vBufferID(0)
, _iBufferID(0)
, _isize(6 * segments * segments)
, _vsize((segments + 1) * (segments + 1))
, _varray(new Vertex[_vsize])
, _iarray(new int[_isize])
{
static_assert(sizeof(Vertex) == 64,
"The size of the Vertex needs to be 64 for performance");
float a, b, c, powerscale;
bool accutareRadius = SpiceManager::ref().getPlanetEllipsoid(planetName, a, b, c);
if (accutareRadius) {
PowerScaledCoordinate powerScaledRadii = psc::CreatePowerScaledCoordinate(a, b, c);
powerScaledRadii[3] += 3; // SPICE returns radii in km
std::swap(powerScaledRadii[1], powerScaledRadii[2]); // c is equivalent to y in our coordinate system
radius.set(powerScaledRadii.vec4());
a = powerScaledRadii[0];
b = powerScaledRadii[1];
c = powerScaledRadii[2];
powerscale = powerScaledRadii[3];
}
else {
boost::any r = radius.get();
glm::vec4 modRadius = boost::any_cast<glm::vec4>(r);
a = modRadius[0];
b = modRadius[1];
c = modRadius[2];
powerscale = modRadius[3];
}
int nr = 0;
const float fsegments = static_cast<float>(segments);
for (int i = 0; i <= segments; i++) {
// define an extra vertex around the y-axis due to texture mapping
for (int j = 0; j <= segments; j++) {
const float fi = static_cast<float>(i);
const float fj = static_cast<float>(j);
// inclination angle (north to south)
const float theta = fi * float(M_PI) / fsegments; // 0 -> PI
// azimuth angle (east to west)
const float phi = fj * float(M_PI) * 2.0f / fsegments; // 0 -> 2*PI
const float x = a * sin(phi) * sin(theta); //
const float y = b * cos(theta); // up
const float z = c * cos(phi) * sin(theta); //
_varray[nr].location[0] = x;
_varray[nr].location[1] = y;
_varray[nr].location[2] = z;
_varray[nr].location[3] = powerscale;
glm::vec3 normal = glm::vec3(x, y, z);
if (!(x == 0.f && y == 0.f && z == 0.f))
normal = glm::normalize(normal);
_varray[nr].normal[0] = normal[0];
_varray[nr].normal[1] = normal[1];
_varray[nr].normal[2] = normal[2];
const float t1 = fj / fsegments;
const float t2 = fi / fsegments;
_varray[nr].tex[0] = t1;
_varray[nr].tex[1] = t2;
++nr;
}
}
nr = 0;
// define indices for all triangles
for (int i = 1; i <= segments; ++i) {
for (int j = 0; j < segments; ++j) {
const int t = segments + 1;
_iarray[nr] = t * (i - 1) + j + 0; //1
++nr;
_iarray[nr] = t * (i + 0) + j + 0; //2
++nr;
_iarray[nr] = t * (i + 0) + j + 1; //3
++nr;
_iarray[nr] = t * (i - 1) + j + 0; //4
++nr;
_iarray[nr] = t * (i + 0) + j + 1; //5
++nr;
_iarray[nr] = t * (i - 1) + j + 1; //6
++nr;
}
}
}
PowerScaledSphere::PowerScaledSphere(const PowerScaledSphere& cpy)
: _vaoID(cpy._vaoID)
, _vBufferID(cpy._vBufferID)

View File

@@ -766,6 +766,30 @@ bool SpiceManager::checkForError(std::string errorMessage) {
return false;
}
bool SpiceManager::getPlanetEllipsoid(std::string planetName, float &a, float &b, float &c) {
SpiceDouble radii[3];
SpiceInt n;
int id;
getNaifId(planetName, id);
if (bodfnd_c(id, "RADII")) {
bodvrd_c(planetName.c_str(), "RADII", 3, &n, radii);
a = radii[0];
b = radii[1];
c = radii[2];
}
else {
LWARNING("Could not find SPICE data for the shape of " + planetName + ", using modfile value");
a = 1.f;
b = 1.f;
c = 1.f;
}
bool hasError = checkForError("Error retrieving planet radii of " + planetName);
return !hasError;
}
//bool SpiceManager::getSubSolarPoint(std::string computationMethod,
// std::string target,
// double ephemeris,