SkyShader example, get light color

I’d like to add a directional light in a scene with the SkyShader.
I can get the “sun” position, but I have no clues how to get the sun color to match with the light.
Is it possible ?
Thank you.

/cc

1 Like

You might actually want two light sources. But more on that in a second. The direct lighting from any distant object will be the original light intensity multiplied by the extinction coefficient. As white light from the sun goes through the atmosphere, some blue light is scattered out of the direct lighting, which then scatters back to us as the blue light of the sky. But, because this blue light is removed from the direct sun light, the remaining light is more yellow or orange. Thus, to get the direct light, you just need to use that Fex equation in the shader, which is a horrific variable name for extinctionCoefficient. More specifically, you can probably follow along with what I did in A-Sky-Forge and it should also work for you.

//We defined our light earlier in the code, l is being set here as light so I can use it readily.
let l = this.light;

//I'm setting the position here, but you already know how to use this.
//As you might suspect, the position of your light is critical for the color.
l.position.set(this.position.x, this.position.y, this.position.z);

//Here, I got some of the other variables I was finding in the shader, but anything you need to derive Fex
//is something you will need here.
let cosZenithAngleOfSun = Math.max(0.0, this.up.dot(sunPosition));
let zenithAngleOfSun = Math.acos(cosZenithAngleOfSun);
let inverseSDenominator = 1.0 / (cosZenithAngleOfSun + 0.15 * Math.pow(93.885 - (zenithAngleOfSun * 180.0 / Math.PI), -1.253));
const rayleighAtmosphereHeight = 8.4E3;
const mieAtmosphereHeight = 1.25E3;
let sR = rayleighAtmosphereHeight * inverseSDenominator;
let sM = mieAtmosphereHeight * inverseSDenominator;
let betaMTimesSM = betaM.clone().multiplyScalar(sM);

//Note that these min maxs are just clamping again.
this.fexSun.set(
  Math.max(Math.min(Math.exp(-(betaRSun.x * sR + betaMTimesSM.x)), 1.0), 0.0),
  Math.max(Math.min(Math.exp(-(betaRSun.y * sR + betaMTimesSM.y)), 1.0), 0.0),
  Math.max(Math.min(Math.exp(-(betaRSun.z * sR + betaMTimesSM.z)), 1.0), 0.0)
);
//I'm also calling this fexSun, because, as you might suspect, I'm also use a different fex in my code (for the moon).
l.color.setRGB(this.fexSun.x, this.fexSun.y, this.fexSun.z);

//I also included logic for the sunE which is the intensity of the sunlight
//If the light is too bright or dark, this will probably prove useful to your needs.
let solarLightBaseIntensitySquared = sunE / 700.0;
let solarLightBaseIntensity = Math.sqrt(solarLightBaseIntensitySquared);
l.intensity = solarLightBaseIntensity;

In addition to the direct lighting, you also need ambient lighting as well. That is, all the light from the rest of the sky that is not light from the sun. It turns out, once you have the above, this is also pretty easy to derive as it’s just 1.0-DirectLighting effectively.

let ambientColorVec = this.oneVector.clone().sub(this.fexSun);
this.ambientColor = ambientColorVec;
this.ambientIntensity = solarLightBaseIntensity * sunFade;

sunFade is a variable that causes the sunlight to “fade out” at the end of the day because it’s otherwise too bright, but it appears it’s just the sun x, y, z location as seen below in a linear equation, with some mins and maxs used to emulate clamping in JS. NOTE! In this early example I used z as up >_<. I came from a math background - I really should use y as up.

//Beware that z there, it should really be y as THREE uses y as up by default.
//I don't think that makes an impact elsewhere, but I'm leaving the code as is to avoid confusion.
let sunFade = 1.0 - Math.min(Math.max(1.0 - Math.exp(sunPosition.z), 0.0), 1.0);

All this is in https://github.com/Dante83/SkyForge in case you want to get a bit more context. Also, if it’s still not working give me a poke and I’ll have a deeper look at it.

Thank you for this in-depth explanation, I actually tried to extract the code from the shader, but I could not get it to work. Never worked with shaders before…
I’ll get back to this soon, thank you!

Time to dig deeper then! Any console errors? (I’m just yanking these guts out of my code, so I might have overlooked something)