Merge pull request #127 from tschw/19188

19188
This commit is contained in:
Philip Rosedale 2013-04-24 16:53:04 -07:00
commit 6c986a1049
7 changed files with 170 additions and 148 deletions

View file

@ -42,7 +42,7 @@ void usage(void)
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
}; }
bool processParameters(int parameterCount, char* parameterData[]) bool processParameters(int parameterCount, char* parameterData[])
{ {
@ -93,7 +93,7 @@ bool processParameters(int parameterCount, char* parameterData[])
return true; return true;
}; };
int main(int argc, const char* argv[]) { int main(int argc, char* argv[]) {
srand(time(0)); srand(time(0));
int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1));

View file

@ -34,7 +34,17 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) {
return float(_ptrController->changeLOD(fraction, overalloc, 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)); _ptrController->render(fovDiagonal, aspect, glm::affineInverse(view));
} }

View file

@ -13,9 +13,9 @@
namespace starfield { class Controller; } namespace starfield { class Controller; }
/** //
* Starfield rendering component. // Starfield rendering component.
*/ //
class Stars { class Stars {
starfield::Controller* _ptrController; starfield::Controller* _ptrController;
@ -25,49 +25,49 @@ class Stars {
Stars(); Stars();
~Stars(); ~Stars();
/** //
* Reads input file from URL. Returns true upon success. // Reads input file from URL. Returns true upon success.
* //
* The limit parameter allows to reduce the number of stars // The limit parameter allows to reduce the number of stars
* that are loaded, keeping the brightest ones. // that are loaded, keeping the brightest ones.
*/ //
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000); bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
/** //
* Renders the starfield from a local viewer's perspective. // Renders the starfield from a local viewer's perspective.
* The parameter specifies the field of view. // The parameters specifiy the field of view.
*/ //
void render(float fovDiagonal, float aspect, glm::mat4 const& view); void render(float fovY, float aspect, float nearZ);
/** //
* Sets the resolution for FOV culling. // Sets the resolution for FOV culling.
* //
* The parameter determines the number of tiles in azimuthal // The parameter determines the number of tiles in azimuthal
* and altitudinal directions. // and altitudinal directions.
* //
* GPU resources are updated upon change in which case 'true' // GPU resources are updated upon change in which case 'true'
* is returned. // is returned.
*/ //
bool setResolution(unsigned k); bool setResolution(unsigned k);
/** //
* Allows to alter the number of stars to be rendered given a // Allows to alter the number of stars to be rendered given a
* factor. The least brightest ones are omitted first. // factor. The least brightest ones are omitted first.
* //
* The further parameters determine when GPU resources should // The further parameters determine when GPU resources should
* be reallocated. Its value is fractional in respect to the // be reallocated. Its value is fractional in respect to the
* last number of stars 'n' that caused 'n * (1+overalloc)' to // last number of stars 'n' that caused 'n * (1+overalloc)' to
* be allocated. When the next call to setLOD causes the total // be allocated. When the next call to setLOD causes the total
* number of stars that could be rendered to drop below 'n * // number of stars that could be rendered to drop below 'n *
* (1-realloc)' or rises above 'n * (1+realloc)' GPU resources // (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
* are updated. Note that all parameters must be fractions, // are updated. Note that all parameters must be fractions,
* that is within the range [0;1] and that 'overalloc' must be // that is within the range [0;1] and that 'overalloc' must be
* greater than or equal to 'realloc'. // greater than or equal to 'realloc'.
* //
* The current level of detail is returned as a float in [0;1]. // The current level of detail is returned as a float in [0;1].
*/ //
float changeLOD(float factor, float changeLOD(float factor,
float overalloc = 0.25, float realloc = 0.15); float overalloc = 0.25, float realloc = 0.15);
private: private:
// don't copy/assign // don't copy/assign

View file

@ -862,9 +862,10 @@ void display(void)
if (::starsOn) { if (::starsOn) {
// should be the first rendering pass - w/o depth buffer / lighting // should be the first rendering pass - w/o depth buffer / lighting
glm::mat4 view;
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); // finally render the starfield
stars.render(angleConvert<Degrees,Radians>(whichCamera.getFieldOfView()), aspectRatio, view); stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip());
} }
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);

View file

