Spatial shader on WorldEnvironment on sky material is not visible

Godot Version

v4.3.dev1.official [9d1cbab1c]

Question

I tried to use a spatial shader on WorldEnvironment on sky but is not visible.
I say is a defined sky shader but can I convert it or use it as a spatial shader?
I saw it is a defined shader sky - docs godotengine but I want to use source code from the spatial shader.
I tested on MeshInstance3D and the shader is visible.
Any idea?
See my screenshot of how I set the shader on the sky:

Spatial shaders do NOT work like sky shaders so you cannot use them in the same way. For instance: There is no vertex function in the sky shader available. You also have other built-in variables available than in a spatial shader. What exactly are you trying to implement as a sky shader?

1 Like

You can convert a spatial shader to a sky shader, set the shader_type sky; at the top just like in the documentation, and use the sky() function instead of the fragment() funciton (roughly equivalent) you will also most likely have to mess with or replace other stuff in the code of course, since the built-ins for sky are different and the way it renders is a little different too. that page should help you if you can understand the shader itself.

1 Like

something like this: Shader - Shadertoy BETA - an atmospheric effect.
If I use a plane … this is the result :

This is not really applicable to sky shaders. Sky shaders are the last instance at the end of what your camera is rendering so you can’t go “out” of the atmosphere if you would try to render this as a sky shader. What you can try to do instead is to have a seperate half-transparent sphere mesh around a planet mesh and use the shader on that sphere mesh. You then render stars to the sky texture instead.

1 Like

I try to change that plane to a sphere and use the shader but the shader is the basic and the result is not very good. You can see that Transparency is not working well and I need to use Flip Faces.

Maybe use the light() and re-create the new shader for this issue.
Or if the Godot team will comes with a sky for high altitude levels that let create in-out animations.

This cannot be hard for the Godot team, but as you say this can be created in the Godot area to have a proper instance ! ! !

I had a quick go at converting it to a sky shader here. You’ll need to provide a 256x256 noise texture for the uniform but otherwise it just works, this one doesn’t write to the lighting cubemap though that would be the next thing to do probably

shader_type sky;

uniform sampler2D noise_tex;
/*
* created by dmytro rubalskyi (ruba)
*
* all values are in kilometers
*
* references: 
*
* http://nishitalab.org/user/nis/cdrom/sig93_nis.pdf
* 
* http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html
*
* http://www-evasion.imag.fr/people/Eric.Bruneton/
*
* https://software.intel.com/en-us/blogs/2013/09/19/otdoor-light-scattering-sample-update
*
*/

#define M_MAX 1e9
#define KEY_M (float(77)+0.5)/256.0

const float M_PI = 3.1415926535;
const float M_4PI = 4.0 * M_PI;

///////////////////////////////////////
// planet
const float earthRadius 	= 6360.0;
const float atmoHeight 		= 60.0;
const float atmoRadius 		= earthRadius + atmoHeight;
const vec3 earthCenter 		= vec3(0.0, 0.0, 0.0);

///////////////////////////////////////
// sun
const float distanceToSun = 1.496e8;
const float sunRadius = 2.0 * 109.0 * earthRadius;
const float sunIntensity = 10.0;

///////////////////////////////////////
// atmosphere
const vec3 betaR 			= vec3(5.8e-4, 1.35e-3, 3.31e-3);
const vec3 betaM 			= vec3(4.0e-3, 4.0e-3, 4.0e-3);

const vec3 M_4PIbetaR	 	= M_4PI * betaR;
const vec3 M_4PIbetaM 		= M_4PI * betaM;

const float heightScaleRayleight = 6.0;
const float heightScaleMie = 1.2;
const float G = -0.76;

const float NUM_DENSITY_SAMPLES = 8.0;
const float NUM_VIEW_SAMPLES = 8.0;
const int 	INT_NUM_DENSITY_SAMPLES = int(NUM_DENSITY_SAMPLES);
const int	INT_NUM_VIEW_SAMPLES = int(NUM_VIEW_SAMPLES);

///////////////////////////////////////
// ray - sphere intersection
vec2 iSphere(vec3 ro, vec3 rd, vec4 sph)
{
    vec3 tmp = ro - sph.xyz;

    float b = dot(rd, tmp);
    float c = dot(tmp, tmp) - sph.w * sph.w;
    
    float disc = b * b - c;
    
    if(disc < 0.0) return vec2(-M_MAX, -M_MAX);
    
    float disc_sqrt = sqrt(disc);
	
    float t0 = -b - disc_sqrt;
    float t1 = -b + disc_sqrt;
    
    return vec2(t0, t1);
}

///////////////////////////////////////
// Henyey-Greenstein phase function
float phase(float nu, float g)
{
	return (3.0 * (1.0 - g * g) * (1.0 + nu * nu)) / (2.0 * (2.0 + g * g) * pow(1.0 + g * g - 2.0 * g * nu, 1.5));
}

///////////////////////////////////////
// density integral calculation from p0 to p1 
// for mie and rayleight
vec2 densityOverPath(vec3 p0, vec3 p1, vec2 prescaler)
{
    float l = length(p1 - p0);
    vec3  v = (p1 - p0) / l;
    
    l /= NUM_DENSITY_SAMPLES;
    
    vec2 density = vec2(0.0);
    float t = 0.0;
    
	for(int i = 0; i < INT_NUM_DENSITY_SAMPLES; i++)
    {
        vec3 sp = p0 + v * (t + 0.5 * l);
        vec2 h = vec2(length(sp) - earthRadius);
        density += exp(-h / prescaler);
        
        t += l;
    }
    
    return l * density;
}

