From 7faa9e4318e00b3c94799e289b09cd08355e75e3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 7 May 2013 12:40:15 -0700 Subject: [PATCH] More work on atmosphere rendering; rendering now working. --- .../resources/shaders/SkyFromAtmosphere.frag | 24 +++++ .../resources/shaders/SkyFromAtmosphere.vert | 76 +++++++++++++++ interface/src/Environment.cpp | 96 ++++++++++++++++++- interface/src/Environment.h | 21 +++- interface/src/main.cpp | 6 ++ libraries/voxels/src/EnvironmentData.cpp | 12 +++ libraries/voxels/src/EnvironmentData.h | 23 +++-- 7 files changed, 246 insertions(+), 12 deletions(-) create mode 100644 interface/resources/shaders/SkyFromAtmosphere.frag create mode 100644 interface/resources/shaders/SkyFromAtmosphere.vert diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag new file mode 100644 index 0000000000..3b9ccee8a5 --- /dev/null +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -0,0 +1,24 @@ +// +// 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/SkyFromAtmosphere.vert b/interface/resources/shaders/SkyFromAtmosphere.vert new file mode 100644 index 0000000000..19261ca046 --- /dev/null +++ b/interface/resources/shaders/SkyFromAtmosphere.vert @@ -0,0 +1,76 @@ +// +// 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 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 ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos; + float fHeight = length(v3Start); + float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepth*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 -void Environment::render() { - +#include "Camera.h" +#include "Environment.h" +#include "world.h" + +// checks for an error, printing the info log if one is deteced +static void errorCheck(GLhandleARB obj) { + if (glGetError() != GL_NO_ERROR) { + QByteArray log(1024, 0); + glGetInfoLogARB(obj, log.size(), 0, log.data()); + qDebug() << log; + } +} + +static GLhandleARB compileShader(int type, const QString& filename) { + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Couldn't find file." << filename; + return 0; + } + GLhandleARB shaderID = glCreateShaderObjectARB(type); + QByteArray source = file.readAll(); + const char* sdata = source.constData(); + glShaderSource(shaderID, 1, &sdata, 0); + glCompileShaderARB(shaderID); + errorCheck(shaderID); + return shaderID; +} + +void Environment::init() { + _skyFromAtmosphereProgramID = glCreateProgramObjectARB(); + glAttachObjectARB(_skyFromAtmosphereProgramID, compileShader( + GL_VERTEX_SHADER_ARB, "resources/shaders/SkyFromAtmosphere.vert")); + glAttachObjectARB(_skyFromAtmosphereProgramID, compileShader( + GL_FRAGMENT_SHADER_ARB, "resources/shaders/SkyFromAtmosphere.frag")); + glLinkProgramARB(_skyFromAtmosphereProgramID); + errorCheck(_skyFromAtmosphereProgramID); + + _cameraPosLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "v3CameraPos"); + _lightPosLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "v3LightPos"); + _invWavelengthLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "v3InvWavelength"); + _innerRadiusLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fInnerRadius"); + _krESunLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fKrESun"); + _kmESunLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fKmESun"); + _kr4PiLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fKr4PI"); + _km4PiLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fKm4PI"); + _scaleLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fScale"); + _scaleDepthLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fScaleDepth"); + _scaleOverScaleDepthLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "fScaleOverScaleDepth"); + _gLocation = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "g"); + _g2Location = glGetUniformLocationARB(_skyFromAtmosphereProgramID, "g2"); +} + +void Environment::render(Camera& camera) { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(getAtmosphereCenter().x, getAtmosphereCenter().y, getAtmosphereCenter().z); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluPerspective(camera.getFieldOfView(), camera.getAspectRatio(), 100, 100000000); + + glUseProgramObjectARB(_skyFromAtmosphereProgramID); + glm::vec3 relativeCameraPos = camera.getPosition() - getAtmosphereCenter(); + glUniform3fARB(_cameraPosLocation, relativeCameraPos.x, relativeCameraPos.y, relativeCameraPos.z); + glm::vec3 lightDirection = glm::normalize(getSunLocation()); + glUniform3fARB(_lightPosLocation, lightDirection.x, lightDirection.y, lightDirection.z); + glUniform3fARB(_invWavelengthLocation, + 1 / powf(0.650f, 4.0f), 1 / powf(0.570f, 4.0f), 1 / powf(0.475f, 4.0f)); + glUniform1fARB(_innerRadiusLocation, getAtmosphereInnerRadius()); + glUniform1fARB(_krESunLocation, getRayleighScattering() * getSunBrightness()); + glUniform1fARB(_kmESunLocation, getMieScattering() * getSunBrightness()); + glUniform1fARB(_kr4PiLocation, getRayleighScattering() * 4.0f * PIf); + glUniform1fARB(_km4PiLocation, getMieScattering() * 4.0f * PIf); + glUniform1fARB(_scaleLocation, 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); + glUniform1fARB(_scaleDepthLocation, 0.25f); + glUniform1fARB(_scaleOverScaleDepthLocation, + (1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())) / 0.25f); + glUniform1fARB(_gLocation, -0.990f); + glUniform1fARB(_g2Location, -0.990f * -0.990f); + + glFrontFace(GL_CW); + glutSolidSphere(getAtmosphereOuterRadius(), 100, 50); + glFrontFace(GL_CCW); + + glUseProgramObjectARB(0); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } diff --git a/interface/src/Environment.h b/interface/src/Environment.h index e028d86e32..f2517cb018 100644 --- a/interface/src/Environment.h +++ b/interface/src/Environment.h @@ -10,15 +10,32 @@ #define __interface__Environment__ #include "EnvironmentData.h" +#include "InterfaceConfig.h" + +class Camera; class Environment : public EnvironmentData { public: - void render(); + void init(); + void render(Camera& camera); private: - + GLhandleARB _skyFromAtmosphereProgramID; + 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; }; #endif /* defined(__interface__Environment__) */ diff --git a/interface/src/main.cpp b/interface/src/main.cpp index dd63a74c1a..171c530286 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -311,6 +311,8 @@ void init(void) { voxels.setViewerAvatar(&myAvatar); voxels.setCamera(&myCamera); + environment.init(); + handControl.setScreenDimensions(WIDTH, HEIGHT); headMouseX = WIDTH/2; @@ -682,6 +684,9 @@ void renderViewFrustum(ViewFrustum& viewFrustum) { void displaySide(Camera& whichCamera) { glPushMatrix(); + // draw the sky dome + environment.render(whichCamera); + if (::starsOn) { // should be the first rendering pass - w/o depth buffer / lighting @@ -1747,6 +1752,7 @@ void reshape(int width, int height) { glBindTexture(GL_TEXTURE_2D, 0); } } else { + camera.setAspectRatio(aspectRatio); camera.setFieldOfView(fov = 60); } diff --git a/libraries/voxels/src/EnvironmentData.cpp b/libraries/voxels/src/EnvironmentData.cpp index 9fff790810..4882a00e2e 100644 --- a/libraries/voxels/src/EnvironmentData.cpp +++ b/libraries/voxels/src/EnvironmentData.cpp @@ -10,6 +10,18 @@ #include "EnvironmentData.h" #include "PacketHeaders.h" +// initial values from Sean O'Neil's GPU Gems entry (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), +// GameEngine.cpp +EnvironmentData::EnvironmentData() : + _atmosphereCenter(0, -6371000, 0), + _atmosphereInnerRadius(6371000), + _atmosphereOuterRadius(6530275), + _rayleighScattering(0.0025f), + _mieScattering(0.0010f), + _sunLocation(1000, 1000, 0), + _sunBrightness(20.0f) { +} + int EnvironmentData::getBroadcastData(unsigned char* destinationBuffer) const { unsigned char* bufferStart = destinationBuffer; diff --git a/libraries/voxels/src/EnvironmentData.h b/libraries/voxels/src/EnvironmentData.h index 12ebcd4a94..2bac3ba920 100644 --- a/libraries/voxels/src/EnvironmentData.h +++ b/libraries/voxels/src/EnvironmentData.h @@ -14,15 +14,24 @@ class EnvironmentData { public: - void setAtmosphereCenter(const glm::vec3& center); - void setAtmosphereInnerRadius(float radius); - void setAtmosphereOuterRadius(float radius); + EnvironmentData(); + + void setAtmosphereCenter(const glm::vec3& center) { _atmosphereCenter = center; } + void setAtmosphereInnerRadius(float radius) { _atmosphereInnerRadius = radius; } + void setAtmosphereOuterRadius(float radius) { _atmosphereOuterRadius = radius; } + const glm::vec3& getAtmosphereCenter() const { return _atmosphereCenter; } + float getAtmosphereInnerRadius() const { return _atmosphereInnerRadius; } + float getAtmosphereOuterRadius() const { return _atmosphereOuterRadius; } - void setRayleighScattering(float scattering); - void setMieScattering(float scattering); + void setRayleighScattering(float scattering) { _rayleighScattering = scattering; } + void setMieScattering(float scattering) { _mieScattering = scattering; } + float getRayleighScattering() const { return _rayleighScattering; } + float getMieScattering() const { return _mieScattering; } - void setSunLocation(const glm::vec3 location); - void setSunBrightness(float brightness); + void setSunLocation(const glm::vec3& location) { _sunLocation = location; } + void setSunBrightness(float brightness) { _sunBrightness = brightness; } + const glm::vec3& getSunLocation() const { return _sunLocation; } + float getSunBrightness() const { return _sunBrightness; } int getBroadcastData(unsigned char* destinationBuffer) const; int parseData(unsigned char* sourceBuffer, int numBytes);