mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 12:43:19 +02:00
numerous starfield fixes
This commit is contained in:
parent
1e58f6fd40
commit
715534154e
6 changed files with 164 additions and 144 deletions
|
@ -34,7 +34,17 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) {
|
|||
return float(_ptrController->changeLOD(fraction, overalloc, realloc));
|
||||
}
|
||||
|
||||
void Stars::render(float fovDiagonal, float aspect, glm::mat4 const& view) {
|
||||
void Stars::render(float fovY, float aspect, float nearZ) {
|
||||
|
||||
// determine length of screen diagonal from quadrant height and aspect ratio
|
||||
float quadrantHeight = nearZ * tan(angleConvert<Degrees,Radians>(fovY) * 0.5f);
|
||||
float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
|
||||
|
||||
// determine fov angle in respect to the diagonal
|
||||
float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f;
|
||||
|
||||
// pull the modelview matrix off the GL stack
|
||||
glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
|
||||
|
||||
_ptrController->render(fovDiagonal, aspect, glm::affineInverse(view));
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
namespace starfield { class Controller; }
|
||||
|
||||
/**
|
||||
* Starfield rendering component.
|
||||
*/
|
||||
//
|
||||
// Starfield rendering component.
|
||||
//
|
||||
class Stars {
|
||||
|
||||
starfield::Controller* _ptrController;
|
||||
|
@ -25,49 +25,49 @@ class Stars {
|
|||
Stars();
|
||||
~Stars();
|
||||
|
||||
/**
|
||||
* Reads input file from URL. Returns true upon success.
|
||||
*
|
||||
* The limit parameter allows to reduce the number of stars
|
||||
* that are loaded, keeping the brightest ones.
|
||||
*/
|
||||
//
|
||||
// Reads input file from URL. Returns true upon success.
|
||||
//
|
||||
// The limit parameter allows to reduce the number of stars
|
||||
// that are loaded, keeping the brightest ones.
|
||||
//
|
||||
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
|
||||
|
||||
/**
|
||||
* Renders the starfield from a local viewer's perspective.
|
||||
* The parameter specifies the field of view.
|
||||
*/
|
||||
void render(float fovDiagonal, float aspect, glm::mat4 const& view);
|
||||
//
|
||||
// Renders the starfield from a local viewer's perspective.
|
||||
// The parameters specifiy the field of view.
|
||||
//
|
||||
void render(float fovY, float aspect, float nearZ);
|
||||
|
||||
/**
|
||||
* Sets the resolution for FOV culling.
|
||||
*
|
||||
* The parameter determines the number of tiles in azimuthal
|
||||
* and altitudinal directions.
|
||||
*
|
||||
* GPU resources are updated upon change in which case 'true'
|
||||
* is returned.
|
||||
*/
|
||||
//
|
||||
// Sets the resolution for FOV culling.
|
||||
//
|
||||
// The parameter determines the number of tiles in azimuthal
|
||||
// and altitudinal directions.
|
||||
//
|
||||
// GPU resources are updated upon change in which case 'true'
|
||||
// is returned.
|
||||
//
|
||||
bool setResolution(unsigned k);
|
||||
|
||||
/**
|
||||
* Allows to alter the number of stars to be rendered given a
|
||||
* factor. The least brightest ones are omitted first.
|
||||
*
|
||||
* The further parameters determine when GPU resources should
|
||||
* be reallocated. Its value is fractional in respect to the
|
||||
* last number of stars 'n' that caused 'n * (1+overalloc)' to
|
||||
* be allocated. When the next call to setLOD causes the total
|
||||
* number of stars that could be rendered to drop below 'n *
|
||||
* (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
|
||||
* are updated. Note that all parameters must be fractions,
|
||||
* that is within the range [0;1] and that 'overalloc' must be
|
||||
* greater than or equal to 'realloc'.
|
||||
*
|
||||
* The current level of detail is returned as a float in [0;1].
|
||||
*/
|
||||
//
|
||||
// Allows to alter the number of stars to be rendered given a
|
||||
// factor. The least brightest ones are omitted first.
|
||||
//
|
||||
// The further parameters determine when GPU resources should
|
||||
// be reallocated. Its value is fractional in respect to the
|
||||
// last number of stars 'n' that caused 'n * (1+overalloc)' to
|
||||
// be allocated. When the next call to setLOD causes the total
|
||||
// number of stars that could be rendered to drop below 'n *
|
||||
// (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
|
||||
// are updated. Note that all parameters must be fractions,
|
||||
// that is within the range [0;1] and that 'overalloc' must be
|
||||
// greater than or equal to 'realloc'.
|
||||
//
|
||||
// The current level of detail is returned as a float in [0;1].
|
||||
//
|
||||
float changeLOD(float factor,
|
||||
float overalloc = 0.25, float realloc = 0.15);
|
||||
float overalloc = 0.25, float realloc = 0.15);
|
||||
|
||||
private:
|
||||
// don't copy/assign
|
||||
|
|
|
@ -762,9 +762,10 @@ void display(void)
|
|||
if (::starsOn) {
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
|
||||
glm::mat4 view;
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
|
||||
stars.render(angleConvert<Degrees,Radians>(whichCamera.getFieldOfView()), aspectRatio, view);
|
||||
|
||||
// finally render the starfield
|
||||
stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip());
|
||||
|
||||
}
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
|
|
|
@ -130,16 +130,17 @@ namespace starfield {
|
|||
|
||||
float halfPersp = perspective * 0.5f;
|
||||
|
||||
// determine dimensions based on a sought screen diagonal
|
||||
// define diagonal and near distance
|
||||
float halfDiag = std::sin(halfPersp);
|
||||
float nearClip = std::cos(halfPersp);
|
||||
|
||||
// determine half dimensions based on the screen diagonal
|
||||
//
|
||||
// ww + hh = dd
|
||||
// a = w / h => w = ha
|
||||
// hh + hh aa = dd
|
||||
// hh = dd / (1 + aa)
|
||||
float diag = 2.0f * std::sin(halfPersp);
|
||||
float nearClip = std::cos(halfPersp);
|
||||
|
||||
float hh = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect));
|
||||
float hh = sqrt(halfDiag * halfDiag / (1.0f + aspect * aspect));
|
||||
float hw = hh * aspect;
|
||||
|
||||
// cancel all translation
|
||||
|
@ -154,32 +155,34 @@ namespace starfield {
|
|||
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
|
||||
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
|
||||
angleHorizontalPolar<Radians>(azimuth, altitude);
|
||||
float const eps = 0.002f;
|
||||
altitude = glm::clamp(altitude,
|
||||
-Radians::halfPi() + eps, Radians::halfPi() - eps);
|
||||
#if STARFIELD_HEMISPHERE_ONLY
|
||||
altitude = std::max(0.0f, altitude);
|
||||
#endif
|
||||
unsigned tileIndex =
|
||||
_objTiling.getTileIndex(azimuth, altitude);
|
||||
|
||||
// fprintf(stderr, "Stars.cpp: starting on tile #%d\n", tileIndex);
|
||||
|
||||
|
||||
#if STARFIELD_DEBUG_CULLING
|
||||
mat4 matrix_debug = glm::translate(
|
||||
glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
|
||||
vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix);
|
||||
mat4 matrix_debug = glm::translate(glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
|
||||
vec3(0.0f, 0.0f, -4.0f)) *
|
||||
glm::affineInverse(matrix);
|
||||
#endif
|
||||
|
||||
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f)
|
||||
* glm::affineInverse(matrix);
|
||||
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
|
||||
|
||||
this->_itrOutIndex = (unsigned*) _arrBatchOffs;
|
||||
this->_vecWxform = vec3(row(matrix, 3));
|
||||
this->_valHalfPersp = halfPersp;
|
||||
this->_valMinBright = minBright;
|
||||
|
||||
floodFill(_arrTile + tileIndex, TileSelection(*this,
|
||||
_arrTile, _arrTile + _objTiling.getTileCount(),
|
||||
(Tile**) _arrBatchCount));
|
||||
TileSelection::Cursor cursor;
|
||||
cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude);
|
||||
cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude);
|
||||
|
||||
floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(),
|
||||
(TileSelection::Cursor*) _arrBatchCount));
|
||||
|
||||
#if STARFIELD_DEBUG_CULLING
|
||||
# define matrix matrix_debug
|
||||
|
@ -269,31 +272,35 @@ namespace starfield {
|
|||
|
||||
class TileSelection {
|
||||
|
||||
public:
|
||||
struct Cursor { Tile* current, * firstInRow; };
|
||||
private:
|
||||
Renderer& _refRenderer;
|
||||
Tile** const _arrStack;
|
||||
Tile** _itrStack;
|
||||
Cursor* const _arrStack;
|
||||
Cursor* _itrStack;
|
||||
Tile const* const _arrTile;
|
||||
Tile const* const _itrTilesEnd;
|
||||
Tile const* const _ptrTilesEnd;
|
||||
|
||||
public:
|
||||
|
||||
TileSelection(Renderer& renderer, Tile const* tiles,
|
||||
Tile const* tiles_end, Tile** stack) :
|
||||
Tile const* tiles_end, Cursor* stack) :
|
||||
|
||||
_refRenderer(renderer),
|
||||
_arrStack(stack),
|
||||
_itrStack(stack),
|
||||
_arrTile(tiles),
|
||||
_itrTilesEnd(tiles_end) {
|
||||
_ptrTilesEnd(tiles_end) {
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// flood fill strategy
|
||||
|
||||
bool select(Tile* t) {
|
||||
bool select(Cursor const& c) {
|
||||
Tile* t = c.current;
|
||||
|
||||
if (t < _arrTile || t >= _itrTilesEnd ||
|
||||
if (t < _arrTile || t >= _ptrTilesEnd ||
|
||||
!! (t->flags & Tile::checked)) {
|
||||
|
||||
// out of bounds or been here already
|
||||
|
@ -311,7 +318,8 @@ namespace starfield {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool process(Tile* t) {
|
||||
bool process(Cursor const& c) {
|
||||
Tile* t = c.current;
|
||||
|
||||
if (! (t->flags & Tile::visited)) {
|
||||
|
||||
|
@ -321,14 +329,39 @@ namespace starfield {
|
|||
return false;
|
||||
}
|
||||
|
||||
void right(Tile*& cursor) const { cursor += 1; }
|
||||
void left(Tile*& cursor) const { cursor -= 1; }
|
||||
void up(Tile*& cursor) const { cursor += yStride(); }
|
||||
void down(Tile*& cursor) const { cursor -= yStride(); }
|
||||
void right(Cursor& c) const {
|
||||
|
||||
void defer(Tile* t) { *_itrStack++ = t; }
|
||||
c.current += 1;
|
||||
if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) {
|
||||
c.current = c.firstInRow;
|
||||
}
|
||||
}
|
||||
void left(Cursor& c) const {
|
||||
|
||||
if (c.current == c.firstInRow) {
|
||||
c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles();
|
||||
}
|
||||
c.current -= 1;
|
||||
}
|
||||
void up(Cursor& c) const {
|
||||
|
||||
bool deferred(Tile*& cursor) {
|
||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
||||
c.current += d;
|
||||
c.firstInRow += d;
|
||||
}
|
||||
void down(Cursor& c) const {
|
||||
|
||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
||||
c.current -= d;
|
||||
c.firstInRow -= d;
|
||||
}
|
||||
|
||||
void defer(Cursor const& t) {
|
||||
|
||||
*_itrStack++ = t;
|
||||
}
|
||||
|
||||
bool deferred(Cursor& cursor) {
|
||||
|
||||
if (_itrStack != _arrStack) {
|
||||
cursor = *--_itrStack;
|
||||
|
@ -336,12 +369,6 @@ namespace starfield {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned yStride() const {
|
||||
|
||||
return _refRenderer._objTiling.getAzimuthalTiles();
|
||||
}
|
||||
};
|
||||
|
||||
bool visitTile(Tile* t) {
|
||||
|
@ -362,6 +389,7 @@ namespace starfield {
|
|||
bool tileVisible(Tile* t, unsigned i) {
|
||||
|
||||
float slice = _objTiling.getSliceAngle();
|
||||
float halfSlice = 0.5f * slice;
|
||||
unsigned stride = _objTiling.getAzimuthalTiles();
|
||||
float azimuth = (i % stride) * slice;
|
||||
float altitude = (i / stride) * slice - Radians::halfPi();
|
||||
|
@ -371,14 +399,13 @@ namespace starfield {
|
|||
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
|
||||
float w = dot(_vecWxform, tileCenter);
|
||||
|
||||
float halfSlice = 0.5f * slice;
|
||||
float daz = halfSlice * cos(abs(altitude) - halfSlice);
|
||||
float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
|
||||
float dal = halfSlice;
|
||||
float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal));
|
||||
|
||||
// fprintf(stderr, "Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip);
|
||||
|
||||
return w > adjustedNear;
|
||||
return w >= adjustedNear;
|
||||
}
|
||||
|
||||
void updateVertexCount(Tile* t, BrightnessLevel minBright) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// starfield/renderer/
|
||||
// starfield/renderer/Tiling.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 3/22/13.
|
||||
|
@ -51,6 +51,7 @@ namespace starfield {
|
|||
private:
|
||||
|
||||
unsigned discreteAngle(float unsigned_angle) const {
|
||||
|
||||
return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,32 +9,31 @@
|
|||
#ifndef __hifi__FloodFill__
|
||||
#define __hifi__FloodFill__
|
||||
|
||||
/**
|
||||
* Line scanning, iterative flood fill algorithm.
|
||||
*
|
||||
* The strategy must obey the following contract:
|
||||
*
|
||||
* There is an associated cursor that represents a position on the image.
|
||||
* The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
|
||||
* move it.
|
||||
* The state of a cursor can be deferred to temporary storage (typically a
|
||||
* stack or a queue) using the 'defer(C const&)' member function.
|
||||
* Calling 'deferred(C&)' restores a cursor's state from temporary storage
|
||||
* and removes it there.
|
||||
* The 'select(C const&)' and 'process(C const&)' functions control the
|
||||
* algorithm. The former is called to determine where to go. It may be
|
||||
* called multiple times but does not have to (and should not) return
|
||||
* 'true' more than once for a pixel to be selected (will cause memory
|
||||
* overuse, otherwise). The latter will never be called for a given pixel
|
||||
* unless previously selected. It may be called multiple times, in which
|
||||
* case it should return 'true' upon successful processing and 'false'
|
||||
* when an already processed pixel has been visited.
|
||||
*
|
||||
* Note: The terms "image" and "pixel" are used for illustratory purposes
|
||||
* and mean "undirected graph with 4-connected 2D grid topology" and "node",
|
||||
* respectively.
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Line scanning, iterative flood fill algorithm.
|
||||
//
|
||||
// The strategy must obey the following contract:
|
||||
//
|
||||
// There is an associated cursor that represents a position on the image.
|
||||
// The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
|
||||
// move it.
|
||||
// The state of a cursor can be deferred to temporary storage (typically a
|
||||
// stack or a queue) using the 'defer(C const&)' member function.
|
||||
// Calling 'deferred(C&)' restores a cursor's state from temporary storage
|
||||
// and removes it there.
|
||||
// The 'select(C const&)' and 'process(C const&)' functions control the
|
||||
// algorithm. The former is called to determine where to go. It may be
|
||||
// called multiple times but does not have to (and should not) return
|
||||
// 'true' more than once for a pixel to be selected (will cause memory
|
||||
// overuse, otherwise). The latter will never be called for a given pixel
|
||||
// unless previously selected. It may be called multiple times, in which
|
||||
// case it should return 'true' upon successful processing and 'false'
|
||||
// when an already processed pixel has been visited.
|
||||
//
|
||||
// Note: The terms "image" and "pixel" are used for illustratory purposes
|
||||
// and mean "undirected graph with 4-connected 2D grid topology" and "node",
|
||||
// respectively.
|
||||
//
|
||||
template< class Strategy, typename Cursor >
|
||||
void floodFill(Cursor const& position,
|
||||
Strategy const& strategy = Strategy());
|
||||
|
@ -63,57 +62,39 @@ struct floodFill_impl : Strategy {
|
|||
}
|
||||
|
||||
Cursor higher, lower, h,l, i;
|
||||
bool higherFound, lowerFound, hf, lf;
|
||||
do {
|
||||
|
||||
if (! process(position)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
higher = position; higherFound = false;
|
||||
up(higher); yTest(higher, higherFound);
|
||||
lower = position; lowerFound = false;
|
||||
down(lower); yTest(lower, lowerFound);
|
||||
higher = position;
|
||||
up(higher);
|
||||
if (select(higher)) { defer(higher); }
|
||||
|
||||
lower = position;
|
||||
down(lower);
|
||||
if (select(lower)) { defer(lower); }
|
||||
|
||||
i = position, h = higher, l = lower;
|
||||
hf = higherFound, lf = lowerFound;
|
||||
do {
|
||||
right(i), right(h), right(l); yTest(h,hf); yTest(l,lf);
|
||||
|
||||
} while (selectAndProcess(i));
|
||||
right(i), right(h), right(l);
|
||||
if (select(h)) { defer(h); }
|
||||
if (select(l)) { defer(l); }
|
||||
|
||||
} while (select(i) && process(i));
|
||||
|
||||
i = position, h = higher, l = lower;
|
||||
hf = higherFound, lf = lowerFound;
|
||||
do {
|
||||
left(i); left(h); left(l); yTest(h,hf); yTest(l,lf);
|
||||
left(i); left(h); left(l);
|
||||
if (select(h)) { defer(h); }
|
||||
if (select(l)) { defer(l); }
|
||||
|
||||
} while (selectAndProcess(i));
|
||||
} while (select(i) && process(i));
|
||||
|
||||
} while (deferred(position));
|
||||
}
|
||||
|
||||
bool selectAndProcess(Cursor const& i) {
|
||||
|
||||
if (select(i)) {
|
||||
|
||||
process(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void yTest(Cursor const& i, bool& state) {
|
||||
|
||||
if (! select(i)) {
|
||||
|
||||
state = false;
|
||||
|
||||
} else if (! state) {
|
||||
|
||||
state = true;
|
||||
defer(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< class Strategy, typename Cursor >
|
||||
|
|
Loading…
Reference in a new issue