Support fisheye projection, dumb version

pull/878/head
Levin Li 2020-10-02 17:00:00 +08:00
parent 62b5f58351
commit b465017de8
26 changed files with 289 additions and 89 deletions

View File

@ -11,5 +11,5 @@ varying float shade;
void main(void)
{
shade = abs(dot(viewDir.xyz, in_Normal.xyz) * brightness * fadeFactor);
gl_Position = MVPMatrix * in_Position;
set_vp(in_Position);
}

View File

@ -2,5 +2,5 @@ attribute vec4 in_Position;
void main(void)
{
gl_Position = MVPMatrix * in_Position;
set_vp(in_Position);
}

View File

@ -3,5 +3,5 @@ attribute vec2 in_Position;
void main(void)
{
vec4 p = vec4(in_Position.x, 0.0, in_Position.y, 1.0);
gl_Position = MVPMatrix * p;
set_vp(p);
}

View File

@ -20,5 +20,5 @@ void main(void)
float a = in_TexCoord0.w / 65535.0; // [0, 65535] -> [0, 1]
color = vec4(texture2D(colorTex, vec2(t, 0.0)).rgb, a);
texCoord = in_TexCoord0.st;
gl_Position = MVPMatrix * in_Position;
set_vp(in_Position);
}

View File

@ -52,5 +52,5 @@ void main(void)
gl_PointSize = s * min(obsDistanceToStarRatio, 1.0);
color = vec4(in_Color.rgb, min(1.0, br * (1.0 - pixelWeight * relStarDensity())));
gl_Position = MVPMatrix * vec4(p, 1.0);
set_vp(vec4(p, 1.0));
}

View File

@ -1,10 +1,16 @@
attribute vec3 in_Position;
attribute vec2 in_TexCoord0;
uniform float pointWidth;
uniform float pointHeight;
uniform vec3 center;
varying vec2 texCoord;
void main(void)
{
texCoord = in_TexCoord0.st;
gl_Position = MVPMatrix * vec4(in_Position, 1.0);
set_vp(vec4(center, 1.0));
vec2 transformed = vec2((texCoord.x - 0.5) * pointWidth, (texCoord.y - 0.5) * pointHeight);
gl_Position.xy += transformed * gl_Position.w;
}

View File

@ -10,5 +10,5 @@ void main(void)
float x = in_Position.x * pixelSize;
float y = in_Position.y * pixelSize;
vec3 pos = (x * c - y * s + x0) * u + (x * s + y * c + y0) * v;
gl_Position = MVPMatrix * vec4(pos, 1.0);
set_vp(vec4(pos, 1.0));
}

View File

@ -7,5 +7,5 @@ void main(void)
{
gl_PointSize = in_PointSize;
color = in_Color;
gl_Position = MVPMatrix * vec4(in_Position, 1.0);
set_vp(vec4(in_Position, 1.0));
}

View File

@ -9,7 +9,6 @@ varying vec2 texCoord;
void main(void)
{
vec3 p = viewMat * in_Position.xyz * tidalSize;
gl_Position = MVPMatrix * vec4(p, 1.0);
texCoord = in_TexCoord0.st;
set_vp(vec4(p, 1.0));
}

View File

@ -104,7 +104,10 @@ void DSORenderer::process(DeepSkyObject* const &dso,
}
float t = (float)wWidth / (float)wHeight;
pr = Perspective(fov, t, nearZ, farZ);
if (renderer->getProjectionMode() == Renderer::ProjectionMode::FisheyeMode)
pr = Ortho(-t, t, -1.0f, 1.0f, nearZ, farZ);
else
pr = Perspective(fov, t, nearZ, farZ);
}
else
{

View File

@ -225,6 +225,7 @@ void Renderer::renderMarker(MarkerRepresentation::Symbol symbol,
ShaderProperties shadprop;
shadprop.texUsage = ShaderProperties::VertexColors;
shadprop.lightModel = ShaderProperties::UnlitModel;
shadprop.fishEyeOverride = ShaderProperties::FisheyeOverrideModeDisabled;
auto* prog = shaderManager->getShader(shadprop);
if (prog == nullptr)
return;

View File

@ -1352,6 +1352,21 @@ Vector3f Observer::getPickRay(float x, float y) const
return pickDirection.normalized();
}
Vector3f Observer::getPickRayFisheye(float x, float y) const
{
float r = hypot(x, y);
float phi = float(PI) * r;
float sin_phi = sin(phi);
float theta = atan2(y, x);
float newX = sin_phi * cos(theta);
float newY = sin_phi * sin(theta);
float newZ = cos(phi);
Vector3f pickDirection = Vector3f(newX, newY, -newZ);
pickDirection.normalize();
return pickDirection;
}
// Internal method to update the position and orientation of the observer in
// universal coordinates.

View File

@ -135,6 +135,7 @@ public:
void update(double dt, double timeScale);
Eigen::Vector3f getPickRay(float x, float y) const;
Eigen::Vector3f getPickRayFisheye(float x, float y) const;
void orbit(const Selection&, const Eigen::Quaternionf &q);

View File

@ -171,7 +171,7 @@ void Overlay::drawRectangle(const Rect& r)
if (useTexture && r.tex == nullptr)
useTexture = false;
renderer.drawRectangle(r, projection);
renderer.drawRectangle(r, ShaderProperties::FisheyeOverrideModeDisabled, projection);
}
void Overlay::setColor(float r, float g, float b, float a)