@ -130,17 +130,18 @@ namespace starfield {
float halfPersp = perspective * 0.5f; float halfPersp = perspective * 0.5f;
// determine dimensions based on a sought screen diagonal // define diagonal and near distance
// float halfDiag = std::sin(halfPersp);
// ww + hh = dd
// a = h / w => h = wa
// ww + ww aa = dd
// ww = dd / (1 + aa)
float diag = 2.0f * std::sin(halfPersp);
float nearClip = std::cos(halfPersp); float nearClip = std::cos(halfPersp);
float hw = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect)); // determine half dimensions based on the screen diagonal
float hh = hw * aspect; //
// ww + hh = dd
// a = w / h => w = ha
// hh + hh aa = dd
// hh = dd / (1 + aa)
float hh = sqrt(halfDiag * halfDiag / (1.0f + aspect * aspect));
float hw = hh * aspect;
// cancel all translation // cancel all translation
mat4 matrix = orientation; mat4 matrix = orientation;
@ -154,6 +155,9 @@ namespace starfield {
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi(); float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z)); float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
angleHorizontalPolar<Radians>(azimuth, altitude); angleHorizontalPolar<Radians>(azimuth, altitude);
float const eps = 0.002f;
altitude = glm::clamp(altitude,
-Radians::halfPi() + eps, Radians::halfPi() - eps);
#if STARFIELD_HEMISPHERE_ONLY #if STARFIELD_HEMISPHERE_ONLY
altitude = std::max(0.0f, altitude); altitude = std::max(0.0f, altitude);
#endif #endif
@ -162,24 +166,25 @@ namespace starfield {
// printLog("Stars.cpp: starting on tile #%d\n", tileIndex); // printLog("Stars.cpp: starting on tile #%d\n", tileIndex);
#if STARFIELD_DEBUG_CULLING #if STARFIELD_DEBUG_CULLING
mat4 matrix_debug = glm::translate( mat4 matrix_debug = glm::translate(glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f), vec3(0.0f, 0.0f, -4.0f)) *
vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix); glm::affineInverse(matrix);
#endif #endif
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
* glm::affineInverse(matrix);
this->_itrOutIndex = (unsigned*) _arrBatchOffs; this->_itrOutIndex = (unsigned*) _arrBatchOffs;
this->_vecWxform = vec3(row(matrix, 3)); this->_vecWxform = vec3(row(matrix, 3));
this->_valHalfPersp = halfPersp; this->_valHalfPersp = halfPersp;
this->_valMinBright = minBright; this->_valMinBright = minBright;
floodFill(_arrTile + tileIndex, TileSelection(*this, TileSelection::Cursor cursor;
_arrTile, _arrTile + _objTiling.getTileCount(), cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude);
(Tile**) _arrBatchCount)); cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude);
floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(),
(TileSelection::Cursor*) _arrBatchCount));
#if STARFIELD_DEBUG_CULLING #if STARFIELD_DEBUG_CULLING
# define matrix matrix_debug # define matrix matrix_debug
@ -269,31 +274,35 @@ namespace starfield {
class TileSelection { class TileSelection {
public:
struct Cursor { Tile* current, * firstInRow; };
private:
Renderer& _refRenderer; Renderer& _refRenderer;
Tile** const _arrStack; Cursor* const _arrStack;
Tile** _itrStack; Cursor* _itrStack;
Tile const* const _arrTile; Tile const* const _arrTile;
Tile const* const _itrTilesEnd; Tile const* const _ptrTilesEnd;
public: public:
TileSelection(Renderer& renderer, Tile const* tiles, TileSelection(Renderer& renderer, Tile const* tiles,
Tile const* tiles_end, Tile** stack) : Tile const* tiles_end, Cursor* stack) :
_refRenderer(renderer), _refRenderer(renderer),
_arrStack(stack), _arrStack(stack),
_itrStack(stack), _itrStack(stack),
_arrTile(tiles), _arrTile(tiles),
_itrTilesEnd(tiles_end) { _ptrTilesEnd(tiles_end) {
} }
protected: protected:
// flood fill strategy // 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)) { !! (t->flags & Tile::checked)) {
// out of bounds or been here already // out of bounds or been here already
@ -311,7 +320,8 @@ namespace starfield {
return false; return false;
} }
bool process(Tile* t) { bool process(Cursor const& c) {
Tile* t = c.current;
if (! (t->flags & Tile::visited)) { if (! (t->flags & Tile::visited)) {
@ -321,14 +331,39 @@ namespace starfield {
return false; return false;
} }
void right(Tile*& cursor) const { cursor += 1; } void right(Cursor& c) const {
void left(Tile*& cursor) const { cursor -= 1; }
void up(Tile*& cursor) const { cursor += yStride(); }
void down(Tile*& cursor) const { cursor -= yStride(); }
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) { if (_itrStack != _arrStack) {
cursor = *--_itrStack; cursor = *--_itrStack;
@ -336,12 +371,6 @@ namespace starfield {
} }
return false; return false;
} }
private:
unsigned yStride() const {
return _refRenderer._objTiling.getAzimuthalTiles();
}
}; };
bool visitTile(Tile* t) { bool visitTile(Tile* t) {
@ -362,6 +391,7 @@ namespace starfield {
bool tileVisible(Tile* t, unsigned i) { bool tileVisible(Tile* t, unsigned i) {
float slice = _objTiling.getSliceAngle(); float slice = _objTiling.getSliceAngle();
float halfSlice = 0.5f * slice;
unsigned stride = _objTiling.getAzimuthalTiles(); unsigned stride = _objTiling.getAzimuthalTiles();
float azimuth = (i % stride) * slice; float azimuth = (i % stride) * slice;
float altitude = (i / stride) * slice - Radians::halfPi(); float altitude = (i / stride) * slice - Radians::halfPi();
@ -371,14 +401,13 @@ namespace starfield {
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz); vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
float w = dot(_vecWxform, tileCenter); float w = dot(_vecWxform, tileCenter);
float halfSlice = 0.5f * slice; float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
float daz = halfSlice * cos(abs(altitude) - halfSlice);
float dal = halfSlice; float dal = halfSlice;
float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal)); float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal));
// printLog("Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip); // printLog("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) { void updateVertexCount(Tile* t, BrightnessLevel minBright) {

View file

@ -1,5 +1,5 @@
// //
// starfield/renderer/ // starfield/renderer/Tiling.h
// interface // interface
// //
// Created by Tobias Schwinger on 3/22/13. // Created by Tobias Schwinger on 3/22/13.
@ -51,6 +51,7 @@ namespace starfield {
private: private:
unsigned discreteAngle(float unsigned_angle) const { unsigned discreteAngle(float unsigned_angle) const {
return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f)); return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f));
} }

