I am trying to implement Sean O’Neil’s Atmosphere from space glsl shader, but my shading n00bness ran into a confusing problem, so I add one line of code at a time. When I add a for loop I get AssertionError: Shader input nSamples is not present.
despite having it set in code. Remove the for loop and nSamples suddenly exists.
Vertex shader a2.glsl:
//GLSL
//
// Atmospheric scattering vertex shader
//
// Author: Sean O'Neil
//
// Copyright (c) 2004 Sean O'Neil
//
uniform vec3 v3CameraPos; // The camera's current position
uniform vec3 v3LightPos; // The direction vector to the light source
uniform float fOuterRadius; // The outer (atmosphere) radius
uniform float fOuterRadius2; // fOuterRadius^2
uniform float fInnerRadius;
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
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
uniform float fKr4PI; // Kr * 4 * PI
uniform float fKm4PI; // Km * 4 * PI
uniform float fSamples;
uniform float nSamples;
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 C = 0.0 - 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);
// Next line causes breakage
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;
}
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v3Direction = 0.0-v3Pos;
}
Temporary Fragment shader a3.glsl
//GLSL
//
// Atmospheric scattering fragment shader
//
// Author: Sean O'Neil
//
// Copyright (c) 2004 Sean O'Neil
//
varying vec3 v3Direction;
void main (void)
{
}
And code
self.atmosphere = loader.loadModel("planet_sphere")
self.atmosphere.setColor(0.5,0.5,1,0.5)
outerRadius = self.radius + bodyDB['atmosphere']['thickness']
self.atmosphere.setShaderInput("fOuterRadius", outerRadius)
self.atmosphere.setShaderInput('fOuterRadius2', outerRadius**2)
self.atmosphere.setShaderInput("v3CameraPos", 0,0, 0)
self.atmosphere.setShaderInput("v3LightPos", -149598261, 20000, 0)
Km = 0.0025 # Mie scattering constant
ESun = 15.0 # Sun brightness constant
Kr = 0.0025 #Rayleigh scattering constant
self.atmosphere.setShaderInput("fKm4PI", Km*4*3.14)
self.atmosphere.setShaderInput("fKr4PI", Kr*4*3.14)
self.atmosphere.setShaderInput("fKmESun", Km*ESun)
self.atmosphere.setShaderInput("fKrESun", Kr*ESun)
self.atmosphere.setShaderInput("nSamples", 2.0)
self.atmosphere.setShaderInput("fSamples", 2.0)
self.atmosphere.setShaderInput('fScale' , 1.0/outerRadius-self.radius) # 1 / (fOuterRadius - fInnerRadius)
self.atmosphere.setShaderInput('fScaleDepth' , 0.25)
self.atmosphere.setShaderInput('fScaleOverScaleDepth' , (1.0/outerRadius-self.radius)/0.25)
self.atmosphere.setShaderInput('g', -0.95) #; // The Mie phase asymmetry factor
self.atmosphere.setShaderInput('g2', -0.95**2)
m_fWavelength4 = [0,0,0]
m_fWavelength4[0] = 0.650**4 # 650 nm for red
m_fWavelength4[1] = 0.570**4 # 570 nm for green
m_fWavelength4[2] = 0.475**4 # 475 nm for blue
self.atmosphere.setShaderInput("v3InvWavelength", 1/m_fWavelength4[0], 1/m_fWavelength4[1], 1/m_fWavelength4[2])
self.atmosphere.setShaderInput('fInnerRadius', float(self.radius))
self.atmosphere.setShaderInput('fInnerRadius2', float(self.radius)**2)
self.atmosphere.setShaderInput('fInnerRadius', self.radius**2)
#atmoShader = Shader.load(Shader.SLGLSL, "AtmoVert.glsl", "AtmoFrag.glsl")
atmoShader = Shader.load(Shader.SLGLSL, "a2.glsl", "a3.glsl")
#atmoShader = Shader.load(Shader.SLGLSL, "AtmoFrag.glsl", "AtmoVert.glsl")
#atmoShader = Shader.load("atmosphere2.cg")
self.atmosphere.setShader(atmoShader)