- Implemented cloud textures

- Changed eclipse shadow shaders to use just a single interpolant for all shadows rather than one interpolant per shadow. This will prevent Celestia from generating uncompilable shaders when there are many eclipse shadows
ver1_5_1
Chris Laurel 2006-07-12 17:39:24 +00:00
parent 8283e04e95
commit 063ec093d3
3 changed files with 179 additions and 77 deletions

View File

@ -4012,7 +4012,10 @@ static void renderSphere_FP_VP(const RenderInfo& ri,
static void renderSphere_GLSL(const RenderInfo& ri,
const LightingState& ls,
RingSystem* rings,
Atmosphere* atmosphere,
float cloudTexOffset,
float radius,
unsigned int textureRes,
const Mat4f& planetMat,
const Frustum& frustum,
const GLContext& context)
@ -4069,7 +4072,7 @@ static void renderSphere_GLSL(const RenderInfo& ri,
(renderFlags & ShowRingShadows) != 0)
#endif
{
Texture* ringsTex = rings->texture.find(medres);
Texture* ringsTex = rings->texture.find(textureRes);
if (ringsTex != NULL)
{
glx::glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
@ -4087,6 +4090,23 @@ static void renderSphere_GLSL(const RenderInfo& ri,
shadprop.texUsage |= ShaderProperties::RingShadowTexture;
}
}
if (atmosphere != NULL)
{
Texture* cloudTex = NULL;
if (atmosphere->cloudTexture.tex[textureRes] != InvalidResource)
cloudTex = atmosphere->cloudTexture.find(textureRes);
if (cloudTex != NULL)
{
shadprop.texUsage |= ShaderProperties::CloudShadowTexture;
textures[nTextures++] = cloudTex;
#if 1
glx::glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
cloudTex->bind();
glx::glActiveTextureARB(GL_TEXTURE0_ARB);
#endif
}
}
// Set the shadow information.
// Track the total number of shadows; if there are too many, we'll have
@ -4126,6 +4146,12 @@ static void renderSphere_GLSL(const RenderInfo& ri,
prog->ringRadius = rings->innerRadius / radius;
prog->ringWidth = radius / ringWidth;
}
if (shadprop.texUsage & ShaderProperties::CloudShadowTexture)
{
prog->shadowTextureOffset = cloudTexOffset;
prog->cloudHeight = 1.0f + atmosphere->cloudHeight / radius;
}
if (shadprop.shadowCounts != 0)
setEclipseShadowShaderConstants(ls, radius, planetMat, *prog);
@ -4178,6 +4204,7 @@ static void renderClouds_GLSL(const RenderInfo& ri,
float texOffset,
RingSystem* rings,
float radius,
unsigned int textureRes,
const Mat4f& planetMat,
const Frustum& frustum,
const GLContext& context)
@ -4199,7 +4226,7 @@ static void renderClouds_GLSL(const RenderInfo& ri,
if (rings != NULL)
//(renderFlags & ShowRingShadows) != 0)
{
Texture* ringsTex = rings->texture.find(medres);
Texture* ringsTex = rings->texture.find(textureRes);
if (ringsTex != NULL)
{
glx::glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
@ -5418,12 +5445,28 @@ void Renderer::renderObject(Point3f pos,
nearPlaneDistance, farPlaneDistance);
viewFrustum.transform(invMV);
// Temporary hack until we fix culling for ringed planets
// Temporary hack until we fix culling for ringed planets; prevents
// over-tesselation of ringed planet surfaces. The amount of tesselation
// should be based on the screen width of the planet sphere, not including
// the rings.
if (obj.rings != NULL)
{
if (ri.pixWidth > 5000)
ri.pixWidth = 5000;
}
// Get cloud layer parameters
Texture* cloudTex = NULL;
float cloudTexOffset = 0.0f;
if (obj.atmosphere != NULL)
{
Atmosphere* atmosphere = const_cast<Atmosphere*>(obj.atmosphere); // Ugly cast required because MultiResTexture::find() is non-const
if ((renderFlags & ShowCloudMaps) != 0 &&
atmosphere->cloudTexture.tex[textureResolution] != InvalidResource)
cloudTex = atmosphere->cloudTexture.find(textureResolution);
if (atmosphere->cloudSpeed != 0.0f)
cloudTexOffset = (float) (-pfmod(now * atmosphere->cloudSpeed / (2 * PI), 1.0));
}
Model* model = NULL;
if (obj.model == InvalidResource)
@ -5434,7 +5477,10 @@ void Renderer::renderObject(Point3f pos,
switch (context->getRenderPath())
{
case GLContext::GLPath_GLSL:
renderSphere_GLSL(ri, ls, obj.rings, obj.radius,
renderSphere_GLSL(ri, ls, obj.rings,
const_cast<Atmosphere*>(obj.atmosphere), cloudTexOffset,
obj.radius,
textureResolution,
planetMat, viewFrustum, *context);
break;
@ -5573,11 +5619,6 @@ void Renderer::renderObject(Point3f pos,
}
// If there's a cloud layer, we'll render it now.
Texture* cloudTex = NULL;
if ((renderFlags & ShowCloudMaps) != 0 &&
atmosphere->cloudTexture.tex[textureResolution] != InvalidResource)
cloudTex = atmosphere->cloudTexture.find(textureResolution);
if (cloudTex != NULL)
{
glPushMatrix();
@ -5590,7 +5631,6 @@ void Renderer::renderObject(Point3f pos,
if (distance - radius < atmosphere->cloudHeight)
glFrontFace(GL_CW);
float texOffset = (float) (-pfmod(now * atmosphere->cloudSpeed / (2 * PI), 1.0));
if (atmosphere->cloudSpeed != 0.0f)
{
// Make the clouds appear to rotate above the surface of
@ -5599,7 +5639,7 @@ void Renderer::renderObject(Point3f pos,
// texture matrix doesn't require us to compute a second
// set of model space rendering parameters.
glMatrixMode(GL_TEXTURE);
glTranslatef(texOffset, 0.0f, 0.0f);
glTranslatef(cloudTexOffset, 0.0f, 0.0f);
glMatrixMode(GL_MODELVIEW);
}
@ -5616,9 +5656,10 @@ void Renderer::renderObject(Point3f pos,
{
renderClouds_GLSL(ri, ls,
cloudTex,
texOffset,
cloudTexOffset,
obj.rings,
radius * cloudScale,
textureResolution,
planetMat,
viewFrustum,
*context);
@ -5631,7 +5672,7 @@ void Renderer::renderObject(Point3f pos,
vproc->enable();
vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
vproc->parameter(vp::TextureTranslation,
texOffset, 0.0f, 0.0f, 0.0f);
cloudTexOffset, 0.0f, 0.0f, 0.0f);
if (ls.nLights > 1)
vproc->use(vp::diffuseTexOffset_2light);
else

View File

@ -53,10 +53,9 @@ ShaderProperties::ShaderProperties() :
bool
ShaderProperties::usesShadows() const
{
if ((texUsage & RingShadowTexture) != 0 || shadowCounts != 0)
return true;
else
return false;
return (texUsage & RingShadowTexture) != 0 ||
(texUsage & CloudShadowTexture) != 0 ||
shadowCounts != 0;
}
@ -94,8 +93,8 @@ bool
ShaderProperties::hasShadowsForLight(unsigned int light) const
{
assert(light < MaxShaderLights);
return ((getShadowCountForLight(light) != 0) ||
(texUsage & RingShadowTexture));
return getShadowCountForLight(light) != 0 ||
(texUsage & (RingShadowTexture | CloudShadowTexture)) != 0;
}
@ -287,6 +286,15 @@ RingShadowTexCoord(unsigned int index)
}
static string
CloudShadowTexCoord(unsigned int index)
{
char buf[64];
sprintf(buf, "cloudShadowTexCoord%d", index);
return string(buf);
}
void
CelestiaGLProgram::initParameters(const ShaderProperties& props)
{
@ -333,6 +341,12 @@ CelestiaGLProgram::initParameters(const ShaderProperties& props)
textureOffset = floatParam("textureOffset");
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
cloudHeight = floatParam("cloudHeight");
shadowTextureOffset = floatParam("cloudShadowTexOffset");
}
if ((props.texUsage & ShaderProperties::NightTexture) != 0)
{
nightTexMin = floatParam("nightTexMin");
@ -387,6 +401,13 @@ CelestiaGLProgram::initSamplers(const ShaderProperties& props)
if (slot != -1)
glx::glUniform1iARB(slot, nSamplers++);
}
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
int slot = glx::glGetUniformLocationARB(program->getID(), "cloudShadowTex");
if (slot != -1)
glx::glUniform1iARB(slot, nSamplers++);
}
}
@ -475,6 +496,16 @@ SeparateSpecular(unsigned int i)
}
// Used by rings shader
static string
ShadowDepth(unsigned int i)
{
char buf[32];
sprintf(buf, "shadowDepths.%c", "xyzw"[i & 3]);
return string(buf);
}
static string
TexCoord2D(unsigned int i)
{
@ -595,6 +626,12 @@ BeginLightSourceShadows(const ShaderProperties& props, unsigned int light)
source += "shadow *= (1.0 - texture2D(ringTex, vec2(" +
RingShadowTexCoord(light) + ", 0.0)).a);\n";
}
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
source += "shadow *= (1.0 - texture2D(cloudShadowTex, " +
CloudShadowTexCoord(light) + ").a * 0.75);\n";
}
return source;
}
@ -605,9 +642,10 @@ Shadow(unsigned int light, unsigned int shadow)
{
string source;
source += "shadowCenter = " +
IndexedParameter("shadowTexCoord", light, shadow) +
".st - vec2(0.5, 0.5);\n";
source += "shadowCenter.s = dot(vec4(position_obj, 1.0), " +
IndexedParameter("shadowTexGenS", light, shadow) + ") - 0.5;\n";
source += "shadowCenter.t = dot(vec4(position_obj, 1.0), " +
IndexedParameter("shadowTexGenT", light, shadow) + ") - 0.5;\n";
source += "shadowR = clamp(dot(shadowCenter, shadowCenter) * " +
IndexedParameter("shadowScale", light, shadow) + " + " +
IndexedParameter("shadowBias", light, shadow) + ", 0.0, 1.0);\n";
@ -659,7 +697,7 @@ TextureSamplerDeclarations(const ShaderProperties& props)
{
source += "uniform sampler2D overlayTex;\n";
}
return source;
}
@ -768,18 +806,7 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
// Shadow parameters
if (props.shadowCounts != 0)
{
for (unsigned int i = 0; i < props.nLights; i++)
{
for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
{
source += "varying vec2 " +
IndexedParameter("shadowTexCoord", i, j) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenS", i, j) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenT", i, j) + ";\n";
}
}
source += "varying vec3 position_obj;\n";
}
if (props.texUsage & ShaderProperties::RingShadowTexture)
@ -789,6 +816,13 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
source += "varying vec4 ringShadowTexCoord;\n";
}
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
source += "uniform float cloudShadowTexOffset;\n";
source += "uniform float cloudHeight;\n";
for (unsigned int i = 0; i < props.nLights; i++)
source += "varying vec2 " + CloudShadowTexCoord(i) + ";\n";
}
// Begin main() function
source += "\nvoid main(void)\n{\n";
@ -881,6 +915,33 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
" = (length(ringShadowProj) - ringRadius) * ringWidth;\n";
}
}
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
for (unsigned int j = 0; j < props.nLights; j++)
{
source += "{\n";
// A cheap way to calculate cloud shadow texture coordinates that doesn't correctly account
// for sun angle.
//source += " " + CloudShadowTexCoord(j) + " = vec2(diffTexCoord.x + cloudShadowTexOffset, diffTexCoord.y);\n";
// Compute the intersection of the sun direction and the cloud layer (currently assumed to be a sphere)
source += " float s = 1.0 / (cloudHeight * cloudHeight);\n";
source += " float invPi = 1.0f / 3.1415927;\n";
source += " vec3 coeff;\n";
source += " coeff.x = dot(" + LightProperty(j, "direction") + ", " + LightProperty(j, "direction") + ") * s;\n";
source += " coeff.y = dot(" + LightProperty(j, "direction") + ", gl_Vertex.xyz) * s;\n";
source += " coeff.z = dot(gl_Vertex.xyz, gl_Vertex.xyz) * s - 1.0;\n";
source += " float disc = sqrt(coeff.y * coeff.y - coeff.x * coeff.z);\n";
source += " vec3 cloudSpherePos = normalize(gl_Vertex.xyz + ((-coeff.y + disc) / coeff.x) * " + LightProperty(j, "direction") + ");\n";
// Find the texture coordinates at this point on the sphere by converting from rectangular to spherical; this is an
// expensive calculation to perform per vertex.
source += " " + CloudShadowTexCoord(j) + " = vec2(cloudShadowTexOffset + fract(atan(cloudSpherePos.x, cloudSpherePos.z) * (invPi * 0.5) + 0.75), 0.5 - asin(cloudSpherePos.y) * invPi);\n";
source += "}\n";
}
}
if (props.texUsage & ShaderProperties::OverlayTexture)
{
@ -890,18 +951,7 @@ ShaderManager::buildVertexShader(const ShaderProperties& props)
if (props.shadowCounts != 0)
{
for (unsigned int i = 0; i < props.nLights; i++)
{
for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
{
source += IndexedParameter("shadowTexCoord", i, j) +
".s = dot(gl_Vertex, " +
IndexedParameter("shadowTexGenS", i, j) + ");\n";
source += IndexedParameter("shadowTexCoord", i, j) +
".t = dot(gl_Vertex, " +
IndexedParameter("shadowTexGenT", i, j) + ");\n";
}
}
source += "position_obj = gl_Vertex.xyz;\n";
}
source += "gl_Position = ftransform();\n";
@ -1019,12 +1069,15 @@ ShaderManager::buildFragmentShader(const ShaderProperties& props)
// Declare shadow parameters
if (props.shadowCounts != 0)
{
source += "varying vec3 position_obj;\n";
for (unsigned int i = 0; i < props.nLights; i++)
{
for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
{
source += "varying vec2 " +
IndexedParameter("shadowTexCoord", i, j) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenS", i, j) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenT", i, j) + ";\n";
source += "uniform float " +
IndexedParameter("shadowScale", i, j) + ";\n";
source += "uniform float " +
@ -1038,7 +1091,14 @@ ShaderManager::buildFragmentShader(const ShaderProperties& props)
source += "uniform sampler2D ringTex;\n";
source += "varying vec4 ringShadowTexCoord;\n";
}
if (props.texUsage & ShaderProperties::CloudShadowTexture)
{
source += "uniform sampler2D cloudShadowTex;\n";
for (unsigned int i = 0; i < props.nLights; i++)
source += "varying vec2 " + CloudShadowTexCoord(i) + ";\n";
}
source += "\nvoid main(void)\n{\n";
source += "vec4 color;\n";
@ -1053,7 +1113,6 @@ ShaderManager::buildFragmentShader(const ShaderProperties& props)
}
}
// Sum the illumination from each light source, computing a total diffuse and specular
// contributions from all sources.
if (props.usesTangentSpaceLighting())
@ -1065,6 +1124,7 @@ ShaderManager::buildFragmentShader(const ShaderProperties& props)
// an option for this.
if (props.texUsage & ShaderProperties::NormalTexture)
{
//source += "vec3 n = normalize(texture2D(normTex, " + normTexCoord + ".st).xyz * 2.0 - vec3(1.0, 1.0, 1.0));\n";
source += "vec3 n = texture2D(normTex, " + normTexCoord + ".st).xyz * 2.0 - vec3(1.0, 1.0, 1.0);\n";
}
else
@ -1221,15 +1281,8 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
if (props.shadowCounts != 0)
{
for (unsigned int i = 0; i < props.nLights; i++)
{
source += "uniform vec4 " +
IndexedParameter("shadowTexGenS", i, 0) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenT", i, 0) + ";\n";
source += "varying vec3 " +
IndexedParameter("shadowTexCoord", i, 0) + ";\n";
}
source += "varying vec3 position_obj;\n";
source += "varying vec4 shadowDepths;\n";
}
source += "\nvoid main(void)\n{\n";
@ -1249,17 +1302,11 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
if (props.shadowCounts != 0)
{
source += "position_obj = gl_Vertex.xyz;\n";
for (unsigned int i = 0; i < props.nLights; i++)
{
source += IndexedParameter("shadowTexCoord", i, 0) +
".x = dot(gl_Vertex, " +
IndexedParameter("shadowTexGenS", i, 0) + ");\n";
source += IndexedParameter("shadowTexCoord", i, 0) +
".y = dot(gl_Vertex, " +
IndexedParameter("shadowTexGenT", i, 0) + ");\n";
source += IndexedParameter("shadowTexCoord", i, 0) +
".z = dot(gl_Vertex.xyz, " +
LightProperty(i, "direction") + ");\n";
source += ShadowDepth(i) + " = dot(gl_Vertex.xyz, " +
LightProperty(i, "direction") + ");\n";
}
}
@ -1300,16 +1347,25 @@ ShaderManager::buildRingsFragmentShader(const ShaderProperties& props)
source += "uniform sampler2D diffTex;\n";
}
if (props.shadowCounts != 0)
{
source += "varying vec3 position_obj;\n";
source += "varying vec4 shadowDepths;\n";
for (unsigned int i = 0; i < props.nLights; i++)
{
source += "varying vec3 " +
IndexedParameter("shadowTexCoord", i, 0) + ";\n";
source += "uniform float " +
IndexedParameter("shadowScale", i, 0) + ";\n";
source += "uniform float " +
IndexedParameter("shadowBias", i, 0) + ";\n";
for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
{
source += "uniform vec4 " +
IndexedParameter("shadowTexGenS", i, j) + ";\n";
source += "uniform vec4 " +
IndexedParameter("shadowTexGenT", i, j) + ";\n";
source += "uniform float " +
IndexedParameter("shadowScale", i, j) + ";\n";
source += "uniform float " +
IndexedParameter("shadowBias", i, j) + ";\n";
}
}
}
@ -1331,8 +1387,7 @@ ShaderManager::buildRingsFragmentShader(const ShaderProperties& props)
{
source += "shadow = 1.0;\n";
source += Shadow(i, 0);
source += "shadow = min(1.0, shadow + step(0.0, " +
IndexedParameter("shadowTexCoord", i, 0) + ".z));\n";
source += "shadow = min(1.0, shadow + step(0.0, " + ShadowDepth(i) + "));\n";
source += "diff.rgb += (shadow * " + SeparateDiffuse(i) + ") * " +
FragLightProperty(i, "color") + ";\n";
}

View File

@ -37,6 +37,7 @@ class ShaderProperties
SpecularInDiffuseAlpha = 0x10,
RingShadowTexture = 0x20,
OverlayTexture = 0x40,
CloudShadowTexture = 0x80,
SharedTextureCoords = 0x8000,
};
@ -97,6 +98,11 @@ class CelestiaGLProgram
// Diffuse texture coordinate offset
FloatShaderParameter textureOffset;
// Cloud shadow parameters
// Height of cloud layer above planet, in units of object radius
FloatShaderParameter cloudHeight;
FloatShaderParameter shadowTextureOffset;
// Control the night texture effect--set to 1 for a purely additive effect,
// and 0 to show the night texture only in otherwise unilluminated regions.