///////////////////////////////////////
// inscatter integral calculation
vec4 inscatter(vec3 cam, vec3 v, vec3 sun)
{    
    vec4 atmoSphere 	= vec4(earthCenter, atmoRadius);
    vec4 earthSphere 	= vec4(earthCenter, earthRadius);
        
	vec2 t0 = iSphere(cam, v, atmoSphere);
    vec2 t1 = iSphere(cam, v, earthSphere);
   
    bool bNoPlanetIntersection = t1.x < 0.0 && t1.y < 0.0;
    
    float farPoint = bNoPlanetIntersection ? t0.y : t1.x;
    float nearPoint = t0.x > 0.0 ? t0.x : 0.0;
    
    float l = (farPoint - nearPoint) / NUM_VIEW_SAMPLES;
	cam += nearPoint * v;  
    
    float t = 0.0;

    vec3 rayleight = vec3(0.0);
	vec3 mie = vec3(0.0);
    
    vec2 prescalers = vec2(heightScaleRayleight, heightScaleMie);
    
    vec2 densityPointToCam = vec2(0.0);
    
    for(int i = 0; i < INT_NUM_VIEW_SAMPLES; i++)
    {
        vec3 sp = cam + v * (t + 0.5 * l);
        float tc = iSphere(sp, sun, vec4(earthCenter, atmoRadius)).y;
        
        vec3 pc = sp + tc * sun;
        
        vec2 densitySPCam = densityOverPath(sp, cam, prescalers);
        vec2 densities = densityOverPath(sp, pc, prescalers) + densitySPCam;
        
        vec2 h = vec2(length(sp) - earthRadius);
        vec2 expRM = exp(-h / prescalers);
        
        rayleight 	+= expRM.x * exp( -M_4PIbetaR * densities.x );
		mie 		+= expRM.y * exp( -M_4PIbetaM * densities.y );

		densityPointToCam += densitySPCam;
        
        t += l;
    }
    
	rayleight *= l;
    mie *= l;
    
    vec3 extinction = exp( - (M_4PIbetaR * densityPointToCam.x + M_4PIbetaM * densityPointToCam.y));
    
    float nu = dot(sun, -v);
    
    vec3 inscatter_ = sunIntensity * (betaM * mie * phase(nu, G) + betaR * phase(nu, 0.0) * rayleight);
    return vec4(inscatter_, extinction.r * float(bNoPlanetIntersection));
}

///////////////////////////////////////
// rotation around axis Y
vec3 rotate_y(vec3 v, float angle)
{
	vec3 vo = v; float cosa = cos(angle); float sina = sin(angle);
	v.x = cosa*vo.x - sina*vo.z;
	v.z = sina*vo.x + cosa*vo.z;
	return v;
}

///////////////////////////////////////
// noise from iq
float noise( in vec3 x )
{
    vec3 p = floor(x);
    vec3 f = fract(x);
	f = f*f*(3.0-2.0*f);
	
	vec2 uv = (p.xy+vec2(37.0,17.0) * p.z) + f.xy;
	vec2 rg = texture( noise_tex, (uv + 0.5)/256.0, -100.0 ).yx;
	return mix( rg.x, rg.y, f.z );
}

void sky()
{
	if (AT_CUBEMAP_PASS) {
		
	} else {    
	    vec3 ro = vec3(0.0); // ray-origin, camera position
	    
		//bool key_m = texture(iChannel1, vec2(KEY_M, 0.75)).x > 0.0;
		//ro = key_m ?	2.0 * vec3(earthRadius * sin(mouse.x), 0.0, earthRadius * cos(mouse.x)): 
	    //				vec3(0.0, earthRadius + 0.1, 1000.0 * abs(cos(iTime / 10.0)));
		ro = vec3(0.0, earthRadius + 0.1, -960. - (1000.0 * cos(TIME / 7.0)));
	    
		vec3 rd = EYEDIR;
	    
	    vec3 sun = normalize(vec3(1.0, 1.0, 1.0));
	    
	    vec4 col = inscatter(ro, rd, sun);
	    
	    vec3 sunPos = sun * distanceToSun;
	    
	    vec4 star = vec4(sunPos, sunRadius);
	    vec2 t0 = iSphere(ro, rd, star);
	    
	    if(t0.x > 0.0)
	    {
	    	col.xyz += vec3(1.0,1.0,1.0) * col.a;
	    }
	    
	    vec3 stars = vec3(noise(rd * 600. * 0.75));
	    stars += vec3(noise(rd * 600. * 0.5));
	    stars += vec3(noise(rd * 600. * 0.25));
	    stars += vec3(noise(rd * 600. * 0.1));
		stars *= 7.0;
	    stars = clamp(stars, 0., 1.0);
	    stars = (vec3(1.0) - stars);
	    
	    col.xyz = col.xyz + stars * col.a;
	    col.xyz = pow(col.xyz, vec3(1.0 / 2.2));
	    
	    COLOR = col.rgb;
	}
}

yes, your source code helps me. thank you for your help.

maybe I can link the mouse and find a noise shader function to run without using the 256 texture … is more dynamic

I tried to change the iChannel0 with SCREEN_TEXTURE, but this does not have a good result on the sky shader and I don’t have much info about sky shader.

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;

you don’t need to link the mouse, this one already works based on the direction the camera is looking, so you just control the camera

ok, I saw you know shader_type sky, do you have some documentation about this feature?
I cut it from your example and added some new source code … is not ready, I added speed for a ship, and it needs to add a good shader for stars and a planet to this sky shader because is just s sphere. I don’t know if is possible with a sky shader. I tried a cloud shader example …

Sky shaders — Godot Engine (stable) documentation in English this is the documentation about sky shaders specifically.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.