View File

@ -63,5 +63,5 @@ void OverlayImage::render(float curr_time, int width, int height)
r.colors[i] = Color(colors[i], colors[i].alpha() * alpha);
}
r.nColors = 4;
renderer->drawRectangle(r, renderer->getOrthoProjectionMatrix());
renderer->drawRectangle(r, ShaderProperties::FisheyeOverrideModeDisabled, renderer->getOrthoProjectionMatrix());
}

View File

@ -70,7 +70,6 @@ void PointStarVertexBuffer::startPoints()
if (prog == nullptr)
return;
prog->use();
prog->setMVPMatrices(renderer.getProjectionMatrix(), renderer.getModelViewMatrix());
unsigned int stride = sizeof(StarVertex);
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);

View File

@ -244,6 +244,7 @@ Renderer::Renderer() :
screenDpi(96),
corrFac(1.12f),
faintestAutoMag45deg(8.0f), //def. 7.0f
projectionMode(ProjectionMode::PerspectiveMode),
#ifndef GL_ES
renderMode(GL_FILL),
#endif
@ -668,6 +669,8 @@ void Renderer::resize(int width, int height)
float Renderer::calcPixelSize(float fovY, float windowHeight)
{
if (getProjectionMode() == ProjectionMode::FisheyeMode)
return 2.0f / windowHeight;
return 2 * (float) tan(degToRad(fovY / 2.0)) / (float) windowHeight;
}
@ -683,6 +686,16 @@ int Renderer::getScreenDpi() const
return screenDpi;
}
int Renderer::getWindowWidth() const
{
return windowWidth;
}
int Renderer::getWindowHeight() const
{
return windowHeight;
}
void Renderer::setScreenDpi(int _dpi)
{
screenDpi = _dpi;
@ -765,6 +778,18 @@ void Renderer::setLabelMode(int _labelMode)
markSettingsChanged();
}
Renderer::ProjectionMode Renderer::getProjectionMode() const
{
return projectionMode;
}
void Renderer::setProjectionMode(ProjectionMode _projectionMode)
{
projectionMode = _projectionMode;
shaderManager->setFisheyeEnabled(projectionMode == ProjectionMode::FisheyeMode);
markSettingsChanged();
}
int Renderer::getOrbitMask() const
{
return orbitMask;
@ -867,7 +892,9 @@ void Renderer::addAnnotation(vector<Annotation>& annotations,
{
GLint view[4] = { 0, 0, windowWidth, windowHeight };
Vector3f win;
if (Project(pos, m_MVPMatrix, view, win))
bool fisheye = projectionMode == ProjectionMode::FisheyeMode;
bool success = fisheye ? ProjectFisheye(pos, m_modelMatrix, m_projMatrix, view, win) : ProjectPerspective(pos, m_MVPMatrix, view, win);
if (success)
{
float depth = pos.x() * m_modelMatrix(2, 0) +
pos.y() * m_modelMatrix(2, 1) +
@ -1357,9 +1384,13 @@ static Vector3d astrocentricPosition(const UniversalCoord& pos,
void Renderer::autoMag(float& faintestMag)
{
float fieldCorr = 2.0f * FOV/(fov + FOV);
faintestMag = (float) (faintestAutoMag45deg * sqrt(fieldCorr));
saturationMag = saturationMagNight * (1.0f + fieldCorr * fieldCorr);
float fieldCorr;
if (getProjectionMode() == ProjectionMode::FisheyeMode)
fieldCorr = 2.0f - 2000.0f / (windowHeight / (screenDpi / 25.4f / 3.78f) + 1000.0f); // larger window height = more stars to display
else
fieldCorr= 2.0f * FOV / (fov + FOV);
faintestMag = (float) (faintestAutoMag45deg * sqrt(fieldCorr));
saturationMag = saturationMagNight * (1.0f + fieldCorr * fieldCorr);
}
@ -1587,7 +1618,11 @@ void Renderer::draw(const Observer& observer,
// Set up the projection and modelview matrices.
// We'll usethem for positioning star and planet labels.
m_projMatrix = Perspective(fov, getAspectRatio(), NEAR_DIST, FAR_DIST);
float aspectRatio = getAspectRatio();
if (getProjectionMode() == Renderer::ProjectionMode::FisheyeMode)
m_projMatrix = Ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, NEAR_DIST, FAR_DIST);
else
m_projMatrix = Perspective(fov, aspectRatio, NEAR_DIST, FAR_DIST);
m_modelMatrix = Affine3f(getCameraOrientation()).matrix();
m_MVPMatrix = m_projMatrix * m_modelMatrix;
@ -1827,51 +1862,46 @@ void renderPoint(const Renderer &renderer,
#endif
}
void renderLargePoint(const Renderer &renderer,
void renderLargePoint(Renderer &renderer,
const Vector3f &position,
const Color &color,
float size,
float pixelSize,
const Matrix3f &cameraOrientation,
const Matrices &mvp)
{
auto *prog = renderer.getShaderManager().getShader("largestar");
if (prog == nullptr)
return;
// Draw billboard for large points
prog->use();
prog->samplerParam("starTex") = 0;
prog->setMVPMatrices(*mvp.projection, *mvp.modelview);
prog->vec4Param("color") = color.toVector4();
prog->vec3Param("center") = position;
prog->floatParam("pointWidth") = size / renderer.getWindowWidth() * 2.0f;
prog->floatParam("pointHeight") = size / renderer.getWindowHeight() * 2.0f;
float distanceAdjust = pixelSize * position.norm() * 0.5f;
size *= distanceAdjust;
auto &vo = renderer.getVertexObject(VOType::LargeStar, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW);
vo.bind();
if (!vo.initialized())
{
const float texCoords[] = {
// texCoords
0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
auto m = renderer.getCameraOrientation().conjugate().toRotationMatrix();
Vector3f v0 = position + (cameraOrientation * Vector3f(-1, -1, 0) * size);
Vector3f v1 = position + (cameraOrientation * Vector3f( 1, -1, 0) * size);
Vector3f v2 = position + (cameraOrientation * Vector3f( 1, 1, 0) * size);
Vector3f v3 = position + (cameraOrientation * Vector3f(-1, 1, 0) * size);
0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
vo.allocate(sizeof(texCoords), texCoords);
vo.setVertices(3, GL_FLOAT, false, 5 * sizeof(float), 0); // Vertices are useless, but required to set somehow on Mac...
vo.setTextureCoords(2, GL_FLOAT, false, 5 * sizeof(float), 3 * sizeof(float));
}
float quadVertices[] = {
// positions // texCoords
v0.x(), v0.y(), v0.z(), 0.0f, 0.0f,
v1.x(), v1.y(), v1.z(), 1.0f, 0.0f,
v2.x(), v2.y(), v2.z(), 1.0f, 1.0f,
v3.x(), v3.y(), v3.z(), 0.0f, 1.0f
};
static GLubyte indices[] = { 0, 1, 2, 0, 2, 3 };
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), quadVertices);
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), quadVertices + 3);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
vo.draw(GL_TRIANGLES, 6);
vo.unbind();
}
@ -1974,7 +2004,7 @@ void Renderer::renderObjectAsPoint(const Vector3f& position,
if (useSprites)
gaussianDiscTex->bind();
if (pointSize > gl::maxPointSize)
renderLargePoint(*this, center, {color, alpha}, pointSize, pixelSize, m, mvp);
renderLargePoint(*this, center, {color, alpha}, pointSize, mvp);
else
renderPoint(*this, center, {color, alpha}, pointSize, useSprites, mvp);
@ -1988,7 +2018,7 @@ void Renderer::renderObjectAsPoint(const Vector3f& position,
{
gaussianGlareTex->bind();
if (glareSize > gl::maxPointSize)
renderLargePoint(*this, center, {color, glareAlpha}, glareSize, pixelSize, m, mvp);
renderLargePoint(*this, center, {color, glareAlpha}, glareSize, mvp);
else
renderPoint(*this, center, {color, glareAlpha}, glareSize, true, mvp);
}
@ -5032,15 +5062,19 @@ Renderer::renderAnnotations(vector<Annotation>::iterator startIter,
// Precompute values that will be used to generate the normalized device z value;
// we're effectively just handling the projection instead of OpenGL. We use an orthographic
// projection matrix in order to get the label text position exactly right but need to mimic
// the depth coordinate generation of a perspective projection.
float d1 = -(farDist + nearDist) / (farDist - nearDist);
float d2 = -2.0f * nearDist * farDist / (farDist - nearDist);
// the depth coordinate generation of a perspective projection. For fisheye, just apply a
// linear transformation since fisheye uses orthographic projection already.
float d0 = farDist - nearDist;
float d1 = -(farDist + nearDist) / d0; // Used in perspective projection
float d2 = -2.0f * nearDist * farDist / d0; // Used in perspective projection
bool fisheye = projectionMode == ProjectionMode::FisheyeMode;
vector<Annotation>::iterator iter = startIter;
for (; iter != endIter && iter->position.z() > nearDist; iter++)
{
// Compute normalized device z
float ndc_z = clamp(d1 + d2 / -iter->position.z(), -1.0f, 1.0f);
float z = fisheye ? (1.0f - (iter->position.z() - nearDist) / d0 * 2.0f) : (d1 + d2 / -iter->position.z());
float ndc_z = clamp(z, -1.0f, 1.0f);
// Offsets to left align label
int labelHOffset = 0;
@ -5400,7 +5434,7 @@ bool Renderer::captureFrame(int x, int y, int w, int h, Renderer::PixelFormat fo
return glGetError() == GL_NO_ERROR;
}
void Renderer::drawRectangle(const Rect &r, const Eigen::Matrix4f& p, const Eigen::Matrix4f& m)
void Renderer::drawRectangle(const Rect &r, int fishEyeOverrideMode, const Eigen::Matrix4f& p, const Eigen::Matrix4f& m)
{
ShaderProperties shadprop;
shadprop.lightModel = ShaderProperties::UnlitModel;
@ -5410,6 +5444,8 @@ void Renderer::drawRectangle(const Rect &r, const Eigen::Matrix4f& p, const Eige
if (r.tex != nullptr)
shadprop.texUsage |= ShaderProperties::DiffuseTexture;
shadprop.fishEyeOverride = fishEyeOverrideMode;
auto *prog = getShaderManager().getShader(shadprop);
if (prog == nullptr)
return;
@ -6062,11 +6098,16 @@ Renderer::renderSolarSystemObjects(const Observer &observer,
// Set up a perspective projection using the current interval's near and
// far clip planes.
Matrix4f proj = Perspective(fov, getAspectRatio(), nearPlaneDistance, farPlaneDistance);
float aspectRatio = getAspectRatio();
Matrix4f proj;
if (getProjectionMode() == Renderer::ProjectionMode::FisheyeMode)
proj = Ortho(-aspectRatio, aspectRatio, -1.0f, 1.0f, nearPlaneDistance, farPlaneDistance);
else
proj = Perspective(fov, aspectRatio, nearPlaneDistance, farPlaneDistance);
Matrices m = { &proj, &m_modelMatrix };
Frustum intervalFrustum(degToRad(fov),
getAspectRatio(),
aspectRatio,
nearPlaneDistance,
farPlaneDistance);

View File

@ -72,7 +72,8 @@ enum class VOType
AxisArrow = 1,
Rectangle = 2,
Terminator = 3,
Count = 4
LargeStar = 4,
Count = 5
};
enum class RenderMode
@ -100,6 +101,12 @@ class Renderer
double linearFadeFraction;
};
enum class ProjectionMode
{
PerspectiveMode = 0,
FisheyeMode = 1
};
#ifdef USE_GLCONTEXT
bool init(GLContext*, int, int, DetailOptions&);
#else
@ -233,6 +240,8 @@ class Renderer
void setRenderFlags(uint64_t);
int getLabelMode() const;
void setLabelMode(int);
ProjectionMode getProjectionMode() const;
void setProjectionMode(ProjectionMode);
float getAmbientLightLevel() const;
void setAmbientLightLevel(float);
float getMinimumOrbitSize() const;
@ -245,6 +254,8 @@ class Renderer
void setOrbitMask(int);
int getScreenDpi() const;
void setScreenDpi(int);
int getWindowWidth() const;
int getWindowHeight() const;
// GL wrappers
void getViewport(int* x, int* y, int* w, int* h) const;
@ -268,7 +279,7 @@ class Renderer
void enableDepthTest() noexcept;
void disableDepthTest() noexcept;
void drawRectangle(const Rect& r, const Eigen::Matrix4f& p, const Eigen::Matrix4f& m = Eigen::Matrix4f::Identity());
void drawRectangle(const Rect& r, int fishEyeOverrideMode, const Eigen::Matrix4f& p, const Eigen::Matrix4f& m = Eigen::Matrix4f::Identity());
void setRenderRegion(int x, int y, int width, int height, bool withScissor = true);
const ColorTemperatureTable* getStarColorTable() const;
@ -758,6 +769,7 @@ class Renderer
float faintestAutoMag45deg;
TextureFont* font[FontCount];
ProjectionMode projectionMode;
int renderMode;
int labelMode;
uint64_t renderFlags;

View File

@ -72,6 +72,28 @@ uniform mat4 MVPMatrix;
invariant gl_Position;
)glsl";
static const char *VPFunction =
"#ifdef FISHEYE\n"
"void set_vp(vec4 in_Position) {\n"
" float PID2 = 1.570796326794896619231322;\n"
" vec4 inPos = ModelViewMatrix * in_Position;\n"
" float l = length(inPos.xy);\n"
" if (l != 0.0)\n{\n"
" float phi = atan(l, -inPos.z);\n"
" float lensR = phi / PID2;\n"
" inPos.xy *= (lensR / l);\n"
" }\n"
" gl_Position = ProjectionMatrix * inPos;\n"
"}\n"
"#else\n"
"void set_vp(vec4 in_Position) {\n"
" gl_Position = MVPMatrix * in_Position;\n"
"}\n"
"#endif\n";
static const char* VertexPosition =
"set_vp(in_Position);\n";
static const char* FragmentHeader = "";
static const char* CommonAttribs = R"glsl(
@ -295,6 +317,11 @@ bool operator<(const ShaderProperties& p0, const ShaderProperties& p1)
if (p1.effects < p0.effects)
return false;
if (p0.fishEyeOverride < p1.fishEyeOverride)
return true;
if (p1.fishEyeOverride < p0.fishEyeOverride)
return false;
return (p0.lightModel < p1.lightModel);
}
@ -1807,6 +1834,11 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
if (props.hasShadowMap())
source += "uniform mat4 ShadowMatrix0;\n";
if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled)
source += "#define FISHEYE\n";
source += VPFunction;
// Begin main() function
source += "\nvoid main(void)\n{\n";
if (props.isViewDependent() || props.hasScattering())
@ -2022,7 +2054,7 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
if (props.hasShadowMap())
source += "shadowTexCoord0 = ShadowMatrix0 * vec4(in_Position.xyz, 1.0);\n";
source += "gl_Position = MVPMatrix * in_Position;\n";
source += VertexPosition;
source += "}\n";
DumpVSSource(source);
@ -2532,7 +2564,7 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
}
}
source += "gl_Position = MVPMatrix * in_Position;\n";
source += VertexPosition;
source += "}\n";
DumpVSSource(source);
@ -2647,6 +2679,11 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
if (props.texUsage & ShaderProperties::DiffuseTexture)
source += "varying vec2 diffTexCoord;\n";
if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled)
source += "#define FISHEYE\n";
source += VPFunction;
source += "\nvoid main(void)\n{\n";
if (props.texUsage & ShaderProperties::DiffuseTexture)
@ -2662,7 +2699,7 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
}
}
source += "gl_Position = MVPMatrix * in_Position;\n";
source += VertexPosition;
source += "}\n";
DumpVSSource(source);
@ -2801,6 +2838,11 @@ ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props)
source += "varying vec3 scatterEx;\n";
source += "varying vec3 eyeDir_obj;\n";
if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled)
source += "#define FISHEYE\n";
source += VPFunction;
// Begin main() function
source += "\nvoid main(void)\n{\n";
source += "float NL;\n";
@ -2810,7 +2852,7 @@ ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props)
source += AtmosphericEffects(props);
source += "eyeDir_obj = eyeDir;\n";
source += "gl_Position = MVPMatrix * in_Position;\n";
source += VertexPosition;
source += "}\n";
DumpVSSource(source);
@ -2909,6 +2951,11 @@ ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props)
source += DeclareVarying("v_Color", Shader_Vector4);
source += DeclareVarying("v_TexCoord0", Shader_Vector2);
if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled)
source += "#define FISHEYE\n";
source += VPFunction;
// Begin main() function
source += "\nvoid main(void)\n{\n";
@ -2933,8 +2980,7 @@ ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props)
if ((props.texUsage & ShaderProperties::PointSprite) != 0)
source += PointSizeCalculation();
source += " gl_Position = MVPMatrix * in_Position;\n";
source += VertexPosition;
source += "}\n";
// End of main()
@ -3035,6 +3081,11 @@ ShaderManager::buildParticleVertexShader(const ShaderProperties& props)
source << "varying vec3 position_obj;\n";
}
if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled)
source << "#define FISHEYE\n";
source << VPFunction;
// Begin main() function
source << "\nvoid main(void)\n{\n";
@ -3065,8 +3116,7 @@ ShaderManager::buildParticleVertexShader(const ShaderProperties& props)
if ((props.texUsage & ShaderProperties::PointSprite) != 0)
source << PointSizeCalculation();
source << " gl_Position = MVPMatrix * in_Position;\n";
source << VertexPosition;
source << "}\n";
// End of main()
@ -3271,8 +3321,7 @@ ShaderManager::buildProgram(const std::string& vs, const std::string& fs)
{
GLProgram* prog = nullptr;
GLShaderStatus status;
string _vs = fmt::sprintf("%s%s%s\n", CommonHeader, VertexHeader, vs);
string _vs = fmt::sprintf("%s%s%s%s%s\n", CommonHeader, VertexHeader, fisheyeEnabled ? "#define FISHEYE\n" : "", VPFunction, vs);
string _fs = fmt::sprintf("%s%s%s\n", CommonHeader, FragmentHeader, fs);
DumpVSSource(_vs);
@ -3348,6 +3397,11 @@ ShaderManager::buildProgram(const std::string& vs, const std::string& fs)
return new CelestiaGLProgram(*prog);
}
void ShaderManager::setFisheyeEnabled(bool enabled)
{
fisheyeEnabled = enabled;
}
CelestiaGLProgram::CelestiaGLProgram(GLProgram& _program,
const ShaderProperties& _props) :
program(&_program),
@ -3383,7 +3437,6 @@ CelestiaGLProgram::intParam(const string& paramName)
return IntegerShaderParameter(program->getID(), paramName.c_str());
}
IntegerShaderParameter
CelestiaGLProgram::samplerParam(const string& paramName)
{
@ -3788,4 +3841,3 @@ CelestiaGLProgram::setMVPMatrices(const Matrix4f& p, const Matrix4f& m)
ModelViewMatrix = m;
MVPMatrix = p * m;
}

