Refactored some shadowing/eclipse code in the renderer
- Enabled ring shadows on moons and other objects that aren't themselves surrounded by ring systems. - Use texture LOD bias to add blurriness to ring shadows (a result of the finite size of the light source.) - Calculate ring phase function per-pixel instead of per-vertex - Implemented more realistic rendering of unlit side of ring systems - Used new Eigen's NewStdVector for vectors containing fixed-sized vectorizable objects.sensor-dev
parent
7e9429ed45
commit
dcf9232c08
|
@ -8,24 +8,22 @@
|
|||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#include <Eigen/StdVector>
|
||||
#include "render.h"
|
||||
#include "celestia.h"
|
||||
#include "astro.h"
|
||||
#include "galaxy.h"
|
||||
#include "vecgl.h"
|
||||
#include "texture.h"
|
||||
#include <celmath/mathlib.h>
|
||||
#include <celmath/perlin.h>
|
||||
#include <celmath/intersect.h>
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/debug.h>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include "celestia.h"
|
||||
#include <celmath/mathlib.h>
|
||||
#include <celmath/perlin.h>
|
||||
#include <celmath/intersect.h>
|
||||
#include "astro.h"
|
||||
#include "galaxy.h"
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/debug.h>
|
||||
#include <GL/glew.h>
|
||||
#include "vecgl.h"
|
||||
#include "render.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
@ -52,10 +50,11 @@ bool operator< (const Blob& b1, const Blob& b2)
|
|||
return (b1.position.squaredNorm() < b2.position.squaredNorm());
|
||||
}
|
||||
|
||||
typedef vector<Blob, aligned_allocator<Blob> > BlobVector;
|
||||
class GalacticForm
|
||||
{
|
||||
public:
|
||||
vector<Blob>* blobs;
|
||||
BlobVector* blobs;
|
||||
Vector3f scale;
|
||||
};
|
||||
|
||||
|
@ -344,7 +343,7 @@ void Galaxy::renderGalaxyPointSprites(const GLContext&,
|
|||
|
||||
int pow2 = 1;
|
||||
|
||||
vector<Blob>* points = form->blobs;
|
||||
BlobVector* points = form->blobs;
|
||||
unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail()));
|
||||
// corrections to avoid excessive brightening if viewed e.g. edge-on
|
||||
|
||||
|
@ -520,7 +519,7 @@ void Galaxy::setLightGain(float lg)
|
|||
GalacticForm* buildGalacticForms(const std::string& filename)
|
||||
{
|
||||
Blob b;
|
||||
vector<Blob>* galacticPoints = new vector<Blob>;
|
||||
BlobVector* galacticPoints = new BlobVector;
|
||||
|
||||
// Load templates in standard .png format
|
||||
int width, height, rgb, j = 0, kmin = 9;
|
||||
|
@ -674,7 +673,7 @@ void InitializeForms()
|
|||
Blob b;
|
||||
Point3f p;
|
||||
|
||||
vector<Blob>* irregularPoints = new vector<Blob>;
|
||||
BlobVector* irregularPoints = new BlobVector;
|
||||
irregularPoints->reserve(galaxySize);
|
||||
|
||||
while (ip < galaxySize)
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#ifndef _CELENGINE_GLCONTEXT_H_
|
||||
#define _CELENGINE_GLCONTEXT_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <celengine/vertexprog.h>
|
||||
#include <celengine/fragmentprog.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class GLContext
|
||||
{
|
||||
|
|
|
@ -15,10 +15,14 @@
|
|||
|
||||
#include <celutil/color.h>
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <vector>
|
||||
|
||||
static const unsigned int MaxLights = 8;
|
||||
|
||||
class Body;
|
||||
class RingSystem;
|
||||
|
||||
class DirectionalLight
|
||||
{
|
||||
public:
|
||||
|
@ -37,6 +41,10 @@ public:
|
|||
class EclipseShadow
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
const Body* caster;
|
||||
Eigen::Quaternionf casterOrientation;
|
||||
Eigen::Vector3f origin;
|
||||
Eigen::Vector3f direction;
|
||||
float penumbraRadius;
|
||||
|
@ -44,18 +52,45 @@ public:
|
|||
float maxDepth;
|
||||
};
|
||||
|
||||
class RingShadow
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
RingSystem* ringSystem;
|
||||
Eigen::Quaternionf casterOrientation;
|
||||
Eigen::Vector3f origin;
|
||||
Eigen::Vector3f direction;
|
||||
float texLod;
|
||||
};
|
||||
|
||||
class LightingState
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
typedef std::vector<EclipseShadow, Eigen::aligned_allocator<EclipseShadow> > EclipseShadowVector;
|
||||
|
||||
LightingState() :
|
||||
nLights(0),
|
||||
shadowingRingSystem(NULL),
|
||||
eyeDir_obj(-Eigen::Vector3f::UnitZ()),
|
||||
eyePos_obj(-Eigen::Vector3f::UnitZ())
|
||||
{ shadows[0] = NULL; };
|
||||
{
|
||||
shadows[0] = NULL;
|
||||
for (unsigned int i = 0; i < MaxLights; ++i)
|
||||
{
|
||||
ringShadows[i].ringSystem = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int nLights;
|
||||
DirectionalLight lights[MaxLights];
|
||||
std::vector<EclipseShadow>* shadows[MaxLights];
|
||||
EclipseShadowVector* shadows[MaxLights];
|
||||
RingShadow ringShadows[MaxLights];
|
||||
RingSystem* shadowingRingSystem; // NULL when there are no ring shadows
|
||||
Eigen::Vector3f ringPlaneNormal;
|
||||
Eigen::Vector3f ringCenter;
|
||||
|
||||
Eigen::Vector3f eyeDir_obj;
|
||||
Eigen::Vector3f eyePos_obj;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
#include "rendcontext.h"
|
||||
#include "texmanager.h"
|
||||
#include "body.h"
|
||||
#include <GL/glew.h>
|
||||
#include "vecgl.h"
|
||||
|
||||
|
@ -554,8 +555,8 @@ GLSL_RenderContext::initLightingEnvironment()
|
|||
{
|
||||
if (lightingState.shadows[li] && !lightingState.shadows[li]->empty())
|
||||
{
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderShadows, lightingState.shadows[li]->size());
|
||||
shaderProps.setShadowCountForLight(li, nShadows);
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, lightingState.shadows[li]->size());
|
||||
shaderProps.setEclipseShadowCountForLight(li, nShadows);
|
||||
totalShadows += nShadows;
|
||||
}
|
||||
}
|
||||
|
@ -646,6 +647,38 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
|
|||
}
|
||||
}
|
||||
|
||||
if (lightingState.shadowingRingSystem)
|
||||
{
|
||||
Texture* ringsTex = lightingState.shadowingRingSystem->texture.find(medres);
|
||||
if (ringsTex != NULL)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
|
||||
ringsTex->bind();
|
||||
textures[nTextures++] = ringsTex;
|
||||
|
||||
// Tweak the texture--set clamp to border and a border color with
|
||||
// a zero alpha.
|
||||
float bc[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bc);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
shaderProps.texUsage |= ShaderProperties::RingShadowTexture;
|
||||
for (unsigned int lightIndex = 0; lightIndex < lightingState.nLights; lightIndex++)
|
||||
{
|
||||
if (lightingState.lights[lightIndex].castsShadows &&
|
||||
lightingState.shadowingRingSystem == lightingState.ringShadows[lightIndex].ringSystem)
|
||||
{
|
||||
shaderProps.setRingShadowForLight(lightIndex, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderProps.setRingShadowForLight(lightIndex, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usePointSize)
|
||||
shaderProps.texUsage |= ShaderProperties::PointSprite;
|
||||
if (useColors)
|
||||
|
@ -681,7 +714,7 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
|
|||
|
||||
prog->setLightParameters(lightingState, diffuse, m.specular, m.emissive);
|
||||
|
||||
if (shaderProps.shadowCounts != 0)
|
||||
if (shaderProps.hasEclipseShadows() != 0)
|
||||
prog->setEclipseShadowParameters(lightingState, objRadius, objOrientation);
|
||||
|
||||
// TODO: handle emissive color
|
||||
|
@ -710,6 +743,25 @@ GLSL_RenderContext::makeCurrent(const Mesh::Material& m)
|
|||
prog->pointScale = getPointScale();
|
||||
}
|
||||
|
||||
// Ring shadow parameters
|
||||
if ((shaderProps.texUsage & ShaderProperties::RingShadowTexture) != 0)
|
||||
{
|
||||
const RingSystem* rings = lightingState.shadowingRingSystem;
|
||||
float ringWidth = rings->outerRadius - rings->innerRadius;
|
||||
prog->ringRadius = rings->innerRadius / objRadius;
|
||||
prog->ringWidth = objRadius / ringWidth;
|
||||
prog->ringPlane = Hyperplane<float, 3>(lightingState.ringPlaneNormal, lightingState.ringCenter / objRadius).coeffs();
|
||||
prog->ringCenter = lightingState.ringCenter / objRadius;
|
||||
|
||||
for (unsigned int lightIndex = 0; lightIndex < lightingState.nLights; ++lightIndex)
|
||||
{
|
||||
if (shaderProps.hasRingShadowForLight(lightIndex))
|
||||
{
|
||||
prog->ringShadowLOD[lightIndex] = lightingState.ringShadows[lightIndex].texLod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mesh::BlendMode newBlendMode = Mesh::InvalidBlend;
|
||||
if (m.opacity != 1.0f ||
|
||||
m.blend == Mesh::AdditiveBlend ||
|
||||
|
|
|
@ -39,6 +39,7 @@ std::ofstream hdrlog;
|
|||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "render.h"
|
||||
#include "boundaries.h"
|
||||
#include "asterism.h"
|
||||
#include "astro.h"
|
||||
|
@ -52,7 +53,6 @@ std::ofstream hdrlog;
|
|||
#include "vertexprog.h"
|
||||
#include "texmanager.h"
|
||||
#include "meshmanager.h"
|
||||
#include "render.h"
|
||||
#include "renderinfo.h"
|
||||
#include "renderglsl.h"
|
||||
#include "axisarrow.h"
|
||||
|
@ -6058,7 +6058,7 @@ static void renderRings(RingSystem& rings,
|
|||
|
||||
static void
|
||||
renderEclipseShadows(Geometry* geometry,
|
||||
vector<EclipseShadow>& eclipseShadows,
|
||||
LightingState::EclipseShadowVector& eclipseShadows,
|
||||
RenderInfo& ri,
|
||||
float planetRadius,
|
||||
Quaternionf& planetOrientation,
|
||||
|
@ -6072,7 +6072,7 @@ renderEclipseShadows(Geometry* geometry,
|
|||
if (geometry != NULL)
|
||||
return;
|
||||
|
||||
for (vector<EclipseShadow>::iterator iter = eclipseShadows.begin();
|
||||
for (LightingState::EclipseShadowVector::iterator iter = eclipseShadows.begin();
|
||||
iter != eclipseShadows.end(); iter++)
|
||||
{
|
||||
EclipseShadow shadow = *iter;
|
||||
|
@ -6192,7 +6192,7 @@ renderEclipseShadows(Geometry* geometry,
|
|||
|
||||
static void
|
||||
renderEclipseShadows_Shaders(Geometry* geometry,
|
||||
vector<EclipseShadow>& eclipseShadows,
|
||||
LightingState::EclipseShadowVector& eclipseShadows,
|
||||
RenderInfo& ri,
|
||||
float planetRadius,
|
||||
const Quaternionf& planetOrientation,
|
||||
|
@ -6216,7 +6216,7 @@ renderEclipseShadows_Shaders(Geometry* geometry,
|
|||
Vector4f shadowParams[4];
|
||||
|
||||
int n = 0;
|
||||
for (vector<EclipseShadow>::iterator iter = eclipseShadows.begin();
|
||||
for (LightingState::EclipseShadowVector::iterator iter = eclipseShadows.begin();
|
||||
iter != eclipseShadows.end() && n < 4; iter++, n++)
|
||||
{
|
||||
EclipseShadow shadow = *iter;
|
||||
|
@ -6700,7 +6700,8 @@ setupObjectLighting(const vector<LightSource>& suns,
|
|||
ls.nLights++;
|
||||
}
|
||||
|
||||
ls.eyePos_obj = m * -(objPosition_eye.cwise() / objScale);
|
||||
Matrix3f invScale = objScale.cwise().inverse().asDiagonal();
|
||||
ls.eyePos_obj = invScale * m * -objPosition_eye;
|
||||
ls.eyeDir_obj = (m * -objPosition_eye).normalized();
|
||||
|
||||
// When the camera is very far from the object, some view-dependent
|
||||
|
@ -6732,8 +6733,7 @@ void Renderer::renderObject(const Vector3f& pos,
|
|||
RenderInfo ri;
|
||||
|
||||
float altitude = distance - obj.radius;
|
||||
float discSizeInPixels = obj.radius /
|
||||
(max(nearPlaneDistance, altitude) * pixelSize);
|
||||
float discSizeInPixels = obj.radius / (max(nearPlaneDistance, altitude) * pixelSize);
|
||||
|
||||
ri.sunDir_eye = Vector3f::UnitY();
|
||||
ri.sunDir_obj = Vector3f::UnitY();
|
||||
|
@ -6967,7 +6967,7 @@ void Renderer::renderObject(const Vector3f& pos,
|
|||
switch (context->getRenderPath())
|
||||
{
|
||||
case GLContext::GLPath_GLSL:
|
||||
renderSphere_GLSL(ri, ls, obj.rings,
|
||||
renderSphere_GLSL(ri, ls,
|
||||
const_cast<Atmosphere*>(obj.atmosphere), cloudTexOffset,
|
||||
obj.radius,
|
||||
textureResolution,
|
||||
|
@ -7185,7 +7185,6 @@ void Renderer::renderObject(const Vector3f& pos,
|
|||
cloudTex,
|
||||
cloudNormalMap,
|
||||
cloudTexOffset,
|
||||
obj.rings,
|
||||
radius,
|
||||
textureResolution,
|
||||
renderFlags,
|
||||
|
@ -7332,10 +7331,14 @@ void Renderer::renderObject(const Vector3f& pos,
|
|||
|
||||
bool Renderer::testEclipse(const Body& receiver,
|
||||
const Body& caster,
|
||||
const DirectionalLight& light,
|
||||
double now,
|
||||
vector<EclipseShadow>& shadows)
|
||||
LightingState& lightingState,
|
||||
unsigned int lightIndex,
|
||||
double now)
|
||||
{
|
||||
const DirectionalLight& light = lightingState.lights[lightIndex];
|
||||
LightingState::EclipseShadowVector& shadows = *lightingState.shadows[lightIndex];
|
||||
bool isReceiverShadowed = false;
|
||||
|
||||
// Ignore situations where the shadow casting body is much smaller than
|
||||
// the receiver, as these shadows aren't likely to be relevant. Also,
|
||||
// ignore eclipses where the caster is not an ellipsoid, since we can't
|
||||
|
@ -7411,16 +7414,65 @@ bool Renderer::testEclipse(const Body& receiver,
|
|||
shadow.umbraRadius = caster.getRadius() *
|
||||
(appOccluderRadius - appSunRadius) / appOccluderRadius;
|
||||
shadow.maxDepth = std::min(1.0f, square(appOccluderRadius / appSunRadius));
|
||||
shadow.caster = &caster;
|
||||
|
||||
// Ignore transits that don't produce a visible shadow.
|
||||
if (shadow.maxDepth > 1.0f / 256.0f)
|
||||
shadows.push_back(shadow);
|
||||
|
||||
return true;
|
||||
isReceiverShadowed = true;
|
||||
}
|
||||
|
||||
// If the caster has a ring system, see if it casts a shadow on the receiver.
|
||||
// Ring shadows are only supported in the OpenGL 2.0 path.
|
||||
if (caster.getRings() && context->getRenderPath() == GLContext::GLPath_GLSL)
|
||||
{
|
||||
bool shadowed = false;
|
||||
|
||||
// The shadow volume of the rings is an oblique circular cylinder
|
||||
if (dist < caster.getRings()->outerRadius + receiver.getRadius())
|
||||
{
|
||||
// Possible intersection, but it depends on the orientation of the
|
||||
// rings.
|
||||
Quaterniond casterOrientation = caster.getOrientation(now);
|
||||
Vector3d ringPlaneNormal = casterOrientation * Vector3d::UnitY();
|
||||
Vector3d shadowDirection = lightToCasterDir.normalized();
|
||||
Vector3d v = ringPlaneNormal.cross(shadowDirection);
|
||||
if (v.squaredNorm() < 1.0e-6)
|
||||
{
|
||||
// Shadow direction is nearly coincident with ring plane normal, so
|
||||
// the shadow cross section is close to circular. No additional test
|
||||
// is required.
|
||||
shadowed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// minDistance is the cross section of the ring shadows in the plane
|
||||
// perpendicular to the ring plane and containing the light direction.
|
||||
Vector3d shadowPlaneNormal = v.normalized().cross(shadowDirection);
|
||||
Hyperplane<double, 3> shadowPlane(shadowPlaneNormal, posCaster - posReceiver);
|
||||
double minDistance = receiver.getRadius() +
|
||||
caster.getRings()->outerRadius * ringPlaneNormal.dot(shadowDirection);
|
||||
if (abs(shadowPlane.signedDistance(Vector3d::Zero())) < minDistance)
|
||||
{
|
||||
// TODO: Implement this test and only set shadowed to true if it passes
|
||||
}
|
||||
shadowed = true;
|
||||
}
|
||||
|
||||
if (shadowed)
|
||||
{
|
||||
RingShadow& shadow = lightingState.ringShadows[lightIndex];
|
||||
shadow.origin = dir.cast<float>();
|
||||
shadow.direction = shadowDirection.cast<float>();
|
||||
shadow.ringSystem = caster.getRings();
|
||||
shadow.casterOrientation = casterOrientation.cast<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return isReceiverShadowed;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7511,6 +7563,18 @@ void Renderer::renderPlanet(Body& body,
|
|||
}
|
||||
|
||||
|
||||
// Add ring shadow records for each light
|
||||
if (body.getRings() && ShowRingShadows)
|
||||
{
|
||||
for (unsigned int li = 0; li < lights.nLights; li++)
|
||||
{
|
||||
lights.ringShadows[li].ringSystem = body.getRings();
|
||||
lights.ringShadows[li].casterOrientation = q.cast<float>();
|
||||
lights.ringShadows[li].origin = Vector3f::Zero();
|
||||
lights.ringShadows[li].direction = -lights.lights[li].position.normalized().cast<float>();
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate eclipse circumstances
|
||||
if ((renderFlags & ShowEclipseShadows) != 0 &&
|
||||
body.getSystem() != NULL)
|
||||
|
@ -7532,9 +7596,7 @@ void Renderer::renderPlanet(Body& body,
|
|||
{
|
||||
for (int i = 0; i < nSatellites; i++)
|
||||
{
|
||||
testEclipse(body, *satellites->getBody(i),
|
||||
lights.lights[li],
|
||||
now, *lights.shadows[li]);
|
||||
testEclipse(body, *satellites->getBody(i), lights, li, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7554,8 +7616,7 @@ void Renderer::renderPlanet(Body& body,
|
|||
Body* planet = system->getPrimaryBody();
|
||||
while (planet != NULL)
|
||||
{
|
||||
testEclipse(body, *planet, lights.lights[li],
|
||||
now, *lights.shadows[li]);
|
||||
testEclipse(body, *planet, lights, li, now);
|
||||
if (planet->getSystem() != NULL)
|
||||
planet = planet->getSystem()->getPrimaryBody();
|
||||
else
|
||||
|
@ -7567,9 +7628,7 @@ void Renderer::renderPlanet(Body& body,
|
|||
{
|
||||
if (system->getBody(i) != &body)
|
||||
{
|
||||
testEclipse(body, *system->getBody(i),
|
||||
lights.lights[li],
|
||||
now, *lights.shadows[li]);
|
||||
testEclipse(body, *system->getBody(i), lights, li, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7577,6 +7636,95 @@ void Renderer::renderPlanet(Body& body,
|
|||
}
|
||||
}
|
||||
|
||||
// Sort out the ring shadows; only one ring shadow source is supported right now. This means
|
||||
// that exotic cases with shadows from two ring different ring systems aren't handled.
|
||||
for (unsigned int li = 0; li < lights.nLights; li++)
|
||||
{
|
||||
if (lights.ringShadows[li].ringSystem != NULL)
|
||||
{
|
||||
RingSystem* rings = lights.ringShadows[li].ringSystem;
|
||||
|
||||
// Use the first set of ring shadows found (shadowing the brightest light
|
||||
// source.)
|
||||
if (lights.shadowingRingSystem == NULL)
|
||||
{
|
||||
lights.shadowingRingSystem = rings;
|
||||
lights.ringPlaneNormal = (rp.orientation * lights.ringShadows[li].casterOrientation.conjugate()) * Vector3f::UnitY();
|
||||
lights.ringCenter = rp.orientation * lights.ringShadows[li].origin;
|
||||
}
|
||||
|
||||
// Light sources have a finite size, which causes some blurring of the texture. Simulate
|
||||
// this effect by using a lower LOD (i.e. a smaller mipmap level, indicated somewhat
|
||||
// confusingly by a _higher_ LOD value.
|
||||
float ringWidth = rings->outerRadius - rings->innerRadius;
|
||||
float projectedRingSize = std::abs(lights.lights[li].direction_obj.dot(lights.ringPlaneNormal)) * ringWidth;
|
||||
float projectedRingSizeInPixels = projectedRingSize / (max(nearPlaneDistance, altitude) * pixelSize);
|
||||
Texture* ringsTex = rings->texture.find(textureResolution);
|
||||
if (ringsTex)
|
||||
{
|
||||
// Calculate the approximate distance from the shadowed object to the rings
|
||||
Hyperplane<float, 3> ringPlane(lights.ringPlaneNormal, lights.ringCenter);
|
||||
float cosLightAngle = lights.lights[li].direction_obj.dot(ringPlane.normal());
|
||||
float approxRingDistance = rings->innerRadius;
|
||||
if (abs(cosLightAngle) < 0.99999f)
|
||||
{
|
||||
approxRingDistance = abs(ringPlane.offset() / cosLightAngle);
|
||||
}
|
||||
if (lights.ringCenter.norm() < rings->innerRadius)
|
||||
{
|
||||
approxRingDistance = max(approxRingDistance, rings->innerRadius - lights.ringCenter.norm());
|
||||
}
|
||||
|
||||
// Calculate the LOD based on the size of the smallest
|
||||
// ring feature relative to the apparent size of the light source.
|
||||
float ringTextureWidth = ringsTex->getWidth();
|
||||
float ringFeatureSize = (projectedRingSize / ringTextureWidth) / approxRingDistance;
|
||||
float relativeFeatureSize = lights.lights[li].apparentSize / ringFeatureSize;
|
||||
//float areaLightLod = log(max(relativeFeatureSize, 1.0f)) / log(2.0f);
|
||||
float areaLightLod = celmath::log2(max(relativeFeatureSize, 1.0f));
|
||||
|
||||
// Compute the LOD that would be automatically used by the GPU.
|
||||
float texelToPixelRatio = ringTextureWidth / projectedRingSizeInPixels;
|
||||
float gpuLod = celmath::log2(texelToPixelRatio);
|
||||
|
||||
//float lod = max(areaLightLod, log(texelToPixelRatio) / log(2.0f));
|
||||
float lod = max(areaLightLod, gpuLod);
|
||||
|
||||
// maxLOD is the index of the smallest mipmap (or close to it for non-power-of-two
|
||||
// textures.) We can't make the lod larger than this.
|
||||
float maxLod = celmath::log2((float) ringsTex->getWidth());
|
||||
if (maxLod > 1.0f)
|
||||
{
|
||||
// Avoid using the 1x1 mipmap, as it appears to cause 'bleeding' when
|
||||
// the light source is very close to the ring plane. This is probably
|
||||
// a numerical precision issue from calculating the intersection of
|
||||
// between a ray and plane that are nearly parallel.
|
||||
maxLod -= 1.0f;
|
||||
}
|
||||
lod = min(lod, maxLod);
|
||||
|
||||
// Not all hardware/drivers support GLSL's textureXDLOD instruction, which lets
|
||||
// us explicitly set the LOD. But, they do all have an optional lodBias parameter
|
||||
// for the textureXD instruction. The bias is just the difference between the
|
||||
// area light LOD and the approximate GPU calculated LOD.
|
||||
float lodBias = max(0.0f, lod - gpuLod);
|
||||
|
||||
if (GLEW_ARB_shader_texture_lod)
|
||||
{
|
||||
lights.ringShadows[li].texLod = lod;
|
||||
}
|
||||
else
|
||||
{
|
||||
lights.ringShadows[li].texLod = lodBias;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lights.ringShadows[li].texLod = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderObject(pos, distance, now,
|
||||
cameraOrientation, nearPlaneDistance, farPlaneDistance,
|
||||
rp, lights);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef _CELENGINE_RENDER_H_
|
||||
#define _CELENGINE_RENDER_H_
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/NewStdVector>
|
||||
#include <celmath/frustum.h>
|
||||
#include <celengine/universe.h>
|
||||
#include <celengine/observer.h>
|
||||
|
@ -19,7 +21,6 @@
|
|||
#include <celengine/starcolors.h>
|
||||
#include <celengine/rendcontext.h>
|
||||
#include <celtxf/texturefont.h>
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
@ -366,7 +367,7 @@ class Renderer
|
|||
Eigen::Vector3f semiAxes;
|
||||
ResourceHandle geometry;
|
||||
Eigen::Quaternionf orientation;
|
||||
std::vector<EclipseShadow>* eclipseShadows;
|
||||
LightingState::EclipseShadowVector* eclipseShadows;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -539,9 +540,9 @@ class Renderer
|
|||
|
||||
bool testEclipse(const Body& receiver,
|
||||
const Body& caster,
|
||||
const DirectionalLight& light,
|
||||
double now,
|
||||
vector<EclipseShadow>& shadows);
|
||||
LightingState& lightingState,
|
||||
unsigned int lightIndex,
|
||||
double now);
|
||||
|
||||
void labelConstellations(const std::vector<Asterism*>& asterisms,
|
||||
const Observer& observer);
|
||||
|
@ -660,7 +661,7 @@ class Renderer
|
|||
std::vector<Annotation> depthSortedAnnotations;
|
||||
std::vector<Annotation> objectAnnotations;
|
||||
std::vector<OrbitPathListEntry> orbitPathList;
|
||||
std::vector<EclipseShadow> eclipseShadows[MaxLights];
|
||||
LightingState::EclipseShadowVector eclipseShadows[MaxLights];
|
||||
std::vector<const Star*> nearStars;
|
||||
|
||||
std::vector<LightSource> lightSourceList;
|
||||
|
|
|
@ -21,12 +21,7 @@
|
|||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include <celutil/debug.h>
|
||||
#include <celmath/frustum.h>
|
||||
#include <celmath/distance.h>
|
||||
#include <celmath/intersect.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include <celutil/util.h>
|
||||
#include "render.h"
|
||||
#include "astro.h"
|
||||
#include "glshader.h"
|
||||
#include "shadermanager.h"
|
||||
|
@ -37,11 +32,16 @@
|
|||
#include "vertexprog.h"
|
||||
#include "texmanager.h"
|
||||
#include "meshmanager.h"
|
||||
#include "render.h"
|
||||
#include "renderinfo.h"
|
||||
#include "renderglsl.h"
|
||||
#include <GL/glew.h>
|
||||
#include "vecgl.h"
|
||||
#include <celutil/debug.h>
|
||||
#include <celmath/frustum.h>
|
||||
#include <celmath/distance.h>
|
||||
#include <celmath/intersect.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include <celutil/util.h>
|
||||
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
@ -53,7 +53,6 @@ const double AtmosphereExtinctionThreshold = 0.05;
|
|||
// Render a planet sphere with GLSL shaders
|
||||
void renderSphere_GLSL(const RenderInfo& ri,
|
||||
const LightingState& ls,
|
||||
RingSystem* rings,
|
||||
Atmosphere* atmosphere,
|
||||
float cloudTexOffset,
|
||||
float radius,
|
||||
|
@ -118,6 +117,7 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
textures[nTextures++] = ri.overlayTex;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (rings != NULL && (renderFlags & Renderer::ShowRingShadows) != 0)
|
||||
{
|
||||
Texture* ringsTex = rings->texture.find(textureRes);
|
||||
|
@ -138,6 +138,7 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
shadprop.texUsage |= ShaderProperties::RingShadowTexture;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (atmosphere != NULL)
|
||||
{
|
||||
|
@ -188,6 +189,15 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
|
||||
cloudTex->bind();
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; lightIndex++)
|
||||
{
|
||||
if (ls.lights[lightIndex].castsShadows)
|
||||
{
|
||||
shadprop.setCloudShadowForLight(lightIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,16 +206,47 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
// Track the total number of shadows; if there are too many, we'll have
|
||||
// to fall back to multipass.
|
||||
unsigned int totalShadows = 0;
|
||||
|
||||
for (unsigned int li = 0; li < ls.nLights; li++)
|
||||
{
|
||||
if (ls.shadows[li] && !ls.shadows[li]->empty())
|
||||
{
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderShadows, ls.shadows[li]->size());
|
||||
shadprop.setShadowCountForLight(li, nShadows);
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, ls.shadows[li]->size());
|
||||
shadprop.setEclipseShadowCountForLight(li, nShadows);
|
||||
totalShadows += nShadows;
|
||||
}
|
||||
}
|
||||
|
||||
if (ls.shadowingRingSystem)
|
||||
{
|
||||
Texture* ringsTex = ls.shadowingRingSystem->texture.find(textureRes);
|
||||
if (ringsTex != NULL)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
|
||||
ringsTex->bind();
|
||||
nTextures++;
|
||||
|
||||
// Tweak the texture--set clamp to border and a border color with
|
||||
// a zero alpha.
|
||||
float bc[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bc);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
shadprop.texUsage |= ShaderProperties::RingShadowTexture;
|
||||
|
||||
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; lightIndex++)
|
||||
{
|
||||
if (ls.lights[lightIndex].castsShadows &&
|
||||
ls.shadowingRingSystem == ls.ringShadows[lightIndex].ringSystem)
|
||||
{
|
||||
shadprop.setRingShadowForLight(lightIndex, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get a shader for the current rendering configuration
|
||||
CelestiaGLProgram* prog = GetShaderManager().getShader(shadprop);
|
||||
if (prog == NULL)
|
||||
|
@ -226,9 +267,18 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
|
||||
if (shadprop.texUsage & ShaderProperties::RingShadowTexture)
|
||||
{
|
||||
float ringWidth = rings->outerRadius - rings->innerRadius;
|
||||
prog->ringRadius = rings->innerRadius / radius;
|
||||
float ringWidth = ls.shadowingRingSystem->outerRadius - ls.shadowingRingSystem->innerRadius;
|
||||
prog->ringRadius = ls.shadowingRingSystem->innerRadius / radius;
|
||||
prog->ringWidth = radius / ringWidth;
|
||||
prog->ringPlane = Hyperplane<float, 3>(ls.ringPlaneNormal, ls.ringCenter / radius).coeffs();
|
||||
prog->ringCenter = ls.ringCenter / radius;
|
||||
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; ++lightIndex)
|
||||
{
|
||||
if (shadprop.hasRingShadowForLight(lightIndex))
|
||||
{
|
||||
prog->ringShadowLOD[lightIndex] = ls.ringShadows[lightIndex].texLod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shadprop.texUsage & ShaderProperties::CloudShadowTexture)
|
||||
|
@ -242,7 +292,7 @@ void renderSphere_GLSL(const RenderInfo& ri,
|
|||
prog->setAtmosphereParameters(*atmosphere, radius, radius);
|
||||
}
|
||||
|
||||
if (shadprop.shadowCounts != 0)
|
||||
if (shadprop.hasEclipseShadows() != 0)
|
||||
prog->setEclipseShadowParameters(ls, radius, planetOrientation);
|
||||
|
||||
glColor(ri.color);
|
||||
|
@ -357,7 +407,6 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
Texture* cloudTex,
|
||||
Texture* cloudNormalMap,
|
||||
float texOffset,
|
||||
RingSystem* rings,
|
||||
float radius,
|
||||
unsigned int textureRes,
|
||||
int renderFlags,
|
||||
|
@ -389,6 +438,7 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
shadprop.texUsage |= ShaderProperties::CompressedNormalTexture;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (rings != NULL && (renderFlags & Renderer::ShowRingShadows) != 0)
|
||||
{
|
||||
Texture* ringsTex = rings->texture.find(textureRes);
|
||||
|
@ -409,7 +459,8 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
shadprop.texUsage |= ShaderProperties::RingShadowTexture;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (atmosphere != NULL)
|
||||
{
|
||||
if (renderFlags & Renderer::ShowAtmospheres)
|
||||
|
@ -429,8 +480,8 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
{
|
||||
if (ls.shadows[li] && !ls.shadows[li]->empty())
|
||||
{
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderShadows, ls.shadows[li]->size());
|
||||
shadprop.setShadowCountForLight(li, nShadows);
|
||||
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, ls.shadows[li]->size());
|
||||
shadprop.setEclipseShadowCountForLight(li, nShadows);
|
||||
totalShadows += nShadows;
|
||||
}
|
||||
}
|
||||
|
@ -455,13 +506,15 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
prog->setAtmosphereParameters(*atmosphere, radius, cloudRadius);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (shadprop.texUsage & ShaderProperties::RingShadowTexture)
|
||||
{
|
||||
float ringWidth = rings->outerRadius - rings->innerRadius;
|
||||
prog->ringRadius = rings->innerRadius / cloudRadius;
|
||||
prog->ringWidth = 1.0f / (ringWidth / cloudRadius);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (shadprop.shadowCounts != 0)
|
||||
prog->setEclipseShadowParameters(ls, cloudRadius, planetOrientation);
|
||||
|
||||
|
@ -599,7 +652,7 @@ void renderRings_GLSL(RingSystem& rings,
|
|||
{
|
||||
// Set one shadow (the planet's) per light
|
||||
for (unsigned int li = 0; li < ls.nLights; li++)
|
||||
shadprop.setShadowCountForLight(li, 1);
|
||||
shadprop.setEclipseShadowCountForLight(li, 1);
|
||||
}
|
||||
|
||||
if (ringsTex)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
void renderSphere_GLSL(const RenderInfo& ri,
|
||||
const LightingState& ls,
|
||||
RingSystem* rings,
|
||||
Atmosphere* atmosphere,
|
||||
float cloudTexOffset,
|
||||
float radius,
|
||||
|
@ -45,7 +44,6 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
|||
Texture* cloudTex,
|
||||
Texture* cloudNormalMap,
|
||||
float texOffset,
|
||||
RingSystem* rings,
|
||||
float radius,
|
||||
unsigned int textureRes,
|
||||
int renderFlags,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// samporient.cpp
|
||||
//
|
||||
// Copyright (C) 2006-2007, Chris Laurel <claurel@shatters.net>
|
||||
// Copyright (C) 2006-2009, the Celestia Development Team
|
||||
// Original version by Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// The SampledOrientation class models orientation of a body by interpolating
|
||||
// a sequence of key frames.
|
||||
|
@ -10,7 +11,10 @@
|
|||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#include <Eigen/StdVector>
|
||||
#include <Eigen/NewStdVector>
|
||||
#include <celengine/samporient.h>
|
||||
#include <celmath/mathlib.h>
|
||||
#include <celmath/geomutil.h>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
@ -18,9 +22,6 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <celmath/mathlib.h>
|
||||
#include <celmath/geomutil.h>
|
||||
#include <celengine/samporient.h>
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
|
@ -33,6 +34,8 @@ struct OrientationSample
|
|||
double t;
|
||||
};
|
||||
|
||||
typedef vector<OrientationSample, aligned_allocator<OrientationSample> > OrientationSampleVector;
|
||||
|
||||
/*!
|
||||
* Sampled orientation files are ASCII text files containing a sequence of
|
||||
* time stamped quaternion keys. Each record in the file has the form:
|
||||
|
@ -95,7 +98,7 @@ private:
|
|||
Quaternionf getOrientation(double tjd) const;
|
||||
|
||||
private:
|
||||
vector<OrientationSample> samples;
|
||||
OrientationSampleVector samples;
|
||||
mutable int lastSample;
|
||||
|
||||
enum InterpolationType
|
||||
|
@ -181,10 +184,9 @@ SampledOrientation::getOrientation(double tjd) const
|
|||
// the search if the covers the requested time.
|
||||
if (n < 1 || n >= (int) samples.size() || tjd < samples[n - 1].t || tjd > samples[n].t)
|
||||
{
|
||||
vector<OrientationSample>::const_iterator iter = lower_bound(samples.begin(),
|
||||
samples.end(),
|
||||
|
||||
samp);
|
||||
OrientationSampleVector::const_iterator iter = lower_bound(samples.begin(),
|
||||
samples.end(),
|
||||
samp);
|
||||
if (iter == samples.end())
|
||||
n = samples.size();
|
||||
else
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,8 +27,20 @@ class ShaderProperties
|
|||
bool usesShadows() const;
|
||||
bool usesFragmentLighting() const;
|
||||
bool usesTangentSpaceLighting() const;
|
||||
unsigned int getShadowCountForLight(unsigned int) const;
|
||||
void setShadowCountForLight(unsigned int, unsigned int);
|
||||
|
||||
unsigned int getEclipseShadowCountForLight(unsigned int lightIndex) const;
|
||||
void setEclipseShadowCountForLight(unsigned int lightIndex, unsigned int shadowCount);
|
||||
bool hasEclipseShadows() const;
|
||||
bool hasRingShadowForLight(unsigned int lightIndex) const;
|
||||
void setRingShadowForLight(unsigned int lightIndex, bool enabled);
|
||||
bool hasRingShadows() const;
|
||||
void setSelfShadowForLight(unsigned int lightIndex, bool enabled);
|
||||
bool hasSelfShadowForLight(unsigned int lightIndex) const;
|
||||
bool hasSelfShadows() const;
|
||||
void setCloudShadowForLight(unsigned int lightIndex, bool enabled);
|
||||
bool hasCloudShadowForLight(unsigned int lightIndex) const;
|
||||
bool hasCloudShadows() const;
|
||||
|
||||
bool hasShadowsForLight(unsigned int) const;
|
||||
bool hasSharedTextureCoords() const;
|
||||
bool hasSpecular() const;
|
||||
|
@ -74,22 +86,45 @@ class ShaderProperties
|
|||
VolumetricAbsorptionEffect = 0x0002,
|
||||
VolumetricEmissionEffect = 0x0004,
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
unsigned short nLights;
|
||||
unsigned short texUsage;
|
||||
unsigned short lightModel;
|
||||
|
||||
// Two bits per light, up to eight lights + three shadows per light
|
||||
unsigned short shadowCounts;
|
||||
// Eight bits per light, up to four lights
|
||||
// For each light:
|
||||
// Bits 0-1, eclipse shadow count, from 0-3
|
||||
// Bit 2, on if there are ring shadows
|
||||
// Bit 3, on for self shadowing
|
||||
// Bit 4, on for cloud shadows
|
||||
uint32 shadowCounts;
|
||||
|
||||
// Effects that may be applied with any light model
|
||||
unsigned short effects;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
ShadowBitsPerLight = 4,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EclipseShadowMask = 0x3,
|
||||
RingShadowMask = 0x4,
|
||||
SelfShadowMask = 0x8,
|
||||
CloudShadowMask = 0x10,
|
||||
AnyEclipseShadowMask = 0x03030303,
|
||||
AnyRingShadowMask = 0x04040404,
|
||||
AnySelfShadowMask = 0x08080808,
|
||||
AnyCloudShadowMask = 0x10101010,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static const unsigned int MaxShaderLights = 4;
|
||||
static const unsigned int MaxShaderShadows = 3;
|
||||
static const unsigned int MaxShaderEclipseShadows = 3;
|
||||
struct CelestiaGLProgramLight
|
||||
{
|
||||
Vec3ShaderParameter direction;
|
||||
|
@ -135,6 +170,7 @@ class CelestiaGLProgram
|
|||
Vec3ShaderParameter fragLightColor[MaxShaderLights];
|
||||
Vec3ShaderParameter fragLightSpecColor[MaxShaderLights];
|
||||
FloatShaderParameter fragLightBrightness[MaxShaderLights];
|
||||
FloatShaderParameter ringShadowLOD[MaxShaderLights];
|
||||
Vec3ShaderParameter eyePosition;
|
||||
FloatShaderParameter shininess;
|
||||
Vec3ShaderParameter ambientColor;
|
||||
|
@ -145,6 +181,8 @@ class CelestiaGLProgram
|
|||
|
||||
FloatShaderParameter ringWidth;
|
||||
FloatShaderParameter ringRadius;
|
||||
Vec4ShaderParameter ringPlane;
|
||||
Vec3ShaderParameter ringCenter;
|
||||
|
||||
// Mix of Lambertian and "lunar" (Lommel-Seeliger) photometric models.
|
||||
// 0 = pure Lambertian, 1 = L-S
|
||||
|
@ -191,7 +229,7 @@ class CelestiaGLProgram
|
|||
// Scale factor for point sprites
|
||||
FloatShaderParameter pointScale;
|
||||
|
||||
CelestiaGLProgramShadow shadows[MaxShaderLights][MaxShaderShadows];
|
||||
CelestiaGLProgramShadow shadows[MaxShaderLights][MaxShaderEclipseShadows];
|
||||
|
||||
private:
|
||||
void initParameters();
|
||||
|
|
Loading…
Reference in New Issue