204 lines
8.1 KiB
C++
204 lines
8.1 KiB
C++
// pointstarrenderer.cpp
|
|
//
|
|
// Copyright (C) 2001-2019, the 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 <celengine/starcolors.h>
|
|
#include <celengine/star.h>
|
|
#include <celengine/univcoord.h>
|
|
#include "pointstarvertexbuffer.h"
|
|
#include "render.h"
|
|
#include "pointstarrenderer.h"
|
|
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
|
|
// Convert a position in the universal coordinate system to astrocentric
|
|
// coordinates, taking into account possible orbital motion of the star.
|
|
static Vector3d astrocentricPosition(const UniversalCoord& pos,
|
|
const Star& star,
|
|
double t)
|
|
{
|
|
return pos.offsetFromKm(star.getPosition(t));
|
|
}
|
|
|
|
PointStarRenderer::PointStarRenderer() :
|
|
ObjectRenderer<Star, float>(StarDistanceLimit)
|
|
{
|
|
}
|
|
|
|
void PointStarRenderer::process(const Star& star, float distance, float appMag)
|
|
{
|
|
nProcessed++;
|
|
|
|
Vector3f starPos = star.getPosition();
|
|
|
|
// Calculate the difference at double precision *before* converting to float.
|
|
// This is very important for stars that are far from the origin.
|
|
Vector3f relPos = (starPos.cast<double>() - obsPos).cast<float>();
|
|
float orbitalRadius = star.getOrbitalRadius();
|
|
bool hasOrbit = orbitalRadius > 0.0f;
|
|
|
|
if (distance > distanceLimit)
|
|
return;
|
|
|
|
// A very rough check to see if the star may be visible: is the star in
|
|
// front of the viewer? If the star might be close (relPos.x^2 < 0.1) or
|
|
// is moving in an orbit, we'll always regard it as potentially visible.
|
|
// TODO: consider normalizing relPos and comparing relPos*viewNormal against
|
|
// cosFOV--this will cull many more stars than relPos*viewNormal, at the
|
|
// cost of a normalize per star.
|
|
if (relPos.dot(viewNormal) > 0.0f || relPos.x() * relPos.x() < 0.1f || hasOrbit)
|
|
{
|
|
#ifdef HDR_COMPRESS
|
|
Color starColorFull = colorTemp->lookupColor(star.getTemperature());
|
|
Color starColor(starColorFull.red() * 0.5f,
|
|
starColorFull.green() * 0.5f,
|
|
starColorFull.blue() * 0.5f);
|
|
#else
|
|
Color starColor = colorTemp->lookupColor(star.getTemperature());
|
|
#endif
|
|
float discSizeInPixels = 0.0f;
|
|
float orbitSizeInPixels = 0.0f;
|
|
|
|
if (hasOrbit)
|
|
orbitSizeInPixels = orbitalRadius / (distance * pixelSize);
|
|
|
|
// Special handling for stars less than SolarSystemMaxDistance away
|
|
// We can't just go ahead and render a nearby star in the usual way
|
|
// for two reasons:
|
|
// * It may be clipped by the near plane
|
|
// * It may be large enough that we should render it as a mesh
|
|
// instead of a particle
|
|
// It's possible that the second condition might apply for stars
|
|
// further than one light year away if the star is huge, the fov is
|
|
// very small and the resolution is high. We'll ignore this for now
|
|
// and use the most inexpensive test possible . . .
|
|
if (distance < SolarSystemMaxDistance || orbitSizeInPixels > 1.0f)
|
|
{
|
|
// Compute the position of the observer relative to the star.
|
|
// This is a much more accurate (and expensive) distance
|
|
// calculation than the previous one which used the observer's
|
|
// position rounded off to floats.
|
|
Vector3d hPos = astrocentricPosition(observer->getPosition(),
|
|
star,
|
|
observer->getTime());
|
|
relPos = hPos.cast<float>() * -astro::kilometersToLightYears(1.0f);
|
|
distance = relPos.norm();
|
|
|
|
// Recompute apparent magnitude using new distance computation
|
|
appMag = star.getApparentMagnitude((float)distance);
|
|
|
|
discSizeInPixels = star.getRadius() / astro::lightYearsToKilometers(distance) / pixelSize;
|
|
++nClose;
|
|
}
|
|
|
|
// Place labels for stars brighter than the specified label threshold brightness
|
|
if (((labelMode & Renderer::StarLabels) != 0) && appMag < labelThresholdMag)
|
|
{
|
|
Vector3f starDir = relPos;
|
|
starDir.normalize();
|
|
if (starDir.dot(viewNormal) > cosFOV)
|
|
{
|
|
float distr = 3.5f * (labelThresholdMag - appMag)/labelThresholdMag;
|
|
if (distr > 1.0f)
|
|
distr = 1.0f;
|
|
renderer->addBackgroundAnnotation(nullptr, starDB->getStarName(star, true),
|
|
Color(Renderer::StarLabelColor, distr * Renderer::StarLabelColor.alpha()),
|
|
relPos);
|
|
nLabelled++;
|
|
}
|
|
}
|
|
// Stars closer than the maximum solar system size are actually
|
|
// added to the render list and depth sorted, since they may occlude
|
|
// planets.
|
|
if (distance > SolarSystemMaxDistance)
|
|
{
|
|
#ifdef USE_HDR
|
|
float satPoint = saturationMag;
|
|
float alpha = exposure*(faintestMag - appMag)/(faintestMag - saturationMag + 0.001f);
|
|
#else
|
|
float satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale; // TODO: precompute this value
|
|
float alpha = (faintestMag - appMag) * brightnessScale + brightnessBias;
|
|
#endif
|
|
#ifdef DEBUG_HDR_ADAPT
|
|
minMag = max(minMag, appMag);
|
|
maxMag = min(maxMag, appMag);
|
|
minAlpha = min(minAlpha, alpha);
|
|
maxAlpha = max(maxAlpha, alpha);
|
|
++total;
|
|
if (alpha > above)
|
|
{
|
|
++countAboveN;
|
|
}
|
|
#endif
|
|
|
|
if (useScaledDiscs)
|
|
{
|
|
float discSize = size;
|
|
if (alpha < 0.0f)
|
|
{
|
|
alpha = 0.0f;
|
|
}
|
|
else if (alpha > 1.0f)
|
|
{
|
|
float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag)));
|
|
discSize *= discScale;
|
|
|
|
float glareAlpha = min(0.5f, discScale / 4.0f);
|
|
glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), discSize * 3.0f);
|
|
|
|
alpha = 1.0f;
|
|
}
|
|
starVertexBuffer->addStar(relPos, Color(starColor, alpha), /*discSize*/appMag);
|
|
}
|
|
else
|
|
{
|
|
if (alpha < 0.0f)
|
|
{
|
|
alpha = 0.0f;
|
|
}
|
|
else if (alpha > 1.0f)
|
|
{
|
|
float discScale = min(100.0f, satPoint - appMag + 2.0f);
|
|
float glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f);
|
|
glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), 2.0f * discScale * size);
|
|
#ifdef DEBUG_HDR_ADAPT
|
|
maxSize = max(maxSize, 2.0f * discScale * size);
|
|
#endif
|
|
}
|
|
starVertexBuffer->addStar(relPos, Color(starColor, alpha), size);
|
|
}
|
|
|
|
++nRendered;
|
|
}
|
|
else
|
|
{
|
|
Matrix3f viewMat = observer->getOrientationf().toRotationMatrix();
|
|
Vector3f viewMatZ = viewMat.row(2);
|
|
|
|
RenderListEntry rle;
|
|
rle.renderableType = RenderListEntry::RenderableStar;
|
|
rle.star = ☆
|
|
|
|
// Objects in the render list are always rendered relative to
|
|
// a viewer at the origin--this is different than for distant
|
|
// stars.
|
|
float scale = astro::lightYearsToKilometers(1.0f);
|
|
rle.position = relPos * scale;
|
|
rle.centerZ = rle.position.dot(viewMatZ);
|
|
rle.distance = rle.position.norm();
|
|
rle.radius = star.getRadius();
|
|
rle.discSizeInPixels = discSizeInPixels;
|
|
rle.appMag = appMag;
|
|
rle.isOpaque = true;
|
|
renderList->push_back(rle);
|
|
}
|
|
}
|
|
}
|