View File

@ -19,7 +19,6 @@
#define ADVANCED_CLOUD_SHADOWS 0
class ShaderProperties
{
public:
@ -90,6 +89,13 @@ class ShaderProperties
VolumetricEmissionEffect = 0x0004,
};
enum
{
FisheyeOverrideModeNone = 0,
FisheyeOverrideModeEnabled = 1,
FisheyeOverrideModeDisabled = 2,
};
public:
unsigned short nLights{ 0 };
unsigned short texUsage{ 0 };
@ -106,6 +112,8 @@ class ShaderProperties
// Bit 4, on for cloud shadows
uint32_t shadowCounts{ 0 };
int fishEyeOverride { FisheyeOverrideModeNone };
private:
enum
{
@ -292,6 +300,8 @@ class ShaderManager
CelestiaGLProgram* getShader(const std::string&);
CelestiaGLProgram* getShader(const std::string&, const std::string&, const std::string&);
void setFisheyeEnabled(bool enabled);
private:
CelestiaGLProgram* buildProgram(const ShaderProperties&);
CelestiaGLProgram* buildProgram(const std::string&, const std::string&);
@ -313,6 +323,8 @@ class ShaderManager
std::map<ShaderProperties, CelestiaGLProgram*> dynamicShaders;
std::map<std::string, CelestiaGLProgram*> staticShaders;
bool fisheyeEnabled { false };
};
#endif // _CELENGINE_SHADERMANAGER_H_

