shadermanager.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:83k
- // shadermanager.cpp
- //
- // Copyright (C) 2001-2007, Chris Laurel <claurel@shatters.net>
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- #include "celutil/util.h"
- #include "gl.h"
- #include "glext.h"
- #include "shadermanager.h"
- #include <cmath>
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <iomanip>
- #include <cstdio>
- #include <cassert>
- using namespace std;
- // GLSL on Mac OS X appears to have a bug that precludes us from using structs
- // #define USE_GLSL_STRUCTS
- ShaderManager g_ShaderManager;
- static const char* errorVertexShaderSource =
- "void main(void) {n"
- " gl_Position = ftransform();n"
- "}n";
- static const char* errorFragmentShaderSource =
- "void main(void) {n"
- " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);n"
- "}n";
- static const string CommonHeader("#version 110n");
- ShaderManager&
- GetShaderManager()
- {
- return g_ShaderManager;
- }
- ShaderProperties::ShaderProperties() :
- nLights(0),
- texUsage(0),
- lightModel(DiffuseModel),
- shadowCounts(0),
- effects(0)
- {
- }
- bool
- ShaderProperties::usesShadows() const
- {
- return (texUsage & RingShadowTexture) != 0 ||
- (texUsage & CloudShadowTexture) != 0 ||
- shadowCounts != 0;
- }
- bool
- ShaderProperties::usesFragmentLighting() const
- {
- if ((texUsage & NormalTexture) != 0 || lightModel == PerPixelSpecularModel)
- return true;
- else
- return false;
- }
- unsigned int
- ShaderProperties::getShadowCountForLight(unsigned int i) const
- {
- return (shadowCounts >> i * 2) & 3;
- }
- void
- ShaderProperties::setShadowCountForLight(unsigned int light, unsigned int n)
- {
- assert(n <= MaxShaderShadows);
- assert(light < MaxShaderLights);
- if (n <= MaxShaderShadows && light < MaxShaderLights)
- {
- shadowCounts &= ~(3 << light * 2);
- shadowCounts |= n << light * 2;
- }
- }
- bool
- ShaderProperties::hasShadowsForLight(unsigned int light) const
- {
- assert(light < MaxShaderLights);
- return getShadowCountForLight(light) != 0 ||
- (texUsage & (RingShadowTexture | CloudShadowTexture)) != 0;
- }
- // Returns true if diffuse, specular, bump, and night textures all use the
- // same texture coordinate set.
- bool
- ShaderProperties::hasSharedTextureCoords() const
- {
- return (texUsage & SharedTextureCoords) != 0;
- }
- bool
- ShaderProperties::hasSpecular() const
- {
- switch (lightModel)
- {
- case SpecularModel:
- case PerPixelSpecularModel:
- return true;
- default:
- return false;
- }
- }
- bool
- ShaderProperties::hasScattering() const
- {
- return (texUsage & Scattering) != 0;
- }
- bool
- ShaderProperties::isViewDependent() const
- {
- switch (lightModel)
- {
- case DiffuseModel:
- case ParticleDiffuseModel:
- case EmissiveModel:
- return false;
- default:
- return true;
- }
- }
- bool
- ShaderProperties::usesTangentSpaceLighting() const
- {
- return (texUsage & NormalTexture) != 0;
- }
- bool operator<(const ShaderProperties& p0, const ShaderProperties& p1)
- {
- if (p0.texUsage < p1.texUsage)
- return true;
- else if (p1.texUsage < p0.texUsage)
- return false;
- if (p0.nLights < p1.nLights)
- return true;
- else if (p1.nLights < p0.nLights)
- return false;
- if (p0.shadowCounts < p1.shadowCounts)
- return true;
- else if (p1.shadowCounts < p0.shadowCounts)
- return false;
- if (p0.effects < p1.effects)
- return true;
- else if (p1.effects < p0.effects)
- return false;
- return (p0.lightModel < p1.lightModel);
- }
- ShaderManager::ShaderManager()
- {
- #if defined(_DEBUG) || defined(DEBUG)
- // Only write to shader log file if this is a debug build
- if (g_shaderLogFile == NULL)
- #ifdef _WIN32
- g_shaderLogFile = new ofstream("shaders.log");
- #else
- g_shaderLogFile = new ofstream("/tmp/celestia-shaders.log");
- #endif
- #endif
- }
- ShaderManager::~ShaderManager()
- {
- }
- CelestiaGLProgram*
- ShaderManager::getShader(const ShaderProperties& props)
- {
- map<ShaderProperties, CelestiaGLProgram*>::iterator iter = shaders.find(props);
- if (iter != shaders.end())
- {
- // Shader already exists
- return iter->second;
- }
- else
- {
- // Create a new shader and add it to the table of created shaders
- CelestiaGLProgram* prog = buildProgram(props);
- shaders[props] = prog;
- return prog;
- }
- }
- static string
- LightProperty(unsigned int i, const char* property)
- {
- char buf[64];
- #ifndef USE_GLSL_STRUCTS
- sprintf(buf, "light%d_%s", i, property);
- #else
- sprintf(buf, "lights[%d].%s", i, property);
- #endif
- return string(buf);
- }
- static string
- FragLightProperty(unsigned int i, const char* property)
- {
- char buf[64];
- sprintf(buf, "light%s%d", property, i);
- return string(buf);
- }
- #if 0
- static string
- IndexedParameter(const char* name, unsigned int index)
- {
- char buf[64];
- sprintf(buf, "%s%d", name, index);
- return string(buf);
- }
- #endif
- static string
- IndexedParameter(const char* name, unsigned int index0, unsigned int index1)
- {
- char buf[64];
- sprintf(buf, "%s%d_%d", name, index0, index1);
- return string(buf);
- }
- static string
- RingShadowTexCoord(unsigned int index)
- {
- char buf[64];
- sprintf(buf, "ringShadowTexCoord.%c", "xyzw"[index]);
- return string(buf);
- }
- static string
- CloudShadowTexCoord(unsigned int index)
- {
- char buf[64];
- sprintf(buf, "cloudShadowTexCoord%d", index);
- return string(buf);
- }
- static string
- VarScatterInVS()
- {
- return string("gl_FrontSecondaryColor.rgb");
- }
- static string
- VarScatterInFS()
- {
- return string("gl_SecondaryColor.rgb");
- }
- static void
- DumpShaderSource(ostream& out, const std::string& source)
- {
- bool newline = true;
- unsigned int lineNumber = 0;
- for (unsigned int i = 0; i < source.length(); i++)
- {
- if (newline)
- {
- lineNumber++;
- out << setw(3) << lineNumber << ": ";
- newline = false;
- }
- out << source[i];
- if (source[i] == 'n')
- newline = true;
- }
- out.flush();
- }
- static string
- DeclareLights(const ShaderProperties& props)
- {
- if (props.nLights == 0)
- return string("");
- #ifndef USE_GLSL_STRUCTS
- ostringstream stream;
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- stream << "uniform vec3 light" << i << "_direction;n";
- stream << "uniform vec3 light" << i << "_diffuse;n";
- stream << "uniform vec3 light" << i << "_specular;n";
- stream << "uniform vec3 light" << i << "_halfVector;n";
- if (props.texUsage & ShaderProperties::NightTexture)
- stream << "uniform float light" << i << "_brightness;n";
- }
- #else
- stream << "uniform struct {n";
- stream << " vec3 direction;n";
- stream << " vec3 diffuse;n";
- stream << " vec3 specular;n";
- stream << " vec3 halfVector;n";
- if (props.texUsage & ShaderProperties::NightTexture)
- stream << " float brightness;n";
- stream << "} lights[%d];n";
- #endif
- return stream.str();
- }
- static string
- SeparateDiffuse(unsigned int i)
- {
- // Used for packing multiple diffuse factors into the diffuse color.
- char buf[32];
- sprintf(buf, "diffFactors.%c", "xyzw"[i & 3]);
- return string(buf);
- }
- static string
- SeparateSpecular(unsigned int i)
- {
- // Used for packing multiple specular factors into the specular color.
- char buf[32];
- sprintf(buf, "specFactors.%c", "xyzw"[i & 3]);
- return string(buf);
- }
- // 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)
- {
- char buf[64];
- sprintf(buf, "gl_MultiTexCoord%d.st", i);
- return string(buf);
- }
- // Tangent space light direction
- static string
- LightDir_tan(unsigned int i)
- {
- char buf[32];
- sprintf(buf, "lightDir_tan_%d", i);
- return string(buf);
- }
- static string
- LightHalfVector(unsigned int i)
- {
- char buf[32];
- sprintf(buf, "lightHalfVec%d", i);
- return string(buf);
- }
- static string
- ScatteredColor(unsigned int i)
- {
- char buf[32];
- sprintf(buf, "scatteredColor%d", i);
- return string(buf);
- }
- static string
- TangentSpaceTransform(const string& dst, const string& src)
- {
- string source;
- source += dst + ".x = dot(tangent, " + src + ");n";
- source += dst + ".y = dot(-bitangent, " + src + ");n";
- source += dst + ".z = dot(gl_Normal, " + src + ");n";
- return source;
- }
- static string
- NightTextureBlend()
- {
- #if 1
- // Output the blend factor for night lights textures
- return string("totalLight = 1.0 - totalLight;n"
- "totalLight = totalLight * totalLight * totalLight * totalLight;n");
- #else
- // Alternate night light blend function; much sharper falloff near terminator.
- return string("totalLight = clamp(10.0 * (0.1 - totalLight), 0.0, 1.0);n");
- #endif
- }
- // Return true if the color sum from all light sources should be computed in
- // the vertex shader, and false if it will be done by the pixel shader.
- static bool
- VSComputesColorSum(const ShaderProperties& props)
- {
- return !props.usesShadows() && props.lightModel != ShaderProperties::PerPixelSpecularModel;
- }
- static string
- AssignDiffuse(unsigned int lightIndex, const ShaderProperties& props)
- {
- if (VSComputesColorSum(props))
- return string("diff.rgb += ") + LightProperty(lightIndex, "diffuse") + " * ";
- else
- return SeparateDiffuse(lightIndex) + " = ";
- }
- // Values used in generated shaders:
- // N - surface normal
- // V - view vector: the normalized direction from vertex to eye
- // L - light direction: normalized direction from vertex to light
- // H - half vector for Blinn-Phong lighting: normalized, bisects L and V
- // R - reflected light direction
- // NL - dot product of light and normal vectors
- // NV - dot product of light and view vectors
- // NH - dot product of light and half vectors
- static string
- AddDirectionalLightContrib(unsigned int i, const ShaderProperties& props)
- {
- string source;
- if (props.lightModel == ShaderProperties::ParticleDiffuseModel)
- {
- // The ParticleDiffuse model doesn't use a surface normal; vertices
- // are lit as if they were infinitesimal spherical particles,
- // unaffected by light direction except when considering shadows.
- source += "NL = 1.0;n";
- }
- else
- {
- source += "NL = max(0.0, dot(gl_Normal, " +
- LightProperty(i, "direction") + "));n";
- }
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "H = normalize(" + LightProperty(i, "direction") + " + normalize(eyePosition - gl_Vertex.xyz));n";
- source += "NH = max(0.0, dot(gl_Normal, H));n";
- // The calculation below uses the infinite viewer approximation. It's slightly faster,
- // but results in less accurate rendering.
- // source += "NH = max(0.0, dot(gl_Normal, " + LightProperty(i, "halfVector") + "));n";
- }
- if (props.usesTangentSpaceLighting())
- {
- source += TangentSpaceTransform(LightDir_tan(i), LightProperty(i, "direction"));
- // Diffuse color is computed in the fragment shader
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += SeparateDiffuse(i) + " = NL;n";
- // Specular is computed in the fragment shader; half vectors are required
- // for the calculation
- source += LightHalfVector(i) + " = " + LightProperty(i, "direction") + " + eyeDir;n";
- }
- else if (props.lightModel == ShaderProperties::OrenNayarModel)
- {
- source += "float cosAlpha = min(NV, NL);n";
- source += "float cosBeta = max(NV, NL);n";
- source += "float sinAlpha = sqrt(1.0 - cosAlpha * cosAlpha);n";
- source += "float sinBeta = sqrt(1.0 - cosBeta * cosBeta);n";
- source += "float tanBeta = sinBeta / cosBeta;n";
- source += "float cosAzimuth = dot(normalize(eye - gl_Normal * NV), normalize(light - gl_Normal * NL));n";
- // TODO: precalculate these constants; place them in uniform values
- source += "float roughness2 = 0.7 * 0.7;n";
- source += "float A = 1.0f - (0.5f * roughness2) / (roughness2 + 0.33);n";
- source += "float B = (0.45f * roughness2) / (roughness2 + 0.09);n";
- // TODO: add normalization factor so that max brightness is always 1
- // TODO: add gamma correction
- source += "float d = NL * (A + B * sinAlpha * tanBeta * max(0.0, cosAzimuth));n";
- if (props.usesShadows())
- {
- source += SeparateDiffuse(i) += " = d;n";
- }
- else
- {
- source += "diff.rgb += " + LightProperty(i, "diffuse") + " * d;n";
- }
- }
- else if (props.lightModel == ShaderProperties::LunarLambertModel)
- {
- source += AssignDiffuse(i, props) + " mix(NL, NL / (max(NV, 0.001) + NL), lunarLambert);n";
- }
- else if (props.usesShadows())
- {
- // When there are shadows, we need to track the diffuse contributions
- // separately for each light.
- source += SeparateDiffuse(i) + " = NL;n";
- if (props.hasSpecular())
- {
- source += SeparateSpecular(i) + " = pow(NH, shininess);n";
- }
- }
- else
- {
- source += "diff.rgb += " + LightProperty(i, "diffuse") + " * NL;n";
- if (props.hasSpecular())
- {
- source += "spec.rgb += " + LightProperty(i, "specular") +
- " * (pow(NH, shininess) * NL);n";
- }
- }
- if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
- {
- source += "totalLight += NL * " + LightProperty(i, "brightness") + ";n";
- }
- return source;
- }
- static string
- BeginLightSourceShadows(const ShaderProperties& props, unsigned int light)
- {
- string source;
- if (props.usesTangentSpaceLighting())
- {
- if (props.hasShadowsForLight(light))
- source += "shadow = 1.0;n";
- }
- else
- {
- source += "shadow = " + SeparateDiffuse(light) + ";n";
- }
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- 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;
- }
- // Calculate the depth of an eclipse shadow at the current fragment. Eclipse
- // shadows are circular, decreasing in depth from maxDepth at the center to
- // zero at the edge of the penumbra.
- // Eclipse shadows are approximate. They assume that the both the sun and
- // occluding body are spherical. An oblate planet is treated as if its polar
- // radius were equal to its equatorial radius. This produces quite accurate
- // eclipses for major moons around giant planets, which orbit close to the
- // equatorial plane of the planet.
- //
- // The radius of the shadow umbra and penumbra are computed accurately
- // (to the limit of the spherical approximation.) The maximum shadow depth
- // is also calculated accurately. However, the shadow falloff from from
- // the umbra to the edge of the penumbra is approximated as linear.
- static string
- Shadow(unsigned int light, unsigned int shadow)
- {
- string source;
- 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";
- // The shadow shadow consists of a circular region of constant depth (maxDepth),
- // surrounded by a ring of linear falloff from maxDepth to zero. For a total
- // eclipse, maxDepth is zero. In reality, the falloff function is much more complex:
- // to calculate the exact amount of sunlight blocked, we need to calculate the
- // a circle-circle intersection area.
- // (See http://mathworld.wolfram.com/Circle-CircleIntersection.html)
-
- // The code generated below will compute:
- // r = 2 * sqrt(dot(shadowCenter, shadowCenter));
- // shadowR = clamp((r - 1) * shadowFalloff, 0, shadowMaxDepth)
- source += "shadowR = clamp((2.0 * sqrt(dot(shadowCenter, shadowCenter)) - 1.0) * " +
- IndexedParameter("shadowFalloff", light, shadow) + ", 0.0, " +
- IndexedParameter("shadowMaxDepth", light, shadow) + ");n";
-
- source += "shadow *= 1.0 - shadowR;n";
- return source;
- }
- static string
- ShadowsForLightSource(const ShaderProperties& props, unsigned int light)
- {
- string source = BeginLightSourceShadows(props, light);
- for (unsigned int i = 0; i < props.getShadowCountForLight(light); i++)
- source += Shadow(light, i);
- return source;
- }
- static string
- ScatteringPhaseFunctions(const ShaderProperties&)
- {
- string source;
- // Evaluate the Mie and Rayleigh phase functions; both are functions of the cosine
- // of the angle between the view vector and light vector
- source += " float phMie = (1.0 - mieK * mieK) / ((1.0 - mieK * cosTheta) * (1.0 - mieK * cosTheta));n";
- // Ignore Rayleigh phase function and treat Rayleigh scattering as isotropic
- // source += " float phRayleigh = (1.0 + cosTheta * cosTheta);n";
- source += " float phRayleigh = 1.0;n";
- return source;
- }
- static string
- AtmosphericEffects(const ShaderProperties& props)
- {
- string source;
- source += "{n";
- // Compute the intersection of the view direction and the cloud layer (currently assumed to be a sphere)
- source += " float rq = dot(eyePosition, eyeDir);n";
- source += " float qq = dot(eyePosition, eyePosition) - atmosphereRadius.y;n";
- source += " float d = sqrt(rq * rq - qq);n";
- source += " vec3 atmEnter = eyePosition + min(0.0, (-rq + d)) * eyeDir;n";
- source += " vec3 atmLeave = gl_Vertex.xyz;n";
- source += " vec3 atmSamplePoint = (atmEnter + atmLeave) * 0.5;n";
- //source += " vec3 atmSamplePoint = atmEnter * 0.2 + atmLeave * 0.8;n";
- // Compute the distance through the atmosphere from the sample point to the sun
- source += " vec3 atmSamplePointSun = atmEnter * 0.5 + atmLeave * 0.5;n";
- source += " rq = dot(atmSamplePointSun, " + LightProperty(0, "direction") + ");n";
- source += " qq = dot(atmSamplePointSun, atmSamplePointSun) - atmosphereRadius.y;n";
- source += " d = sqrt(rq * rq - qq);n";
- source += " float distSun = -rq + d;n";
- source += " float distAtm = length(atmEnter - atmLeave);n";
- // Compute the density of the atmosphere at the sample point; it falls off exponentially
- // with the height above the planet's surface.
- #if 0
- source += " float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
- source += " float density = exp(-h * mieH);n";
- #else
- source += " float density = 0.0;n";
- source += " atmSamplePoint = atmEnter * 0.333 + atmLeave * 0.667;n";
- //source += " atmSamplePoint = atmEnter * 0.1 + atmLeave * 0.9;n";
- source += " float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
- source += " density += exp(-h * mieH);n";
- source += " atmSamplePoint = atmEnter * 0.667 + atmLeave * 0.333;n";
- //source += " atmSamplePoint = atmEnter * 0.9 + atmLeave * 0.1;n";
- source += " h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
- source += " density += exp(-h * mieH);n";
- #endif
- bool hasAbsorption = true;
- if (hasAbsorption)
- {
- source += " vec3 sunColor = exp(-extinctionCoeff * density * distSun);n";
- source += " vec3 ex = exp(-extinctionCoeff * density * distAtm);n";
- }
- else
- {
- source += " vec3 sunColor = exp(-scatterCoeffSum * density * distSun);n";
- source += " vec3 ex = exp(-scatterCoeffSum * density * distAtm);n";
- }
- string scatter;
- if (hasAbsorption)
- {
- scatter = "(1.0 - exp(-scatterCoeffSum * density * distAtm))";
- }
- else
- {
- // If there's no absorption, the extinction coefficients are just the scattering coefficients,
- // so there's no need to recompute the scattering.
- scatter = "(1.0 - ex)";
- }
- // If we're rendering the sky dome, compute the phase functions in the fragment shader
- // rather than the vertex shader in order to avoid artifacts from coarse tessellation.
- if (props.lightModel == ShaderProperties::AtmosphereModel)
- {
- source += " scatterEx = ex;n";
- source += " " + ScatteredColor(0) + " = sunColor * " + scatter + ";n";
- }
- else
- {
- source += " float cosTheta = dot(eyeDir, " + LightProperty(0, "direction") + ");n";
- source += ScatteringPhaseFunctions(props);
- source += " scatterEx = ex;n";
- source += " " + VarScatterInVS() + " = (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * sunColor * " + scatter + ";n";
- }
- // Optional exposure control
- //source += " 1.0 - (scatterIn * exp(-5.0 * max(scatterIn.x, max(scatterIn.y, scatterIn.z))));n";
- source += "}n";
- return source;
- }
- #if 0
- // Integrate the atmosphere by summation--slow, but higher quality
- static string
- AtmosphericEffects(const ShaderProperties& props, unsigned int nSamples)
- {
- string source;
- source += "{n";
- // Compute the intersection of the view direction and the cloud layer (currently assumed to be a sphere)
- source += " float rq = dot(eyePosition, eyeDir);n";
- source += " float qq = dot(eyePosition, eyePosition) - atmosphereRadius.y;n";
- source += " float d = sqrt(rq * rq - qq);n";
- source += " vec3 atmEnter = eyePosition + min(0.0, (-rq + d)) * eyeDir;n";
- source += " vec3 atmLeave = gl_Vertex.xyz;n";
- source += " vec3 step = (atmLeave - atmEnter) * (1.0 / 10.0);n";
- source += " float stepLength = length(step);n";
- source += " vec3 atmSamplePoint = atmEnter + step * 0.5;n";
- source += " vec3 scatter = vec3(0.0, 0.0, 0.0);n";
- source += " vec3 ex = vec3(1.0);n";
- source += " float tau = 0.0;n";
- source += " for (int i = 0; i < 10; ++i) {n";
- // Compute the distance through the atmosphere from the sample point to the sun
- source += " rq = dot(atmSamplePoint, " + LightProperty(0, "direction") + ");n";
- source += " qq = dot(atmSamplePoint, atmSamplePoint) - atmosphereRadius.y;n";
- source += " d = sqrt(rq * rq - qq);n";
- source += " float distSun = -rq + d;n";
- // Compute the density of the atmosphere at the sample point; it falls off exponentially
- // with the height above the planet's surface.
- source += " float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
- source += " float d = exp(-h * mieH);n";
- source += " tau += d * stepLength;n";
- source += " vec3 sunColor = exp(-extinctionCoeff * d * distSun);n";
- source += " ex = exp(-extinctionCoeff * tau);n";
- source += " scatter += ex * sunColor * d * 0.1;n";
- source += " atmSamplePoint += step;n";
- source += " }n";
- // If we're rendering the sky dome, compute the phase functions in the fragment shader
- // rather than the vertex shader in order to avoid artifacts from coarse tessellation.
- if (props.lightModel == ShaderProperties::AtmosphereModel)
- {
- source += " scatterEx = ex;n";
- source += " " + ScatteredColor(i) + " = scatter;n";
- }
- else
- {
- source += " float cosTheta = dot(eyeDir, " + LightProperty(0, "direction") + ");n";
- source += ScatteringPhaseFunctions(props);
- source += " scatterEx = ex;n";
- source += " " + VarScatterInVS() + " = (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * scatter;n";
- }
- // Optional exposure control
- //source += " 1.0 - (" + VarScatterInVS() + " * exp(-5.0 * max(scatterIn.x, max(scatterIn.y, scatterIn.z))));n";
- source += "}n";
- return source;
- }
- #endif
- string
- ScatteringConstantDeclarations(const ShaderProperties& /*props*/)
- {
- string source;
- source += "uniform vec3 atmosphereRadius;n";
- source += "uniform float mieCoeff;n";
- source += "uniform float mieH;n";
- source += "uniform float mieK;n";
- source += "uniform vec3 rayleighCoeff;n";
- source += "uniform float rayleighH;n";
- source += "uniform vec3 scatterCoeffSum;n";
- source += "uniform vec3 invScatterCoeffSum;n";
- source += "uniform vec3 extinctionCoeff;n";
- return source;
- }
- string
- TextureSamplerDeclarations(const ShaderProperties& props)
- {
- string source;
- // Declare texture samplers
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source += "uniform sampler2D diffTex;n";
- }
- if (props.texUsage & ShaderProperties::NormalTexture)
- {
- source += "uniform sampler2D normTex;n";
- }
- if (props.texUsage & ShaderProperties::SpecularTexture)
- {
- source += "uniform sampler2D specTex;n";
- }
- if (props.texUsage & ShaderProperties::NightTexture)
- {
- source += "uniform sampler2D nightTex;n";
- }
- if (props.texUsage & ShaderProperties::EmissiveTexture)
- {
- source += "uniform sampler2D emissiveTex;n";
- }
- if (props.texUsage & ShaderProperties::OverlayTexture)
- {
- source += "uniform sampler2D overlayTex;n";
- }
- return source;
- }
- string
- TextureCoordDeclarations(const ShaderProperties& props)
- {
- string source;
- if (props.hasSharedTextureCoords())
- {
- // If the shared texture coords flag is set, use the diffuse texture
- // coordinate for sampling all the texture maps.
- if (props.texUsage & (ShaderProperties::DiffuseTexture |
- ShaderProperties::NormalTexture |
- ShaderProperties::SpecularTexture |
- ShaderProperties::NightTexture |
- ShaderProperties::EmissiveTexture |
- ShaderProperties::OverlayTexture))
- {
- source += "varying vec2 diffTexCoord;n";
- }
- }
- else
- {
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- source += "varying vec2 diffTexCoord;n";
- if (props.texUsage & ShaderProperties::NormalTexture)
- source += "varying vec2 normTexCoord;n";
- if (props.texUsage & ShaderProperties::SpecularTexture)
- source += "varying vec2 specTexCoord;n";
- if (props.texUsage & ShaderProperties::NightTexture)
- source += "varying vec2 nightTexCoord;n";
- if (props.texUsage & ShaderProperties::EmissiveTexture)
- source += "varying vec2 emissiveTexCoord;n";
- if (props.texUsage & ShaderProperties::OverlayTexture)
- source += "varying vec2 overlayTexCoord;n";
- }
- return source;
- }
- string
- PointSizeCalculation()
- {
- return string("gl_PointSize = pointScale * pointSize / length(vec3(gl_ModelViewMatrix * gl_Vertex));n");
- }
- GLVertexShader*
- ShaderManager::buildVertexShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += DeclareLights(props);
- if (props.lightModel == ShaderProperties::SpecularModel)
- source += "uniform float shininess;n";
- source += "uniform vec3 eyePosition;n";
- source += TextureCoordDeclarations(props);
- source += "uniform float textureOffset;n";
- if (props.hasScattering())
- {
- source += ScatteringConstantDeclarations(props);
- }
- if (props.isViewDependent() || props.hasScattering())
- {
- source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- if (!props.usesTangentSpaceLighting())
- source += "float NV = dot(gl_Normal, eyeDir);n";
- }
- if (props.texUsage & ShaderProperties::PointSprite)
- {
- source += "uniform float pointScale;n";
- source += "attribute float pointSize;n";
- }
- if (props.usesTangentSpaceLighting())
- {
- source += "attribute vec3 tangent;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "varying vec3 " + LightDir_tan(i) + ";n";
- }
- if (props.isViewDependent() &&
- props.lightModel != ShaderProperties::SpecularModel)
- {
- source += "varying vec3 eyeDir_tan;n";
- }
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "varying vec4 diffFactors;n";
- source += "varying vec3 normal;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "varying vec3 " + LightHalfVector(i) + ";n";
- }
- }
- else if (props.usesShadows())
- {
- source += "varying vec4 diffFactors;n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "varying vec4 specFactors;n";
- source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- }
- }
- else
- {
- source += "uniform vec3 ambientColor;n";
- source += "uniform float opacity;n";
- source += "varying vec4 diff;n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "varying vec4 spec;n";
- source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- }
- }
- // If this shader uses tangent space lighting, the diffuse term
- // will be calculated in the fragment shader and we won't need
- // the lunar-Lambert term here in the vertex shader.
- if (!props.usesTangentSpaceLighting())
- {
- if (props.lightModel == ShaderProperties::LunarLambertModel)
- source += "uniform float lunarLambert;n";
- }
- // Miscellaneous lighting values
- if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
- {
- source += "varying float totalLight;n";
- }
- if (props.hasScattering())
- {
- //source += "varying vec3 scatterIn;n";
- source += "varying vec3 scatterEx;n";
- }
- // Shadow parameters
- if (props.shadowCounts != 0)
- {
- source += "varying vec3 position_obj;n";
- }
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- source += "uniform float ringWidth;n";
- source += "uniform float ringRadius;n";
- 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";
- source += "float NL;n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "float NH;n";
- source += "vec3 H;n";
- }
- if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
- {
- source += "totalLight = 0.0;n";
- }
- if (props.usesTangentSpaceLighting())
- {
- source += "vec3 bitangent = cross(gl_Normal, tangent);n";
- if (props.isViewDependent() &&
- props.lightModel != ShaderProperties::SpecularModel)
- {
- source += TangentSpaceTransform("eyeDir_tan", "eyeDir");
- }
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "normal = gl_Normal;n";
- }
- else if (props.usesShadows())
- {
- }
- else
- {
- source += "diff = vec4(ambientColor, opacity);n";
- if (props.hasSpecular())
- source += "spec = vec4(0.0, 0.0, 0.0, 0.0);n";
- }
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += AddDirectionalLightContrib(i, props);
- }
- if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
- {
- source += NightTextureBlend();
- }
- unsigned int nTexCoords = 0;
- // Output the texture coordinates. Use just a single texture coordinate if all textures are mapped
- // identically. The texture offset is added for cloud maps; specular and night texture are not offset
- // because cloud layers never have these textures.
- if (props.hasSharedTextureCoords())
- {
- if (props.texUsage & (ShaderProperties::DiffuseTexture |
- ShaderProperties::NormalTexture |
- ShaderProperties::SpecularTexture |
- ShaderProperties::NightTexture |
- ShaderProperties::EmissiveTexture |
- ShaderProperties::OverlayTexture))
- {
- source += "diffTexCoord = " + TexCoord2D(nTexCoords) + ";n";
- source += "diffTexCoord.x += textureOffset;n";
- }
- }
- else
- {
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source += "diffTexCoord = " + TexCoord2D(nTexCoords) + " + vec2(textureOffset, 0.0);n";
- nTexCoords++;
- }
- if (!props.hasSharedTextureCoords())
- {
- if (props.texUsage & ShaderProperties::NormalTexture)
- {
- source += "normTexCoord = " + TexCoord2D(nTexCoords) + " + vec2(textureOffset, 0.0);n";
- nTexCoords++;
- }
- if (props.texUsage & ShaderProperties::SpecularTexture)
- {
- source += "specTexCoord = " + TexCoord2D(nTexCoords) + ";n";
- nTexCoords++;
- }
- if (props.texUsage & ShaderProperties::NightTexture)
- {
- source += "nightTexCoord = " + TexCoord2D(nTexCoords) + ";n";
- nTexCoords++;
- }
- if (props.texUsage & ShaderProperties::EmissiveTexture)
- {
- source += "emissiveTexCoord = " + TexCoord2D(nTexCoords) + ";n";
- nTexCoords++;
- }
- }
- }
- // Shadow texture coordinates are generated in the shader
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- source += "vec3 ringShadowProj;n";
- for (unsigned int j = 0; j < props.nLights; j++)
- {
- source += "ringShadowProj = gl_Vertex.xyz + " +
- LightProperty(j, "direction") +
- " * max(0.0, gl_Vertex.y / -" +
- LightProperty(j, "direction") + ".y);n";
- source += RingShadowTexCoord(j) +
- " = (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";
- // Disabled: there are too many problems with this approach,
- // though it should theoretically work. The inverse trig
- // approximations produced by the shader compiler are crude
- // enough that visual anomalies are apparent. And in the current
- // GeForce 8800 driver, this shader produces an internal compiler
- // error. Cloud shadows are trivial if the cloud texture is a cube
- // map. Also, DX10 capable hardware could efficiently perform
- // the rect-to-spherical conversion in the pixel shader with an
- // fp32 texture serving as a lookup table.
- #if 0
- // Compute the intersection of the sun direction and the cloud layer (currently assumed to be a sphere)
- source += " float rq = dot(" + LightProperty(j, "direction") + ", gl_Vertex.xyz);n";
- source += " float qq = dot(gl_Vertex.xyz, gl_Vertex.xyz) - cloudHeight * cloudHeight;n";
- source += " float d = sqrt(rq * rq - qq);n";
- source += " vec3 cloudSpherePos = (gl_Vertex.xyz + (-rq + d) * " + LightProperty(j, "direction") + ");n";
- //source += " vec3 cloudSpherePos = gl_Vertex.xyz;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 += " float invPi = 1.0 / 3.1415927;n";
- source += " " + CloudShadowTexCoord(j) + ".y = 0.5 - asin(cloudSpherePos.y) * invPi;n";
- source += " float u = fract(atan(cloudSpherePos.x, cloudSpherePos.z) * (invPi * 0.5) + 0.75);n";
- source += " if (diffTexCoord.x < 0.25 && u > 0.5) u -= 1.0;n";
- source += " else if (diffTexCoord.x > 0.75 && u < 0.5) u += 1.0;n";
- source += " " + CloudShadowTexCoord(j) + ".x = u + cloudShadowTexOffset;n";
- #endif
- source += "}n";
- }
- }
- if (props.hasScattering())
- {
- source += AtmosphericEffects(props);
- }
- if ((props.texUsage & ShaderProperties::OverlayTexture) && !props.hasSharedTextureCoords())
- {
- source += "overlayTexCoord = " + TexCoord2D(nTexCoords) + ";n";
- nTexCoords++;
- }
- if (props.shadowCounts != 0)
- {
- source += "position_obj = gl_Vertex.xyz;n";
- }
- if ((props.texUsage & ShaderProperties::PointSprite) != 0)
- source += PointSizeCalculation();
- source += "gl_Position = ftransform();n";
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Vertex shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLVertexShader* vs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return vs;
- }
- GLFragmentShader*
- ShaderManager::buildFragmentShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- string diffTexCoord("diffTexCoord");
- string specTexCoord("specTexCoord");
- string nightTexCoord("nightTexCoord");
- string emissiveTexCoord("emissiveTexCoord");
- string normTexCoord("normTexCoord");
- if (props.hasSharedTextureCoords())
- {
- specTexCoord = diffTexCoord;
- nightTexCoord = diffTexCoord;
- normTexCoord = diffTexCoord;
- emissiveTexCoord = diffTexCoord;
- }
- source += TextureSamplerDeclarations(props);
- source += TextureCoordDeclarations(props);
- // Declare lighting parameters
- if (props.usesTangentSpaceLighting())
- {
- source += "uniform vec3 ambientColor;n";
- source += "uniform float opacity;n";
- source += "vec4 diff = vec4(ambientColor, opacity);n";
- if (props.isViewDependent())
- {
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- // Specular model is sort of a hybrid: all the view-dependent lighting is
- // handled in the vertex shader, and the fragment shader is view-independent
- source += "varying vec4 specFactors;n";
- source += "vec4 spec = vec4(0.0);n";
- }
- else
- {
- source += "varying vec3 eyeDir_tan;n"; // tangent space eye vector
- source += "vec4 spec = vec4(0.0);n";
- source += "uniform float shininess;n";
- }
- }
- if (props.lightModel == ShaderProperties::LunarLambertModel)
- source += "uniform float lunarLambert;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "varying vec3 " + LightDir_tan(i) + ";n";
- source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
- if (props.hasSpecular())
- {
- source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
- }
- if (props.texUsage & ShaderProperties::NightTexture)
- {
- source += "uniform float " + FragLightProperty(i, "brightness") + ";n";
- }
- }
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "uniform vec3 ambientColor;n";
- source += "uniform float opacity;n";
- source += "varying vec4 diffFactors;n";
- source += "vec4 diff = vec4(ambientColor, opacity);n";
- source += "varying vec3 normal;n";
- source += "vec4 spec = vec4(0.0);n";
- source += "uniform float shininess;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "varying vec3 " + LightHalfVector(i) + ";n";
- source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
- source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
- }
- }
- else if (props.usesShadows())
- {
- source += "uniform vec3 ambientColor;n";
- source += "uniform float opacity;n";
- source += "vec4 diff = vec4(ambientColor, opacity);n";
- source += "varying vec4 diffFactors;n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "varying vec4 specFactors;n";
- source += "vec4 spec = vec4(0.0);n";
- }
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
- }
- }
- else
- {
- source += "varying vec4 diff;n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "varying vec4 spec;n";
- }
- }
- if (props.hasScattering())
- {
- //source += "varying vec3 scatterIn;n";
- source += "varying vec3 scatterEx;n";
- }
- if ((props.texUsage & ShaderProperties::NightTexture))
- {
- #ifdef USE_HDR
- source += "uniform float nightLightScale;n";
- #endif
- if (VSComputesColorSum(props))
- {
- source += "varying float totalLight;n";
- }
- }
- // 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 += "uniform vec4 " +
- IndexedParameter("shadowTexGenS", i, j) + ";n";
- source += "uniform vec4 " +
- IndexedParameter("shadowTexGenT", i, j) + ";n";
- source += "uniform float " +
- IndexedParameter("shadowFalloff", i, j) + ";n";
- source += "uniform float " +
- IndexedParameter("shadowMaxDepth", i, j) + ";n";
- }
- }
- }
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- 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";
- if (props.usesShadows())
- {
- // Temporaries required for shadows
- source += "float shadow;n";
- if (props.shadowCounts != 0)
- {
- source += "vec2 shadowCenter;n";
- source += "float shadowR;n";
- }
- }
- // Sum the illumination from each light source, computing a total diffuse and specular
- // contributions from all sources.
- if (props.usesTangentSpaceLighting())
- {
- // Get the normal in tangent space. Ordinarily it comes from the normal texture, but if one
- // isn't provided, we'll simulate a smooth surface by using a constant (in tangent space)
- // normal of [ 0 0 1 ]
- if (props.texUsage & ShaderProperties::NormalTexture)
- {
- if (props.texUsage & ShaderProperties::CompressedNormalTexture)
- {
- source += "vec3 n;n";
- source += "n.xy = texture2D(normTex, " + normTexCoord + ".st).ag * 2.0 - vec2(1.0, 1.0);n";
- source += "n.z = sqrt(1.0 - n.x * n.x - n.y * n.y);n";
- }
- else
- {
- // TODO: normalizing the filtered normal texture value noticeably improves the appearance; add
- // an option for this.
- //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
- {
- source += "vec3 n = vec3(0.0, 0.0, 1.0);n";
- }
- source += "float l;n";
- if (props.isViewDependent())
- {
- source += "vec3 V = normalize(eyeDir_tan);n";
- if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "vec3 H;n";
- source += "float NH;n";
- }
- else if (props.lightModel == ShaderProperties::LunarLambertModel)
- {
- source += "float NV = dot(n, V);n";
- }
- }
- source += "float NL;n";
- for (unsigned i = 0; i < props.nLights; i++)
- {
- // Bump mapping with self shadowing
- // TODO: normalize the light direction (optionally--not as important for finely tesselated
- // geometry like planet spheres.)
- // source += LightDir_tan(i) + " = normalize(" + LightDir(i)_tan + ");n";
- source += "NL = dot(" + LightDir_tan(i) + ", n);n";
- if (props.lightModel == ShaderProperties::LunarLambertModel)
- {
- source += "NL = max(0.0, NL);n";
- source += "l = mix(NL, (NL / (max(NV, 0.001) + NL)), lunarLambert) * clamp(" + LightDir_tan(i) + ".z * 8.0, 0.0, 1.0);n";
- }
- else
- {
- source += "l = max(0.0, dot(" + LightDir_tan(i) + ", n)) * clamp(" + LightDir_tan(i) + ".z * 8.0, 0.0, 1.0);n";
- }
- if ((props.texUsage & ShaderProperties::NightTexture) &&
- !VSComputesColorSum(props))
- {
- if (i == 0)
- source += "float totalLight = ";
- else
- source += "totalLight += ";
- source += "l * " + FragLightProperty(i, "brightness") + ";n";
- }
- string illum;
- if (props.hasShadowsForLight(i))
- illum = string("l * shadow");
- else
- illum = string("l");
- if (props.hasShadowsForLight(i))
- source += ShadowsForLightSource(props, i);
- source += "diff.rgb += " + illum + " * " +
- FragLightProperty(i, "color") + ";n";
- if (props.lightModel == ShaderProperties::SpecularModel && props.usesShadows())
- {
- source += "spec.rgb += " + illum + " * " + SeparateSpecular(i) +
- " * " + FragLightProperty(i, "specColor") +
- ";n";
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "H = normalize(eyeDir_tan + " + LightDir_tan(i) + ");n";
- source += "NH = max(0.0, dot(n, H));n";
- source += "spec.rgb += " + illum + " * pow(NH, shininess) * " + FragLightProperty(i, "specColor") + ";n";
- }
- }
- }
- else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
- {
- source += "float NH;n";
- source += "vec3 n = normalize(normal);n";
- // Sum the contributions from each light source
- for (unsigned i = 0; i < props.nLights; i++)
- {
- string illum;
- if (props.hasShadowsForLight(i))
- illum = string("shadow");
- else
- illum = SeparateDiffuse(i);
- if (props.hasShadowsForLight(i))
- source += ShadowsForLightSource(props, i);
- source += "diff.rgb += " + illum + " * " + FragLightProperty(i, "color") + ";n";
- source += "NH = max(0.0, dot(n, normalize(" + LightHalfVector(i) + ")));n";
- source += "spec.rgb += " + illum + " * pow(NH, shininess) * " + FragLightProperty(i, "specColor") + ";n";
- }
- }
- else if (props.usesShadows())
- {
- // Sum the contributions from each light source
- for (unsigned i = 0; i < props.nLights; i++)
- {
- source += ShadowsForLightSource(props, i);
- source += "diff.rgb += shadow * " +
- FragLightProperty(i, "color") + ";n";
- if (props.lightModel == ShaderProperties::SpecularModel)
- {
- source += "spec.rgb += shadow * " + SeparateSpecular(i) +
- " * " +
- FragLightProperty(i, "specColor") + ";n";
- }
- }
- }
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- if (props.texUsage & ShaderProperties::PointSprite)
- source += "color = texture2D(diffTex, gl_TexCoord[0].st);n";
- else
- source += "color = texture2D(diffTex, " + diffTexCoord + ".st);n";
- }
- else
- {
- source += "color = vec4(1.0, 1.0, 1.0, 1.0);n";
- }
- // Mix in the overlay color with the base color
- if (props.texUsage & ShaderProperties::OverlayTexture)
- {
- source += "vec4 overlayColor = texture2D(overlayTex, overlayTexCoord.st);n";
- source += "color.rgb = mix(color.rgb, overlayColor.rgb, overlayColor.a);n";
- }
- if (props.hasSpecular())
- {
- // Add in the specular color
- if (props.texUsage & ShaderProperties::SpecularInDiffuseAlpha)
- source += "gl_FragColor = color * diff + float(color.a) * spec;n";
- else if (props.texUsage & ShaderProperties::SpecularTexture)
- source += "gl_FragColor = color * diff + texture2D(specTex, " + specTexCoord + ".st) * spec;n";
- else
- source += "gl_FragColor = color * diff + spec;n";
- }
- else
- {
- source += "gl_FragColor = color * diff;n";
- }
- // Add in the emissive color
- // TODO: support a constant emissive color, not just an emissive texture
- if (props.texUsage & ShaderProperties::NightTexture)
- {
- // If the night texture blend factor wasn't computed in the vertex
- // shader, we need to do so now.
- if (!VSComputesColorSum(props))
- {
- if (!props.usesTangentSpaceLighting())
- {
- source += "float totalLight = ";
-
- if (props.nLights == 0)
- {
- source += "0.0fn";
- }
- else
- {
- int k;
- for (k = 0; k < props.nLights - 1; k++)
- source += SeparateDiffuse(k) + " + ";
- source += SeparateDiffuse(k) + ";n";
- }
- }
- source += NightTextureBlend();
- }
- #ifdef USE_HDR
- source += "gl_FragColor += texture2D(nightTex, " + nightTexCoord + ".st) * totalLight * nightLightScale;n";
- #else
- source += "gl_FragColor += texture2D(nightTex, " + nightTexCoord + ".st) * totalLight;n";
- #endif
- }
- if (props.texUsage & ShaderProperties::EmissiveTexture)
- {
- source += "gl_FragColor += texture2D(emissiveTex, " + emissiveTexCoord + ".st);n";
- }
- // Include the effect of atmospheric scattering.
- if (props.hasScattering())
- {
- source += "gl_FragColor.rgb = gl_FragColor.rgb * scatterEx + " + VarScatterInFS() + ";n";
- }
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Fragment shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLFragmentShader* fs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return fs;
- }
- GLVertexShader*
- ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += DeclareLights(props);
- source += "uniform vec3 eyePosition;n";
- source += "varying vec4 diffFactors;n";
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- source += "varying vec2 diffTexCoord;n";
- if (props.shadowCounts != 0)
- {
- source += "varying vec3 position_obj;n";
- source += "varying vec4 shadowDepths;n";
- }
- source += "nvoid main(void)n{n";
- // Get the normalized direction from the eye to the vertex
- source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += SeparateDiffuse(i) + " = (dot(" +
- LightProperty(i, "direction") + ", eyeDir) + 1.0) * 0.5;n";
- }
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- source += "diffTexCoord = " + TexCoord2D(0) + ";n";
- if (props.shadowCounts != 0)
- {
- source += "position_obj = gl_Vertex.xyz;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += ShadowDepth(i) + " = dot(gl_Vertex.xyz, " +
- LightProperty(i, "direction") + ");n";
- }
- }
- source += "gl_Position = ftransform();n";
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Vertex shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLVertexShader* vs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return vs;
- }
- GLFragmentShader*
- ShaderManager::buildRingsFragmentShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += "uniform vec3 ambientColor;n";
- source += "vec4 diff = vec4(ambientColor, 1.0);n";
- for (unsigned int i = 0; i < props.nLights; i++)
- source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
- source += "varying vec4 diffFactors;n";
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source += "varying vec2 diffTexCoord;n";
- 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++)
- {
- 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("shadowFalloff", i, j) + ";n";
- source += "uniform float " +
- IndexedParameter("shadowMaxDepth", i, j) + ";n";
- }
- }
- }
- source += "nvoid main(void)n{n";
- source += "vec4 color;n";
- if (props.usesShadows())
- {
- // Temporaries required for shadows
- source += "float shadow;n";
- source += "vec2 shadowCenter;n";
- source += "float shadowR;n";
- }
- // Sum the contributions from each light source
- for (unsigned i = 0; i < props.nLights; i++)
- {
- if (props.usesShadows())
- {
- source += "shadow = 1.0;n";
- source += Shadow(i, 0);
- source += "shadow = min(1.0, shadow + step(0.0, " + ShadowDepth(i) + "));n";
- source += "diff.rgb += (shadow * " + SeparateDiffuse(i) + ") * " +
- FragLightProperty(i, "color") + ";n";
- }
- else
- {
- source += "diff.rgb += " + SeparateDiffuse(i) + " * " +
- FragLightProperty(i, "color") + ";n";
- }
- }
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- source += "color = texture2D(diffTex, diffTexCoord.st);n";
- else
- source += "color = vec4(1.0, 1.0, 1.0, 1.0);n";
- source += "gl_FragColor = color * diff;n";
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Fragment shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLFragmentShader* fs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return fs;
- }
- GLVertexShader*
- ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += DeclareLights(props);
- source += "uniform vec3 eyePosition;n";
- source += ScatteringConstantDeclarations(props);
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source += "varying vec3 " + ScatteredColor(i) + ";n";
- }
- source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- source += "float NV = dot(gl_Normal, eyeDir);n";
- source += "varying vec3 scatterEx;n";
- source += "varying vec3 eyeDir_obj;n";
- // Begin main() function
- source += "nvoid main(void)n{n";
- source += "float NL;n";
- source += AtmosphericEffects(props);
- source += "eyeDir_obj = eyeDir;n";
- source += "gl_Position = ftransform();n";
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Vertex shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLVertexShader* vs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return vs;
- }
- GLFragmentShader*
- ShaderManager::buildAtmosphereFragmentShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += "varying vec3 scatterEx;n";
- source += "varying vec3 eyeDir_obj;n";
- // Scattering constants
- source += "uniform float mieK;n";
- source += "uniform float mieCoeff;n";
- source += "uniform vec3 rayleighCoeff;n";
- source += "uniform vec3 invScatterCoeffSum;n";
- unsigned int i;
- for (i = 0; i < props.nLights; i++)
- {
- source += "uniform vec3 " + LightProperty(i, "direction") + ";n";
- source += "varying vec3 " + ScatteredColor(i) + ";n";
- }
- source += "nvoid main(void)n";
- source += "{n";
- // Sum the contributions from each light source
- source += "vec3 color = vec3(0.0, 0.0, 0.0);n";
- source += "vec3 V = normalize(eyeDir_obj);n";
- // Only do scattering calculations for the primary light source
- // TODO: Eventually handle multiple light sources, and removed the 'min'
- // from the line below.
- for (i = 0; i < min((unsigned int) props.nLights, 1u); i++)
- {
- source += " float cosTheta = dot(V, " + LightProperty(i, "direction") + ");n";
- source += ScatteringPhaseFunctions(props);
- // TODO: Consider premultiplying by invScatterCoeffSum
- source += " color += (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * " + ScatteredColor(i) + ";n";
- }
- source += " gl_FragColor = vec4(color, dot(scatterEx, vec3(0.333, 0.333, 0.333)));n";
- source += "}n";
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Fragment shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLFragmentShader* fs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return fs;
- }
- // The emissive shader ignores all lighting and uses the diffuse color
- // as the final fragment color.
- GLVertexShader*
- ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- source += "uniform float opacity;n";
- // There are no light sources used for the emissive light model, but
- // we still need the diffuse property of light 0. For other lighting
- // models, the material color is premultiplied with the light color.
- // Emissive shaders interoperate better with other shaders if they also
- // take the color from light source 0.
- #ifndef USE_GLSL_STRUCTS
- source += string("uniform vec3 light0_diffuse;n");
- #else
- source += string("uniform struct {n vec3 diffuse;n} lights[1];n");
- #endif
- if (props.texUsage & ShaderProperties::PointSprite)
- {
- source += "uniform float pointScale;n";
- source += "attribute float pointSize;n";
- }
- // Begin main() function
- source += "nvoid main(void)n{n";
- // Optional texture coordinates (generated automatically for point
- // sprites.)
- if ((props.texUsage & ShaderProperties::DiffuseTexture) &&
- !(props.texUsage & ShaderProperties::PointSprite))
- {
- source += " gl_TexCoord[0].st = " + TexCoord2D(0) + ";n";
- }
- // Set the color.
- string colorSource;
- if (props.texUsage & ShaderProperties::VertexColors)
- colorSource = "gl_Color.rgb";
- else
- colorSource = LightProperty(0, "diffuse");
- source += " gl_FrontColor = vec4(" + colorSource + ", opacity);n";
- // Optional point size
- if ((props.texUsage & ShaderProperties::PointSprite) != 0)
- source += PointSizeCalculation();
- source += " gl_Position = ftransform();n";
- source += "}n";
- // End of main()
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Vertex shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLVertexShader* vs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return vs;
- }
- GLFragmentShader*
- ShaderManager::buildEmissiveFragmentShader(const ShaderProperties& props)
- {
- string source = CommonHeader;
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source += "uniform sampler2D diffTex;n";
- }
- // Begin main()
- source += "nvoid main(void)n";
- source += "{n";
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source += " gl_FragColor = gl_Color * texture2D(diffTex, gl_TexCoord[0].st);n";
- }
- else
- {
- source += " gl_FragColor = gl_Color;n";
- }
- source += "}n";
- // End of main()
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Fragment shader source:n";
- DumpShaderSource(*g_shaderLogFile, source);
- *g_shaderLogFile << 'n';
- }
- GLFragmentShader* fs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return fs;
- }
- // Build the vertex shader used for rendering particle systems.
- GLVertexShader*
- ShaderManager::buildParticleVertexShader(const ShaderProperties& props)
- {
- ostringstream source;
-
- source << CommonHeader;
-
- source << "// PARTICLE SHADERn";
- source << "// shadow count: " << props.shadowCounts << endl;
-
- source << DeclareLights(props);
-
- source << "uniform vec3 eyePosition;n";
- // TODO: scattering constants
-
- if (props.texUsage & ShaderProperties::PointSprite)
- {
- source << "uniform float pointScale;n";
- source << "attribute float pointSize;n";
- }
-
- // Shadow parameters
- if (props.shadowCounts != 0)
- {
- source << "varying vec3 position_obj;n";
- }
-
- // Begin main() function
- source << "nvoid main(void)n{n";
- #define PARTICLE_PHASE_PARAMETER 0
- #if PARTICLE_PHASE_PARAMETER
- float g = -0.4f;
- float miePhaseAsymmetry = 1.55f * g - 0.55f * g * g * g;
- source << " float mieK = " << miePhaseAsymmetry << ";n";
- source << " vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
- source << " float brightness = 0.0;n";
- for (unsigned int i = 0; i < min(1u, props.nLights); i++)
- {
- source << " {n";
- source << " float cosTheta = dot(" << LightProperty(i, "direction") << ", eyeDir);n";
- source << " float phMie = (1.0 - mieK * mieK) / ((1.0 - mieK * cosTheta) * (1.0 - mieK * cosTheta));n";
- source << " brightness += phMie;n";
- source << " }n";
- }
- #else
- source << " float brightness = 1.0;n";
- #endif
- // Optional texture coordinates (generated automatically for point
- // sprites.)
- if ((props.texUsage & ShaderProperties::DiffuseTexture) &&
- !(props.texUsage & ShaderProperties::PointSprite))
- {
- source << " gl_TexCoord[0].st = " << TexCoord2D(0) << ";n";
- }
-
- // Set the color. Should *always* use vertex colors for color and opacity.
- source << " gl_FrontColor = gl_Color * brightness;n";
-
- // Optional point size
- if ((props.texUsage & ShaderProperties::PointSprite) != 0)
- source << PointSizeCalculation();
-
- source << " gl_Position = ftransform();n";
-
- source << "}n";
- // End of main()
-
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Vertex shader source:n";
- DumpShaderSource(*g_shaderLogFile, source.str());
- *g_shaderLogFile << endl;
- }
-
- GLVertexShader* vs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateVertexShader(source.str(), &vs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return vs;
- }
- GLFragmentShader*
- ShaderManager::buildParticleFragmentShader(const ShaderProperties& props)
- {
- ostringstream source;
- source << CommonHeader;
-
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source << "uniform sampler2D diffTex;n";
- }
- if (props.usesShadows())
- {
- source << "uniform vec3 ambientColor;n";
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- source << "uniform vec3 " << FragLightProperty(i, "color") << ";n";
- }
- }
-
- // 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 << "uniform vec4 " << IndexedParameter("shadowTexGenS", i, j) << ";n";
- source << "uniform vec4 " << IndexedParameter("shadowTexGenT", i, j) << ";n";
- source << "uniform float " << IndexedParameter("shadowFalloff", i, j) << ";n";
- source << "uniform float " << IndexedParameter("shadowMaxDepth", i, j) << ";n";
- }
- }
- }
-
- // Begin main()
- source << "nvoid main(void)n";
- source << "{n";
-
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- source << " gl_FragColor = gl_Color * texture2D(diffTex, gl_TexCoord[0].st);n";
- }
- else
- {
- source << " gl_FragColor = gl_Color;n";
- }
-
- source << "}n";
- // End of main()
-
- if (g_shaderLogFile != NULL)
- {
- *g_shaderLogFile << "Fragment shader source:n";
- DumpShaderSource(*g_shaderLogFile, source.str());
- *g_shaderLogFile << 'n';
- }
-
- GLFragmentShader* fs = NULL;
- GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source.str(), &fs);
- if (status != ShaderStatus_OK)
- return NULL;
- else
- return fs;
- }
- CelestiaGLProgram*
- ShaderManager::buildProgram(const ShaderProperties& props)
- {
- GLProgram* prog = NULL;
- GLShaderStatus status;
- GLVertexShader* vs = NULL;
- GLFragmentShader* fs = NULL;
- if (props.lightModel == ShaderProperties::RingIllumModel)
- {
- vs = buildRingsVertexShader(props);
- fs = buildRingsFragmentShader(props);
- }
- else if (props.lightModel == ShaderProperties::AtmosphereModel)
- {
- vs = buildAtmosphereVertexShader(props);
- fs = buildAtmosphereFragmentShader(props);
- }
- else if (props.lightModel == ShaderProperties::EmissiveModel)
- {
- vs = buildEmissiveVertexShader(props);
- fs = buildEmissiveFragmentShader(props);
- }
- else if (props.lightModel == ShaderProperties::ParticleModel)
- {
- vs = buildParticleVertexShader(props);
- fs = buildParticleFragmentShader(props);
- }
- else
- {
- vs = buildVertexShader(props);
- fs = buildFragmentShader(props);
- }
- if (vs != NULL && fs != NULL)
- {
- status = GLShaderLoader::CreateProgram(*vs, *fs, &prog);
- if (status == ShaderStatus_OK)
- {
- if (props.texUsage & ShaderProperties::NormalTexture)
- {
- // Tangents always in attribute 6 (should be a constant
- // someplace)
- glx::glBindAttribLocationARB(prog->getID(), 6, "tangent");
- }
- if (props.texUsage & ShaderProperties::PointSprite)
- {
- // Point size is always in attribute 7
- glx::glBindAttribLocationARB(prog->getID(), 7, "pointSize");
- }
- status = prog->link();
- }
- }
- else
- {
- status = ShaderStatus_CompileError;
- }
- delete vs;
- delete fs;
- if (status != ShaderStatus_OK)
- {
- // If the shader creation failed for some reason, substitute the
- // error shader.
- status = GLShaderLoader::CreateProgram(errorVertexShaderSource,
- errorFragmentShaderSource,
- &prog);
- if (status != ShaderStatus_OK)
- {
- if (g_shaderLogFile != NULL)
- *g_shaderLogFile << "Failed to create error shader!n";
- }
- else
- {
- status = prog->link();
- }
- }
- if (prog == NULL)
- return NULL;
- else
- return new CelestiaGLProgram(*prog, props);
- }
- CelestiaGLProgram::CelestiaGLProgram(GLProgram& _program,
- const ShaderProperties& _props) :
- program(&_program),
- props(_props)
- {
- initParameters();
- initSamplers();
- };
- CelestiaGLProgram::~CelestiaGLProgram()
- {
- delete program;
- }
- FloatShaderParameter
- CelestiaGLProgram::floatParam(const string& paramName)
- {
- return FloatShaderParameter(program->getID(), paramName.c_str());
- }
- Vec3ShaderParameter
- CelestiaGLProgram::vec3Param(const string& paramName)
- {
- return Vec3ShaderParameter(program->getID(), paramName.c_str());
- }
- Vec4ShaderParameter
- CelestiaGLProgram::vec4Param(const string& paramName)
- {
- return Vec4ShaderParameter(program->getID(), paramName.c_str());
- }
- void
- CelestiaGLProgram::initParameters()
- {
- for (unsigned int i = 0; i < props.nLights; i++)
- {
- lights[i].direction = vec3Param(LightProperty(i, "direction"));
- lights[i].diffuse = vec3Param(LightProperty(i, "diffuse"));
- lights[i].specular = vec3Param(LightProperty(i, "specular"));
- lights[i].halfVector = vec3Param(LightProperty(i, "halfVector"));
- if (props.texUsage & ShaderProperties::NightTexture)
- lights[i].brightness = floatParam(LightProperty(i, "brightness"));
- fragLightColor[i] = vec3Param(FragLightProperty(i, "color"));
- fragLightSpecColor[i] = vec3Param(FragLightProperty(i, "specColor"));
- if (props.texUsage & ShaderProperties::NightTexture)
- fragLightBrightness[i] = floatParam(FragLightProperty(i, "brightness"));
- for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
- {
- shadows[i][j].texGenS =
- vec4Param(IndexedParameter("shadowTexGenS", i, j));
- shadows[i][j].texGenT =
- vec4Param(IndexedParameter("shadowTexGenT", i, j));
- shadows[i][j].falloff =
- floatParam(IndexedParameter("shadowFalloff", i, j));
- shadows[i][j].maxDepth =
- floatParam(IndexedParameter("shadowMaxDepth", i, j));
- }
- }
- if (props.hasSpecular())
- {
- shininess = floatParam("shininess");
- }
- if (props.isViewDependent() || props.hasScattering())
- {
- eyePosition = vec3Param("eyePosition");
- }
- opacity = floatParam("opacity");
- ambientColor = vec3Param("ambientColor");
- #ifdef USE_HDR
- nightLightScale = floatParam("nightLightScale");
- #endif
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- ringWidth = floatParam("ringWidth");
- ringRadius = floatParam("ringRadius");
- }
- textureOffset = floatParam("textureOffset");
- if (props.texUsage & ShaderProperties::CloudShadowTexture)
- {
- cloudHeight = floatParam("cloudHeight");
- shadowTextureOffset = floatParam("cloudShadowTexOffset");
- }
- if (props.hasScattering())
- {
- mieCoeff = floatParam("mieCoeff");
- mieScaleHeight = floatParam("mieH");
- miePhaseAsymmetry = floatParam("mieK");
- rayleighCoeff = vec3Param("rayleighCoeff");
- rayleighScaleHeight = floatParam("rayleighH");
- atmosphereRadius = vec3Param("atmosphereRadius");
- scatterCoeffSum = vec3Param("scatterCoeffSum");
- invScatterCoeffSum = vec3Param("invScatterCoeffSum");
- extinctionCoeff = vec3Param("extinctionCoeff");
- }
- if (props.lightModel == ShaderProperties::LunarLambertModel)
- {
- lunarLambert = floatParam("lunarLambert");
- }
- if ((props.texUsage & ShaderProperties::PointSprite) != 0)
- {
- pointScale = floatParam("pointScale");
- }
- }
- void
- CelestiaGLProgram::initSamplers()
- {
- program->use();
- unsigned int nSamplers = 0;
- if (props.texUsage & ShaderProperties::DiffuseTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "diffTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::NormalTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "normTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::SpecularTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "specTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::NightTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "nightTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::EmissiveTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "emissiveTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::OverlayTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "overlayTex");
- if (slot != -1)
- glx::glUniform1iARB(slot, nSamplers++);
- }
- if (props.texUsage & ShaderProperties::RingShadowTexture)
- {
- int slot = glx::glGetUniformLocationARB(program->getID(), "ringTex");
- 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++);
- }
- }
- void
- CelestiaGLProgram::setLightParameters(const LightingState& ls,
- Color materialDiffuse,
- Color materialSpecular,
- Color materialEmissive
- #ifdef USE_HDR
- ,float _nightLightScale
- #endif
- )
- {
- unsigned int nLights = min(MaxShaderLights, ls.nLights);
- Vec3f diffuseColor(materialDiffuse.red(),
- materialDiffuse.green(),
- materialDiffuse.blue());
- Vec3f specularColor(materialSpecular.red(),
- materialSpecular.green(),
- materialSpecular.blue());
- for (unsigned int i = 0; i < nLights; i++)
- {
- const DirectionalLight& light = ls.lights[i];
- Vec3f lightColor = Vec3f(light.color.red(),
- light.color.green(),
- light.color.blue()) * light.irradiance;
- lights[i].direction = light.direction_obj;
- if (props.usesShadows() ||
- props.usesFragmentLighting() ||
- props.lightModel == ShaderProperties::RingIllumModel)
- {
- fragLightColor[i] = Vec3f(lightColor.x * diffuseColor.x,
- lightColor.y * diffuseColor.y,
- lightColor.z * diffuseColor.z);
- if (props.hasSpecular())
- {
- fragLightSpecColor[i] = Vec3f(lightColor.x * specularColor.x,
- lightColor.y * specularColor.y,
- lightColor.z * specularColor.z);
- }
- fragLightBrightness[i] = max(lightColor.x, max(lightColor.y, lightColor.z));
- }
- else
- {
- lights[i].diffuse = Vec3f(lightColor.x * diffuseColor.x,
- lightColor.y * diffuseColor.y,
- lightColor.z * diffuseColor.z);
- }
- lights[i].brightness = max(lightColor.x, max(lightColor.y, lightColor.z));
- lights[i].specular = Vec3f(lightColor.x * specularColor.x,
- lightColor.y * specularColor.y,
- lightColor.z * specularColor.z);
- Vec3f halfAngle_obj = ls.eyeDir_obj + light.direction_obj;
- if (halfAngle_obj.length() != 0.0f)
- halfAngle_obj.normalize();
- lights[i].halfVector = halfAngle_obj;
- }
- eyePosition = ls.eyePos_obj;
- ambientColor = Vec3f(ls.ambientColor.x * diffuseColor.x + materialEmissive.red(),
- ls.ambientColor.y * diffuseColor.y + materialEmissive.green(),
- ls.ambientColor.z * diffuseColor.z + materialEmissive.blue());
- opacity = materialDiffuse.alpha();
- #ifdef USE_HDR
- nightLightScale = _nightLightScale;
- #endif
- }
- // Set GLSL shader constants for shadows from ellipsoid occluders; shadows from
- // irregular objects are not handled yet.
- void
- CelestiaGLProgram::setEclipseShadowParameters(const LightingState& ls,
- float planetRadius,
- const Mat4f& planetMat)
- {
- for (unsigned int li = 0;
- li < min(ls.nLights, MaxShaderLights);
- li++)
- {
- if (shadows != NULL)
- {
- unsigned int nShadows = min((size_t) MaxShaderShadows, ls.shadows[li]->size());
- for (unsigned int i = 0; i < nShadows; i++)
- {
- EclipseShadow& shadow = ls.shadows[li]->at(i);
- CelestiaGLProgramShadow& shadowParams = shadows[li][i];
- // Compute shadow parameters: max depth of at the center of the shadow
- // (always 1 if an eclipse is total) and the linear falloff
- // rate from the center to the outer endge of the penumbra.
- float u = shadow.umbraRadius / shadow.penumbraRadius;
- shadowParams.falloff = -shadow.maxDepth / std::max(0.001f, 1.0f - std::fabs(u));
- shadowParams.maxDepth = shadow.maxDepth;
- // Compute the transformation to use for generating texture
- // coordinates from the object vertices.
- Point3f origin = shadow.origin * planetMat;
- Vec3f dir = shadow.direction * planetMat;
- float scale = planetRadius / shadow.penumbraRadius;
- Vec3f axis = Vec3f(0, 1, 0) ^ dir;
- float angle = (float) acos(Vec3f(0, 1, 0) * dir);
- axis.normalize();
- Mat4f mat = Mat4f::rotation(axis, -angle);
- Vec3f sAxis = Vec3f(0.5f * scale, 0, 0) * mat;
- Vec3f tAxis = Vec3f(0, 0, 0.5f * scale) * mat;
- float sw = (Point3f(0, 0, 0) - origin) * sAxis / planetRadius + 0.5f;
- float tw = (Point3f(0, 0, 0) - origin) * tAxis / planetRadius + 0.5f;
- shadowParams.texGenS = Vec4f(sAxis.x, sAxis.y, sAxis.z, sw);
- shadowParams.texGenT = Vec4f(tAxis.x, tAxis.y, tAxis.z, tw);
- }
- }
- }
- }
- // Set the scattering and absoroption shader parameters for atmosphere simulation.
- // They are from standard units to the normalized system used by the shaders.
- // atmPlanetRadius - the radius in km of the planet with the atmosphere
- // objRadius - the radius in km of the object we're rendering
- void
- CelestiaGLProgram::setAtmosphereParameters(const Atmosphere& atmosphere,
- float atmPlanetRadius,
- float objRadius)
- {
- // Compute the radius of the sky sphere to render; the density of the atmosphere
- // fallse off exponentially with height above the planet's surface, so the actual
- // radius is infinite. That's a bit impractical, so well just render the portion
- // out to the point where the density is some fraction of the surface density.
- float skySphereRadius = atmPlanetRadius + -atmosphere.mieScaleHeight * (float) log(AtmosphereExtinctionThreshold);
- float tMieCoeff = atmosphere.mieCoeff * objRadius;
- Vec3f tRayleighCoeff = atmosphere.rayleighCoeff * objRadius;
- Vec3f tAbsorptionCoeff = atmosphere.absorptionCoeff * objRadius;
- float r = skySphereRadius / objRadius;
- atmosphereRadius = Vec3f(r, r * r, atmPlanetRadius / objRadius);
- mieCoeff = tMieCoeff;
- mieScaleHeight = objRadius / atmosphere.mieScaleHeight;
- // The scattering shaders use the Schlick approximation to the
- // Henyey-Greenstein phase function because it's slightly faster
- // to compute. Convert the HG asymmetry parameter to the Schlick
- // parameter.
- float g = atmosphere.miePhaseAsymmetry;
- miePhaseAsymmetry = 1.55f * g - 0.55f * g * g * g;
- rayleighCoeff = tRayleighCoeff;
- rayleighScaleHeight = 0.0f; // TODO
- // Precompute sum and inverse sum of scattering coefficients to save work
- // in the vertex shader.
- Vec3f tScatterCoeffSum = Vec3f(tRayleighCoeff.x + tMieCoeff,
- tRayleighCoeff.y + tMieCoeff,
- tRayleighCoeff.z + tMieCoeff);
- scatterCoeffSum = tScatterCoeffSum;
- invScatterCoeffSum = Vec3f(1.0f / tScatterCoeffSum.x, 1.0f / tScatterCoeffSum.y, 1.0f / tScatterCoeffSum.z);
- extinctionCoeff = tScatterCoeffSum + tAbsorptionCoeff;
- }