Skip to content

Commit fafdf5a

Browse files
committed
Fix z fighting of HiPS levels
When a tile is drawn in a planetary survey, and then its child of a higher level is drawn over, we can often observe the lower-level tile shining through the higher-level one, and the shape that shines through depends on the position of the planet, which resembles z fighting. To combat this, we now draw only the deepest HiPS level requested for the current zoom level, substituting lower-resolution textures for the tiles whose native-resolution textures haven't been loaded yet. This makes it much harder to support fading between levels, so fading support is removed.
1 parent 13597ff commit fafdf5a

File tree

2 files changed

+71
-31
lines changed

2 files changed

+71
-31
lines changed

src/core/StelHips.cpp

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ class HipsTile
4141
StelTextureSP allsky; // allsky low res version of the texture.
4242
StelTextureSP normalAllsky; // allsky low res version of the texture.
4343
StelTextureSP horizonAllsky; // allsky low res version of the texture.
44-
45-
// Used for smooth fade in
46-
QTimeLine texFader;
4744
};
4845

4946
static QString getExt(const QString& format)
@@ -437,7 +434,7 @@ static bool isClipped(int n, double (*pos)[4])
437434
return false;
438435
}
439436

440-
bool HipsSurvey::bindTextures(const HipsTile& tile)
437+
bool HipsSurvey::bindTextures(HipsTile& tile, const int orderMin, Vec2f& texCoordShift, float& texCoordScale, bool& tileIsLoaded)
441438
{
442439
constexpr int colorTexUnit = 0;
443440
constexpr int normalTexUnit = 2;
@@ -446,22 +443,53 @@ bool HipsSurvey::bindTextures(const HipsTile& tile)
446443
if (normals && !tile.normalTexture && !tile.normalAllsky) return false;
447444
if (horizons && !tile.horizonTexture && !tile.horizonAllsky) return false;
448445

449-
if (!tile.texture->bind(colorTexUnit) && (!tile.allsky || !tile.allsky->bind(colorTexUnit)))
450-
return false;
451-
if (normals && tile.normalTexture && !tile.normalTexture->bind(normalTexUnit) && (!tile.normalAllsky || !tile.normalAllsky->bind(normalTexUnit)))
452-
return false;
453-
if (horizons && tile.horizonTexture && !tile.horizonTexture->bind(horizonTexUnit) && (!tile.horizonAllsky || !tile.horizonAllsky->bind(horizonTexUnit)))
454-
return false;
446+
bool ok = tile.texture->bind(colorTexUnit);
447+
if (!ok) ok = tile.allsky && tile.allsky->bind(colorTexUnit);
448+
if (ok && normals)
449+
{
450+
ok = tile.normalTexture && tile.normalTexture->bind(normalTexUnit);
451+
if (!ok) ok = tile.normalAllsky && tile.normalAllsky->bind(normalTexUnit);
452+
}
453+
if (ok && horizons)
454+
{
455+
ok = tile.horizonTexture && tile.horizonTexture->bind(horizonTexUnit);
456+
if (!ok) ok = tile.horizonAllsky && tile.horizonAllsky->bind(horizonTexUnit);
457+
}
458+
459+
if (!ok) tileIsLoaded = false;
455460

456-
return true;
461+
if (!ok && tile.order > orderMin)
462+
{
463+
// Current-level textures failed to bind, let's try the previous level
464+
const auto parentTile = getTile(tile.order - 1, tile.pix / 4);
465+
if (!parentTile) return false;
466+
assert(parentTile->order == tile.order - 1);
467+
assert(parentTile->order >= orderMin);
468+
469+
static const Vec2f bottomLeftPartUV[] = {Vec2f(0,0.5), Vec2f(0,0), Vec2f(0.5,0.5), Vec2f(0.5,0)};
470+
const int pos = tile.pix % 4;
471+
// Like the multiplication of the texture transform by scale and shift matrix on the left:
472+
// transform = shift(bottomLeftPartUV[pos]) * scale(0.5) * transform
473+
texCoordShift = texCoordShift * 0.5f + bottomLeftPartUV[pos];
474+
texCoordScale *= 0.5f;
475+
476+
ok = bindTextures(*parentTile, orderMin, texCoordShift, texCoordScale, tileIsLoaded);
477+
if (!ok) return false;
478+
}
479+
480+
return ok;
457481
}
458482

