diff --git a/interface/resources/shaders/SkyFromSpace.frag b/interface/resources/shaders/SkyFromSpace.frag new file mode 100644 index 0000000000..1056320e07 --- /dev/null +++ b/interface/resources/shaders/SkyFromSpace.frag @@ -0,0 +1,48 @@ +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering fragment shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +#version 120 + +uniform vec3 v3LightPos; +uniform float g; +uniform float g2; + +varying vec3 v3Direction; + + +void main (void) +{ + float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); + float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5); + gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor; + gl_FragColor.a = 1.0; // gl_FragColor.b; +} diff --git a/interface/resources/shaders/SkyFromSpace.vert b/interface/resources/shaders/SkyFromSpace.vert new file mode 100644 index 0000000000..d230ee8518 --- /dev/null +++ b/interface/resources/shaders/SkyFromSpace.vert @@ -0,0 +1,109 @@ +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering vertex shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +#version 120 + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3LightPos; // The direction vector to the light source +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fCameraHeight2; // fCameraHeight^2 +uniform float fOuterRadius; // The outer (atmosphere) radius +uniform float fOuterRadius2; // fOuterRadius^2 +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +const int nSamples = 2; +const float fSamples = 2.0; + +varying vec3 v3Direction; + + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main(void) +{ + // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = gl_Vertex.xyz; + vec3 v3Ray = v3Pos - v3CameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere) + float B = 2.0 * dot(v3CameraPos, v3Ray); + float C = fCameraHeight2 - fOuterRadius2; + float fDet = max(0.0, B*B - 4.0 * C); + float fNear = 0.5 * (-B - sqrt(fDet)); + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos + v3Ray * fNear; + fFar -= fNear; + float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius; + float fStartDepth = exp(-1.0 / fScaleDepth); + float fStartOffset = fStartDepth * scale(fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; i + #include "Camera.h" #include "Environment.h" #include "renderer/ProgramObject.h" @@ -12,24 +14,8 @@ #include "world.h" void Environment::init() { - _skyFromAtmosphereProgram = new ProgramObject(); - _skyFromAtmosphereProgram->attachFromSourceFile(GL_VERTEX_SHADER_ARB, "resources/shaders/SkyFromAtmosphere.vert"); - _skyFromAtmosphereProgram->attachFromSourceFile(GL_FRAGMENT_SHADER_ARB, "resources/shaders/SkyFromAtmosphere.frag"); - _skyFromAtmosphereProgram->link(); - - _cameraPosLocation = _skyFromAtmosphereProgram->getUniformLocation("v3CameraPos"); - _lightPosLocation = _skyFromAtmosphereProgram->getUniformLocation("v3LightPos"); - _invWavelengthLocation = _skyFromAtmosphereProgram->getUniformLocation("v3InvWavelength"); - _innerRadiusLocation = _skyFromAtmosphereProgram->getUniformLocation("fInnerRadius"); - _krESunLocation = _skyFromAtmosphereProgram->getUniformLocation("fKrESun"); - _kmESunLocation = _skyFromAtmosphereProgram->getUniformLocation("fKmESun"); - _kr4PiLocation = _skyFromAtmosphereProgram->getUniformLocation("fKr4PI"); - _km4PiLocation = _skyFromAtmosphereProgram->getUniformLocation("fKm4PI"); - _scaleLocation = _skyFromAtmosphereProgram->getUniformLocation("fScale"); - _scaleDepthLocation = _skyFromAtmosphereProgram->getUniformLocation("fScaleDepth"); - _scaleOverScaleDepthLocation = _skyFromAtmosphereProgram->getUniformLocation("fScaleOverScaleDepth"); - _gLocation = _skyFromAtmosphereProgram->getUniformLocation("g"); - _g2Location = _skyFromAtmosphereProgram->getUniformLocation("g2"); + _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); + _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); } void Environment::renderAtmosphere(Camera& camera) { @@ -44,32 +30,48 @@ void Environment::renderAtmosphere(Camera& camera) { float projection[16]; glGetFloatv(GL_PROJECTION_MATRIX, projection); glm::vec3 relativeCameraPos = camera.getPosition() - getAtmosphereCenter(); - float near = camera.getNearClip(), far = glm::length(relativeCameraPos) + getAtmosphereOuterRadius(); + float height = glm::length(relativeCameraPos); + float near = camera.getNearClip(), far = height + getAtmosphereOuterRadius(); projection[10] = (far + near) / (near - far); projection[14] = (2.0f * far * near) / (near - far); glLoadMatrixf(projection); + // use the appropriate shader depending on whether we're inside or outside + ProgramObject* program; + int* locations; + if (height < getAtmosphereOuterRadius()) { + program = _skyFromAtmosphereProgram; + locations = _skyFromAtmosphereUniformLocations; + + } else { + program = _skyFromSpaceProgram; + locations = _skyFromSpaceUniformLocations; + } + // the constants here are from Sean O'Neil's GPU Gems entry // (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp - _skyFromAtmosphereProgram->bind(); - _skyFromAtmosphereProgram->setUniform(_cameraPosLocation, relativeCameraPos); + program->bind(); + program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); glm::vec3 lightDirection = glm::normalize(getSunLocation()); - _skyFromAtmosphereProgram->setUniform(_lightPosLocation, lightDirection); - _skyFromAtmosphereProgram->setUniform(_invWavelengthLocation, + program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); + program->setUniform(locations[INV_WAVELENGTH_LOCATION], 1 / powf(getScatteringWavelengths().r, 4.0f), 1 / powf(getScatteringWavelengths().g, 4.0f), 1 / powf(getScatteringWavelengths().b, 4.0f)); - _skyFromAtmosphereProgram->setUniform(_innerRadiusLocation, getAtmosphereInnerRadius()); - _skyFromAtmosphereProgram->setUniform(_krESunLocation, getRayleighScattering() * getSunBrightness()); - _skyFromAtmosphereProgram->setUniform(_kmESunLocation, getMieScattering() * getSunBrightness()); - _skyFromAtmosphereProgram->setUniform(_kr4PiLocation, getRayleighScattering() * 4.0f * PIf); - _skyFromAtmosphereProgram->setUniform(_km4PiLocation, getMieScattering() * 4.0f * PIf); - _skyFromAtmosphereProgram->setUniform(_scaleLocation, 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); - _skyFromAtmosphereProgram->setUniform(_scaleDepthLocation, 0.25f); - _skyFromAtmosphereProgram->setUniform(_scaleOverScaleDepthLocation, + program->setUniform(locations[CAMERA_HEIGHT2_LOCATION], height * height); + program->setUniform(locations[OUTER_RADIUS_LOCATION], getAtmosphereOuterRadius()); + program->setUniform(locations[OUTER_RADIUS2_LOCATION], getAtmosphereOuterRadius() * getAtmosphereOuterRadius()); + program->setUniform(locations[INNER_RADIUS_LOCATION], getAtmosphereInnerRadius()); + program->setUniform(locations[KR_ESUN_LOCATION], getRayleighScattering() * getSunBrightness()); + program->setUniform(locations[KM_ESUN_LOCATION], getMieScattering() * getSunBrightness()); + program->setUniform(locations[KR_4PI_LOCATION], getRayleighScattering() * 4.0f * PIf); + program->setUniform(locations[KM_4PI_LOCATION], getMieScattering() * 4.0f * PIf); + program->setUniform(locations[SCALE_LOCATION], 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); + program->setUniform(locations[SCALE_DEPTH_LOCATION], 0.25f); + program->setUniform(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], (1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())) / 0.25f); - _skyFromAtmosphereProgram->setUniform(_gLocation, -0.990f); - _skyFromAtmosphereProgram->setUniform(_g2Location, -0.990f * -0.990f); + program->setUniform(locations[G_LOCATION], -0.990f); + program->setUniform(locations[G2_LOCATION], -0.990f * -0.990f); glFrontFace(GL_CW); glDepthMask(GL_FALSE); @@ -78,10 +80,37 @@ void Environment::renderAtmosphere(Camera& camera) { glDepthMask(GL_TRUE); glFrontFace(GL_CCW); - _skyFromAtmosphereProgram->release(); + program->release(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } + +ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { + ProgramObject* program = new ProgramObject(); + QByteArray prefix = QByteArray("resources/shaders/SkyFrom") + from; + program->attachFromSourceFile(GL_VERTEX_SHADER_ARB, prefix + ".vert"); + program->attachFromSourceFile(GL_FRAGMENT_SHADER_ARB, prefix + ".frag"); + program->link(); + + locations[CAMERA_POS_LOCATION] = program->getUniformLocation("v3CameraPos"); + locations[LIGHT_POS_LOCATION] = program->getUniformLocation("v3LightPos"); + locations[INV_WAVELENGTH_LOCATION] = program->getUniformLocation("v3InvWavelength"); + locations[CAMERA_HEIGHT2_LOCATION] = program->getUniformLocation("fCameraHeight2"); + locations[OUTER_RADIUS_LOCATION] = program->getUniformLocation("fOuterRadius"); + locations[OUTER_RADIUS2_LOCATION] = program->getUniformLocation("fOuterRadius2"); + locations[INNER_RADIUS_LOCATION] = program->getUniformLocation("fInnerRadius"); + locations[KR_ESUN_LOCATION] = program->getUniformLocation("fKrESun"); + locations[KM_ESUN_LOCATION] = program->getUniformLocation("fKmESun"); + locations[KR_4PI_LOCATION] = program->getUniformLocation("fKr4PI"); + locations[KM_4PI_LOCATION] = program->getUniformLocation("fKm4PI"); + locations[SCALE_LOCATION] = program->getUniformLocation("fScale"); + locations[SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleDepth"); + locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleOverScaleDepth"); + locations[G_LOCATION] = program->getUniformLocation("g"); + locations[G2_LOCATION] = program->getUniformLocation("g2"); + + return program; +} diff --git a/interface/src/Environment.h b/interface/src/Environment.h index 51d7b92e1e..9c68b5c3e5 100644 --- a/interface/src/Environment.h +++ b/interface/src/Environment.h @@ -23,20 +23,33 @@ public: private: + ProgramObject* createSkyProgram(const char* from, int* locations); + ProgramObject* _skyFromAtmosphereProgram; - int _cameraPosLocation; - int _lightPosLocation; - int _invWavelengthLocation; - int _innerRadiusLocation; - int _krESunLocation; - int _kmESunLocation; - int _kr4PiLocation; - int _km4PiLocation; - int _scaleLocation; - int _scaleDepthLocation; - int _scaleOverScaleDepthLocation; - int _gLocation; - int _g2Location; + ProgramObject* _skyFromSpaceProgram; + + enum { + CAMERA_POS_LOCATION, + LIGHT_POS_LOCATION, + INV_WAVELENGTH_LOCATION, + CAMERA_HEIGHT2_LOCATION, + OUTER_RADIUS_LOCATION, + OUTER_RADIUS2_LOCATION, + INNER_RADIUS_LOCATION, + KR_ESUN_LOCATION, + KM_ESUN_LOCATION, + KR_4PI_LOCATION, + KM_4PI_LOCATION, + SCALE_LOCATION, + SCALE_DEPTH_LOCATION, + SCALE_OVER_SCALE_DEPTH_LOCATION, + G_LOCATION, + G2_LOCATION, + LOCATION_COUNT + }; + + int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; + int _skyFromSpaceUniformLocations[LOCATION_COUNT]; }; #endif /* defined(__interface__Environment__) */