@@ -1856,6 +1856,8 @@ buildRingsVertexShader(const ShaderProperties& props, bool fisheyeEnabled)
18561856GLFragmentShader
18571857buildRingsFragmentShader (const ShaderProperties& props)
18581858{
1859+ bool useProfiles = util::is_set (props.texUsage , TexUsage::RingColorTexture);
1860+
18591861 std::string source (VersionHeader);
18601862 source += CommonHeader;
18611863 source += FragmentHeader;
@@ -1873,6 +1875,12 @@ buildRingsFragmentShader(const ShaderProperties& props)
18731875 source += DeclareUniform (" diffTex" , Shader_Sampler2D);
18741876 }
18751877
1878+ if (useProfiles)
1879+ {
1880+ source += DeclareUniform (" ringColorTex" , Shader_Sampler2D);
1881+ source += DeclareUniform (" ringUnlitColor" , Shader_Vector3);
1882+ }
1883+
18761884 if (props.hasEclipseShadows ())
18771885 {
18781886 source += DeclareInput (" shadowDepths" , Shader_Vector4);
@@ -1901,7 +1909,24 @@ buildRingsFragmentShader(const ShaderProperties& props)
19011909 source += " color = texture(diffTex, diffTexCoord.st);\n " ;
19021910 else
19031911 source += " color = vec4(1.0);\n " ;
1904- source += DeclareLocal (" opticalDepth" , Shader_Float, " color.a" );
1912+
1913+ if (useProfiles)
1914+ {
1915+ // BJ Jónsson radial-profile encoding:
1916+ // diffTex.r = backscattered brightness (lit side, viewer ~ sun direction)
1917+ // diffTex.g = forward-scattered brightness (lit side, viewer opposite sun)
1918+ // diffTex.b = unlit-side brightness (transparent areas glow as sunlight filters through)
1919+ // diffTex.a = transparency (1 - opticalDepth)
1920+ // ringColorTex supplies the lit-side color profile.
1921+ source += DeclareLocal (" ringColor" , Shader_Vector3,
1922+ " texture(ringColorTex, diffTexCoord.st).rgb" );
1923+ source += DeclareLocal (" opticalDepth" , Shader_Float, " 1.0 - color.a" );
1924+ }
1925+ else
1926+ {
1927+ source += DeclareLocal (" opticalDepth" , Shader_Float, " color.a" );
1928+ }
1929+
19051930 if (props.hasEclipseShadows ())
19061931 {
19071932 // Temporaries required for shadows
@@ -1917,15 +1942,35 @@ buildRingsFragmentShader(const ShaderProperties& props)
19171942 // Ring plane normal pointing toward the viewer
19181943 source += DeclareLocal (" ringNormal" , Shader_Vector3,
19191944 " vec3(0.0, sign(eyeDir.y), 0.0)" );
1945+ if (useProfiles)
1946+ {
1947+ source += DeclareLocal (" phase" , Shader_Float);
1948+ source += DeclareLocal (" tint" , Shader_Vector3);
1949+ }
19201950
19211951 for (unsigned i = 0 ; i < props.nLights ; i++)
19221952 {
19231953 // litSide is 1 when viewer and light are on the same side of the rings, 0 otherwise
19241954 source += " litSide = 1.0 - step(0.0, " + LightProperty (i, " direction" ) + " .y * eyeDir.y);\n " ;
1925- // source += assign("litSide", 1.0f - step(0.0f, sh_vec3("eyePosition")["y"]));
19261955
1927- source += " intensity = (dot(" + LightProperty (i, " direction" ) + " , eyeDir) + 1.0) * 0.5;\n " ;
1928- source += " intensity = mix(intensity, intensity * (1.0 - opticalDepth), litSide);\n " ;
1956+ if (useProfiles)
1957+ {
1958+ // phase: 0 at backscatter (light & eye aligned), 1 at forward scatter.
1959+ // BJ's forward-scattered profile was captured at phase 139 degrees,
1960+ // so remap so that phase=139 degrees saturates to the G channel.
1961+ source += " phase = clamp((1.0 - dot(" + LightProperty (i, " direction" )
1962+ + " , eyeDir)) * 0.5 * (180.0 / 139.0), 0.0, 1.0);\n " ;
1963+ // Lit-side brightness blends backscatter and forward-scatter profiles.
1964+ // Unlit-side brightness comes from the dedicated profile.
1965+ source += " intensity = mix(mix(color.r, color.g, phase), color.b, litSide);\n " ;
1966+ // Apply unlit color tint when viewer sees the unlit side.
1967+ source += " tint = mix(ringColor, ringColor * ringUnlitColor, litSide);\n " ;
1968+ }
1969+ else
1970+ {
1971+ source += " intensity = (dot(" + LightProperty (i, " direction" ) + " , eyeDir) + 1.0) * 0.5;\n " ;
1972+ source += " intensity = mix(intensity, intensity * (1.0 - opticalDepth), litSide);\n " ;
1973+ }
19291974
19301975 // Specular highlight from sunlight reflecting off icy ring particles.
19311976 // Only contributes when the viewer and the light are on the same side
@@ -1935,32 +1980,27 @@ buildRingsFragmentShader(const ShaderProperties& props)
19351980 + LightProperty (i, " direction" ) + " + eyeDir), ringNormal)), 32.0);\n " ;
19361981 source += " specFactor *= (1.0 - litSide) * opticalDepth;\n " ;
19371982
1983+ std::string lightTerm = useProfiles
1984+ ? " (intensity * tint + vec3(specFactor))"
1985+ : " (intensity + specFactor)" ;
1986+
19381987 if (props.getEclipseShadowCountForLight (i) > 0 )
19391988 {
19401989 source += " shadow = 1.0;\n " ;
19411990 source += Shadow (i, 0 );
19421991 source += " shadow = min(1.0, shadow + step(0.0, " + ShadowDepth (i) + " ));\n " ;
1943- #if 0
1944- source += "diff.rgb += (shadow * " + SeparateDiffuse(i) + ") * " +
1945- FragLightProperty(i, "color") + ";\n";
1946- #endif
1947- source += " diff.rgb += shadow * (intensity + specFactor) * " + LightProperty (i, " diffuse" ) + " ;\n " ;
1992+ source += " diff.rgb += shadow * " + lightTerm + " * " + LightProperty (i, " diffuse" ) + " ;\n " ;
19481993 }
19491994 else
19501995 {
1951- source += " diff.rgb += (intensity + specFactor) * " + LightProperty (i, " diffuse" ) + " ;\n " ;
1952- #if 0
1953- source += SeparateDiffuse(i) + " = (dot(" +
1954- LightProperty(i, "direction") + ", eyeDir) + 1.0) * 0.5;\n";
1955- #endif
1956- #if 0
1957- source += "diff.rgb += " + SeparateDiffuse(i) + " * " +
1958- FragLightProperty(i, "color") + ";\n";
1959- #endif
1996+ source += " diff.rgb += " + lightTerm + " * " + LightProperty (i, " diffuse" ) + " ;\n " ;
19601997 }
19611998 }
19621999
1963- source += " fragColor = vec4(color.rgb * diff.rgb, opticalDepth);\n " ;
2000+ if (useProfiles)
2001+ source += " fragColor = vec4(diff.rgb, opticalDepth);\n " ;
2002+ else
2003+ source += " fragColor = vec4(color.rgb * diff.rgb, opticalDepth);\n " ;
19642004
19652005 source += " }\n " ;
19662006
@@ -2873,6 +2913,8 @@ CelestiaGLProgram::initParameters()
28732913 {
28742914 ringWidth = floatParam (" ringWidth" );
28752915 ringRadius = floatParam (" ringRadius" );
2916+ if (util::is_set (props.texUsage , TexUsage::RingColorTexture))
2917+ ringUnlitColor = vec3Param (" ringUnlitColor" );
28762918 }
28772919
28782920 textureOffset = floatParam (" texCoordOffset" );
@@ -2987,6 +3029,13 @@ CelestiaGLProgram::initSamplers()
29873029 if (GLint slot = glGetUniformLocation (program.getID (), " shadowMapTex0" ); slot != -1 )
29883030 glUniform1i (slot, nSamplers);
29893031 }
3032+
3033+ if (util::is_set (props.texUsage , TexUsage::RingColorTexture))
3034+ {
3035+ if (GLint slot = glGetUniformLocation (program.getID (), " ringColorTex" ); slot != -1 )
3036+ glUniform1i (slot, nSamplers);
3037+ nSamplers++;
3038+ }
29903039}
29913040
29923041void
0 commit comments