View file

@ -9,32 +9,31 @@
#ifndef __hifi__FloodFill__ #ifndef __hifi__FloodFill__
#define __hifi__FloodFill__ #define __hifi__FloodFill__
/** //
* Line scanning, iterative flood fill algorithm. // Line scanning, iterative flood fill algorithm.
* //
* The strategy must obey the following contract: // The strategy must obey the following contract:
* //
* There is an associated cursor that represents a position on the image. // There is an associated cursor that represents a position on the image.
* The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)' // The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
* move it. // move it.
* The state of a cursor can be deferred to temporary storage (typically a // The state of a cursor can be deferred to temporary storage (typically a
* stack or a queue) using the 'defer(C const&)' member function. // stack or a queue) using the 'defer(C const&)' member function.
* Calling 'deferred(C&)' restores a cursor's state from temporary storage // Calling 'deferred(C&)' restores a cursor's state from temporary storage
* and removes it there. // and removes it there.
* The 'select(C const&)' and 'process(C const&)' functions control the // The 'select(C const&)' and 'process(C const&)' functions control the
* algorithm. The former is called to determine where to go. It may be // 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 // 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 // '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 // overuse, otherwise). The latter will never be called for a given pixel
* unless previously selected. It may be called multiple times, in which // unless previously selected. It may be called multiple times, in which
* case it should return 'true' upon successful processing and 'false' // case it should return 'true' upon successful processing and 'false'
* when an already processed pixel has been visited. // when an already processed pixel has been visited.
* //
* Note: The terms "image" and "pixel" are used for illustratory purposes // Note: The terms "image" and "pixel" are used for illustratory purposes
* and mean "undirected graph with 4-connected 2D grid topology" and "node", // and mean "undirected graph with 4-connected 2D grid topology" and "node",
* respectively. // respectively.
* //
*/
template< class Strategy, typename Cursor > template< class Strategy, typename Cursor >
void floodFill(Cursor const& position, void floodFill(Cursor const& position,
Strategy const& strategy = Strategy()); Strategy const& strategy = Strategy());
@ -63,57 +62,39 @@ struct floodFill_impl : Strategy {
} }
Cursor higher, lower, h,l, i; Cursor higher, lower, h,l, i;
bool higherFound, lowerFound, hf, lf;
do { do {
if (! process(position)) { if (! process(position)) {
continue; continue;
} }
higher = position; higherFound = false; higher = position;
up(higher); yTest(higher, higherFound); up(higher);
lower = position; lowerFound = false; if (select(higher)) { defer(higher); }
down(lower); yTest(lower, lowerFound);
lower = position;
down(lower);
if (select(lower)) { defer(lower); }
i = position, h = higher, l = lower; i = position, h = higher, l = lower;
hf = higherFound, lf = lowerFound;
do { 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; i = position, h = higher, l = lower;
hf = higherFound, lf = lowerFound;
do { 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)); } 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 > template< class Strategy, typename Cursor >