View File

@ -80,7 +80,8 @@ static const float RotationDecay = 2.0f;
static const double MaximumTimeRate = 1.0e15;
static const double MinimumTimeRate = 1.0e-15;
static const float stdFOV = degToRad(45.0f);
static const float MaximumFOV = degToRad(120.0f);
static const float MaximumFOVPerspective = degToRad(120.0f);
static const float MaximumFOVFisheye = degToRad(179.99f);
static const float MinimumFOV = degToRad(0.001f);
static float KeyRotationAccel = degToRad(120.0f);
static float MouseRotationSensitivity = degToRad(1.0f);
@ -430,7 +431,7 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
if (isViewportEffectUsed)
viewportEffect->distortXY(pickX, pickY);
Vector3f pickRay = sim->getActiveObserver()->getPickRay(pickX, pickY);
Vector3f pickRay = renderer->getProjectionMode() == Renderer::ProjectionMode::FisheyeMode ? sim->getActiveObserver()->getPickRayFisheye(pickX, pickY) : sim->getActiveObserver()->getPickRay(pickX, pickY);
Selection oldSel = sim->getSelection();
Selection newSel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
@ -450,7 +451,7 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
if (isViewportEffectUsed)
viewportEffect->distortXY(pickX, pickY);
Vector3f pickRay = sim->getActiveObserver()->getPickRay(pickX, pickY);
Vector3f pickRay = renderer->getProjectionMode() == Renderer::ProjectionMode::FisheyeMode ? sim->getActiveObserver()->getPickRayFisheye(pickX, pickY) : sim->getActiveObserver()->getPickRay(pickX, pickY);
Selection sel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
if (!sel.empty())
@ -632,7 +633,7 @@ void CelestiaCore::mouseMove(float dx, float dy, int modifiers)
// Mouse zoom control
float amount = dy / height;
float minFOV = MinimumFOV;
float maxFOV = MaximumFOV;
float maxFOV = getMaximumFOV();
float fov = sim->getActiveObserver()->getFOV();
// In order for the zoom to have the right feel, it should be
@ -1388,7 +1389,7 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers)
case '.':
addToHistory();
if (observer->getFOV() < MaximumFOV)
if (observer->getFOV() < getMaximumFOV())
{
observer->setFOV(observer->getFOV() * 1.05f);
setZoomFromFOV();
@ -2279,13 +2280,26 @@ void CelestiaCore::splitView(View::Type type, View* av, float splitPos)
flash(_("Added view"));
}
float CelestiaCore::getMaximumFOV() const
{
if (renderer->getProjectionMode() == Renderer::ProjectionMode::FisheyeMode)
return MaximumFOVFisheye;
else
return MaximumFOVPerspective;
}
void CelestiaCore::setFOVFromZoom()
{
for (const auto v : views)
if (v->type == View::ViewWindow)
{
double fov = 2 * atan(height * v->height / (screenDpi / 25.4) / 2. / distanceToScreen) / v->zoom;
v->observer->setFOV((float) fov);
if (renderer->getProjectionMode() == Renderer::ProjectionMode::FisheyeMode)
v->observer->setFOV(MaximumFOVFisheye);
else
{
double fov = 2 * atan(height * v->height / (screenDpi / 25.4) / 2. / distanceToScreen) / v->zoom;
v->observer->setFOV((float) fov);
}
}
}
@ -3841,6 +3855,16 @@ bool CelestiaCore::initSimulation(const fs::path& configFileName,
}
}
if (!config->projectionMode.empty())
{
if (config->projectionMode == "perspective")
renderer->setProjectionMode(Renderer::ProjectionMode::PerspectiveMode);
else if (config->projectionMode == "fisheye")
renderer->setProjectionMode(Renderer::ProjectionMode::FisheyeMode);
else
DPRINTF(LOG_LEVEL_WARNING, "Unknown projection mode %s\n", config->projectionMode);
}
if (!config->viewportEffect.empty() && config->viewportEffect != "none")
{
if (config->viewportEffect == "passthrough")

View File

@ -289,6 +289,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
float getPickTolerance() const;
void setPickTolerance(float);
float getMaximumFOV() const;
void setFOVFromZoom();
void setZoomFromFOV();

View File

@ -93,6 +93,7 @@ CelestiaConfig* ReadCelestiaConfig(const fs::path& filename, CelestiaConfig *con
configParams->getString("TitleFont", config->titleFont);
configParams->getPath("LogoTexture", config->logoTextureFile);
configParams->getString("Cursor", config->cursor);
configParams->getString("ProjectionMode", config->projectionMode);
configParams->getString("ViewportEffect", config->viewportEffect);
configParams->getString("WarpMeshFile", config->warpMeshFile);

View File

@ -79,6 +79,7 @@ public:
float SolarSystemMaxDistance;
unsigned ShadowMapSize;
std::string projectionMode;
std::string viewportEffect;
std::string warpMeshFile;
};

View File

@ -256,7 +256,7 @@ void View::drawBorder(int gWidth, int gHeight, const Color &color, float linewid
r.setColor(color);
r.setType(Rect::Type::BorderOnly);
r.setLineWidth(linewidth);
renderer->drawRectangle(r, renderer->getOrthoProjectionMatrix());
renderer->drawRectangle(r, ShaderProperties::FisheyeOverrideModeDisabled, renderer->getOrthoProjectionMatrix());
}
void View::updateFBO(int gWidth, int gHeight)

View File

@ -65,10 +65,10 @@ LookAt(const Eigen::Matrix<T, 3, 1>& from, const Eigen::Matrix<T, 3, 1>& to, con
/*! Project to screen space
*/
template<class T> bool
Project(const Eigen::Matrix<T, 3, 1>& from,
const Eigen::Matrix<T, 4, 4>& modelViewProjectionMatrix,
const int viewport[4],
Eigen::Matrix<T, 3, 1>& to)
ProjectPerspective(const Eigen::Matrix<T, 3, 1>& from,
const Eigen::Matrix<T, 4, 4>& modelViewProjectionMatrix,
const int viewport[4],
Eigen::Matrix<T, 3, 1>& to)
{
Eigen::Matrix<T, 4, 1> in(from.x(), from.y(), from.z(), T(1.0));
Eigen::Matrix<T, 4, 1> out = modelViewProjectionMatrix * in;
@ -87,16 +87,48 @@ Project(const Eigen::Matrix<T, 3, 1>& from,
}
template<class T> bool
Project(const Eigen::Matrix<T, 3, 1>& from,
const Eigen::Matrix<T, 4, 4>& modelViewMatrix,
const Eigen::Matrix<T, 4, 4>& projMatrix,
const int viewport[4],
Eigen::Matrix<T, 3, 1>& to)
ProjectPerspective(const Eigen::Matrix<T, 3, 1>& from,
const Eigen::Matrix<T, 4, 4>& modelViewMatrix,
const Eigen::Matrix<T, 4, 4>& projMatrix,
const int viewport[4],
Eigen::Matrix<T, 3, 1>& to)
{
Eigen::Matrix<T, 4, 4> m = projMatrix * modelViewMatrix;
return Project(from, m, viewport, to);
}
template<class T> bool
ProjectFisheye(const Eigen::Matrix<T, 3, 1>& from,
const Eigen::Matrix<T, 4, 4>& modelViewMatrix,
const Eigen::Matrix<T, 4, 4>& projMatrix,
const int viewport[4],
Eigen::Matrix<T, 3, 1>& to)
{
Eigen::Matrix<T, 4, 1> inPos = modelViewMatrix * Eigen::Matrix<T, 4, 1>(from.x(), from.y(), from.z(), T(1.0));
T l = hypot(inPos.x(), inPos.y());
if (l != T(0.0))
{
T phi = atan2(l, -inPos.z());
T ratio = phi / T(M_PI_2) / l;
inPos.x() *= ratio;
inPos.y() *= ratio;
}
Eigen::Matrix<T, 4, 1> out = projMatrix * inPos;
if (out.w() == T(0.0))
return false;
out = out.array() / out.w();
// Map x, y and z to range 0-1
out = T(0.5) + out.array() * T(0.5);
// Map x,y to viewport
out.x() = viewport[0] + out.x() * viewport[2];
out.y() = viewport[1] + out.y() * viewport[3];
to = { out.x(), out.y(), out.z() };
return true;
}
/*! Return an perspective projection matrix
*/