459483
void HipsSurvey::drawTile(int order, int pix, int drawOrder, int splitOrder, bool outside,
460-
const SphericalCap& viewportShape, StelPainter* sPainter, Vec3d observerVelocity, DrawCallback callback)
484+
const SphericalCap& viewportShape, StelPainter* sPainter,
485+
Vec3d observerVelocity, DrawCallback callback)
461486
{
462487
Vec3d pos;
463488
Mat3d mat3;
464489
const Vec2d uv[4] = {Vec2d(0, 0), Vec2d(0, 1), Vec2d(1, 0), Vec2d(1, 1)};
490+
bool tileLoaded = true;
491+
Vec2f texCoordShift(0,0);
492+
float texCoordScale = 1;
465493
HipsTile *tile;
466494
int orderMin = getPropertyInt("hips_order_min", 3);
467495
QVector<Vec3d> vertsArray;
@@ -521,26 +549,16 @@ void HipsSurvey::drawTile(int order, int pix, int drawOrder, int splitOrder, boo
521549
tile = getTile(order, pix);
522550

523551
if (!tile) return;
524-
if (!bindTextures(*tile)) return;
552+
if (!bindTextures(*tile, orderMin, texCoordShift, texCoordScale, tileLoaded))
553+
return;
525554

526-
if (tile->texFader.state() == QTimeLine::NotRunning && tile->texFader.currentValue() == 0.0)
527-
tile->texFader.start();
528-
nbLoadedTiles++;
555+
if (tileLoaded)
556+
nbLoadedTiles++;
529557

530-
if (order < drawOrder)
531-
{
532-
// If all the children tiles are loaded, we can skip the parent.
533-
int i;
534-
for (i = 0; i < 4; i++)
535-
{
536-
HipsTile* child = getTile(order + 1, pix * 4 + i);
537-
if (!child || child->texFader.currentValue() < 1.0) break;
538-
}
539-
if (i == 4) goto skip_render;
540-
}
558+
if (order < drawOrder) goto skip_render;
541559

542560
// Actually draw the tile, as a single quad.
543-
alpha = color[3] * static_cast<float>(tile->texFader.currentValue());
561+
alpha = color[3];
544562
if (alpha < 1.0f)
545563
{
546564
sPainter->setBlending(true);
@@ -553,7 +571,7 @@ void HipsSurvey::drawTile(int order, int pix, int drawOrder, int splitOrder, boo
553571
}
554572
sPainter->setCullFace(true);
555573
nb = fillArrays(order, pix, drawOrder, splitOrder, outside, sPainter, observerVelocity,
556-
vertsArray, texArray, indicesArray);
574+
texCoordShift, texCoordScale, vertsArray, texArray, indicesArray);
557575
if (!callback) {
558576
sPainter->setArrays(vertsArray.constData(), texArray.constData());
559577
sPainter->drawFromArray(StelPainter::Triangles, nb, 0, true, indicesArray.constData());
@@ -577,6 +595,7 @@ void HipsSurvey::drawTile(int order, int pix, int drawOrder, int splitOrder, boo
577595

578596
int HipsSurvey::fillArrays(int order, int pix, int drawOrder, int splitOrder,
579597
bool outside, StelPainter* sPainter, Vec3d observerVelocity,
598+
const Vec2f& texCoordShift, const float texCoordScale,
580599
QVector<Vec3d>& verts, QVector<Vec2f>& tex, QVector<uint16_t>& indices)
581600
{
582601
Q_UNUSED(sPainter)
@@ -611,7 +630,7 @@ int HipsSurvey::fillArrays(int order, int pix, int drawOrder, int splitOrder,
611630
}
612631

613632
verts << pos;
614-
tex << texPos;
633+
tex << texPos * texCoordScale + texCoordShift;
615634
}
616635
}
617636
for (uint16_t i = 0; i < gridSize; i++)

src/core/StelHips.hpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,35 @@ class HipsSurvey : public QObject
143143
int getPropertyInt(const QString& key, int fallback = 0);
144144
bool getAllsky();
145145
HipsTile* getTile(int order, int pix);
146-
bool bindTextures(const HipsTile& tile);
146+
/*! @brief Bind textures for drawing
147+
148+
If @p tile is not ready for drawing (e.g. not fully loaded), alter
149+
@p texCoordShift and @p texCoordScale so that they let us address
150+
the corresponding part of a parent texture that will be bound.
151+
152+
@param tile The tile to draw
153+
@param orderMin Smallest available HiPS order of the current survey
154+
@param texCoordShift The UV coordinates shift to be applied to the
155+
texture coordinates to address a subtexture in the parent. Must be
156+
set to 0 before the initial call to this function.
157+
@param texCoordScale The UV coordinates scale to be applied to the
158+
texture coordinates to address a subtexture in the parent. Must be
159+
set to 1 before the initial call to this function.
160+
@param tileIsLoaded Gets set to \c false if it was the requested
161+
HiPS level isn't fully loaded. Must be set to \c true before the
162+
initial call to this function.
163+
164+
@return Whether a tile has been successfully bound.
165+
*/
166+
bool bindTextures(HipsTile& tile, int orderMin, Vec2f& texCoordShift, float& texCoordScale, bool& tileIsLoaded);
147167
// draw a single tile. observerVelocity (in the correct hipsFrame) is necessary for aberration correction. Set to 0 for no aberration correction.
148168
void drawTile(int order, int pix, int drawOrder, int splitOrder, bool outside,
149169
const SphericalCap& viewportShape, StelPainter* sPainter, Vec3d observerVelocity, DrawCallback callback);
150170

151171
// Fill the array for a given tile.
152172
int fillArrays(int order, int pix, int drawOrder, int splitOrder,
153173
bool outside, StelPainter* sPainter, Vec3d observerVelocity,
174+
const Vec2f& texCoordShift, const float texCoordScale,
154175
QVector<Vec3d>& verts, QVector<Vec2f>& tex, QVector<uint16_t>& indices);
155176

156177
void updateProgressBar(int nb, int total);

0 commit comments

Comments
 (0)