3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 07:15:30 +02:00

Include the "sky from space" shaders, too, and use them when the camera is

outside the atmosphere's outer radius.
This commit is contained in:
Andrzej Kapolka 2013-05-08 11:42:31 -07:00
parent 310c0288c7
commit 82f16e7f34
4 changed files with 246 additions and 47 deletions

View file

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

View file

@ -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<nSamples; i++)
{
float fHeight = length(v3SamplePoint);
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
v3SamplePoint += v3SampleRay;
}
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
gl_FrontSecondaryColor.rgb = v3FrontColor * fKmESun;
gl_FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v3Direction = v3CameraPos - v3Pos;
}

View file

@ -5,6 +5,8 @@
// Created by Andrzej Kapolka on 5/6/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <QByteArray>
#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;
}

View file

@ -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__) */