我正在尝试在GLSL 4.10版中实现大气散射。我正在调整Shadertoy着色器https://www.shadertoy.com/view/lslXDr中的着色器。我的程序中的氛围是从行星球体的缩放版本创建的。
我的实际散射方程有效,但对于大多数摄像机位置,大气的内半径与球体的外半径不对齐。我知道这是从大气层的半径大于行星球体,但我似乎无法将其缩小。
我的问题最好在这里说明。该模型在这些图片中放大。可以看出,大气内半径与行星半径(深蓝色球体)不匹配。
此处模型被缩放和翻译。气氛偏离了摄像机的中心,内部的气氛仍然没有与行星对齐。
这是顶点着色器,它实质上是一个直通着色器
#version 410
in vec4 vPosition;
in vec3 vNormal;
out vec3 fPosition;
out mat3 m;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
fPosition = vec3(vPosition);
m = mat3(model);
gl_Position = projection*view*model*vPosition;
}
片段着色器。
#version 410
uniform float time;
uniform vec3 camPosition;
uniform float fInnerRadius;
uniform float fOuterRadius;
in vec3 fPosition;
in mat3 m;
out vec4 FragColor;
const float PI = 3.14159265359;
const float degToRad = PI / 180.0;
const float MAX = 10000.0;
float K_R = 0.166;
const float K_M = 0.0025;
const float E = 14.3;
const vec3 C_R = vec3(0.3, 0.7, 1.0);
const float G_M = -0.85;
float SCALE_H = 4.0 / (fOuterRadius - fInnerRadius);
float SCALE_L = 1.0 / (fOuterRadius - fInnerRadius);
const int numOutScatter = 10;
const float fNumOutScatter = 10.0;
const int numInScatter = 10;
const float fNumInScatter = 10.0;
vec3 rayDirection(vec3 camPosition) {
vec3 ray = m*fPosition - camPosition;
float far = length(ray);
return ray /= far;
}
vec2 rayIntersection(vec3 p, vec3 dir, float radius ) {
float b = dot( p, dir );
float c = dot( p, p ) - radius * radius;
float d = b * b - c;
if ( d < 0.0 ) {
return vec2( MAX, -MAX );
}
d = sqrt( d );
float near = -b - d;
float far = -b + d;
return vec2(near, far);
}
// Mie
// g : ( -0.75, -0.999 )
// 3 * ( 1 - g^2 ) 1 + c^2
// F = ----------------- * -------------------------------
// 2 * ( 2 + g^2 ) ( 1 + g^2 - 2 * g * c )^(3/2)
float miePhase( float g, float c, float cc ) {
float gg = g * g;
float a = ( 1.0 - gg ) * ( 1.0 + cc );
float b = 1.0 + gg - 2.0 * g * c;
b *= sqrt( b );
b *= 2.0 + gg;
return 1.5 * a / b;
}
// Reyleigh
// g : 0
// F = 3/4 * ( 1 + c^2 )
float rayleighPhase( float cc ) {
return 0.75 * ( 1.0 + cc );
}
float density(vec3 p) {
return exp(-(length(p) - fInnerRadius) * SCALE_H);
}
float optic(vec3 p, vec3 q) {
vec3 step = (q - p) / fNumOutScatter;
vec3 v = p + step * 0.5;
float sum = 0.0;
for(int i = 0; i < numOutScatter; i++) {
sum += density(v);
v += step;
}
sum *= length(step)*SCALE_L;
return sum;
}
vec3 inScatter(vec3 o, vec3 dir, vec2 e, vec3 l) {
float len = (e.y - e.x) / fNumInScatter;
vec3 step = dir * len;
vec3 p = o + dir * e.x;
vec3 v = p + dir * (len * 0.5);
vec3 sum = vec3(0.0);
for(int i = 0; i < numInScatter; i++) {
vec2 f = rayIntersection(v, l, fOuterRadius);
vec3 u = v + l * f.y;
float n = (optic(p, v) + optic(v, u))*(PI * 4.0);
sum += density(v)* exp(-n * ( K_R * C_R + K_M ));
v += step;
}
sum *= len * SCALE_L;
float c = dot(dir, -l);
float cc = c * c;
return sum * ( K_R * C_R * rayleighPhase( cc ) + K_M * miePhase( G_M, c, cc ) ) * E;
}
void main (void)
{
vec3 dir = rayDirection(vec3(camPosition.x, 0.0, camPosition.z));
vec3 eye = vec3(camPosition.x, 0.0, camPosition.z);
vec3 l = normalize(vec3(0.0, 0.0, 1.0));
vec2 e = rayIntersection(eye, dir, fOuterRadius);
if ( e.x > e.y ) {
discard;
}
vec2 f = rayIntersection(eye, dir, fInnerRadius);
e.y = min(e.y, f.x);
vec3 I = inScatter(eye, dir, e, l);
FragColor = vec4(I, 1.0);
}
如果需要,这里是吸引大气的代码。绘制行星的代码与scaleFactor具有基本相同的转换。
void drawAtmosphere()
{
glUseProgram(atmosphereShader);
v = getViewMatrix();
vec3 Position = getCameraPosition();
float scaleFactor = 1.25;
m = multiplymat4(translate(0.0, 0.0, -10), scale(fScale*scaleFactor));
float fOuter = (fScale*scaleFactor);
float fInner = fScale;
glUniform1f(glGetUniformLocation(atmosphereShader, "fInnerRadius"), fInner);
glUniform1f(glGetUniformLocation(atmosphereShader, "fOuterRadius"), fOuter);
glUniform3f(glGetUniformLocation(atmosphereShader, "camPosition"), Position.x, Position.y, Position.z);
glUniform1f(glGetUniformLocation(atmosphereShader, "time"), glfwGetTime());
initMVP(atmosphereShader, m, v);
glBindVertexArray (atmosphereVAO);
glDrawArrays( GL_TRIANGLES, 0, planet.vertexNumber);
glBindVertexArray(0);
}
任何帮助,或任何可以指引我朝正确方向发展的事情都表示赞赏。