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
Chris Laurel 2009-10-27 22:02:01 +00:00
parent 7e9429ed45
commit dcf9232c08
11 changed files with 1327 additions and 181 deletions

View File

@ -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)

View File

@ -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
{

View File

@ -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;

View File

@ -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 ||

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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();