N64 Style Skybox
Single-image skybox as seen in some N64 and PS1 games. I’ve always enjoyed this effect but found surprisingly little information about it, so I decided to recreate it myself.
This works as a spatial shader where you apply it to a skybox object surrounding the scene. It’s also possible to implement as a proper sky shader, but you have to pass the camera’s rotation from a script since sky shaders don’t have access to the view matrix.
Shader code
shader_type spatial;
render_mode unshaded;
uniform sampler2D sky_texture : source_color;
uniform bool lock_aspect = false;
uniform float aspect_ratio = 1.3333333;
uniform vec2 fov = vec2(180.0, 90.0);
uniform ivec2 tiling = ivec2(1, 1);
uniform vec2 offset = vec2(0.0, 0.0);
varying vec4 BG_COORDS;
void vertex() {
//Camera YX rotation per Basis.get_euler source code
float y = atan(VIEW_MATRIX[0][2], VIEW_MATRIX[2][2]);
float x = asin(VIEW_MATRIX[1][2]);
//Map rotation to screen space
BG_COORDS.xy = vec2(y * -0.5, x) / PI;
BG_COORDS.y += 0.5;
BG_COORDS.w = fov.y / 180.0;
BG_COORDS.z = !lock_aspect ? fov.x / 360.0 : VIEWPORT_SIZE.x / (VIEWPORT_SIZE.y * aspect_ratio) * BG_COORDS.w;
//Keep background centered vertically when FOV changes
BG_COORDS.y *= BG_COORDS.w > 1.0 ? 0.0 : 1.0 - BG_COORDS.w;
}
void fragment() {
vec2 uv_offset = vec2(-offset.x, offset.y);
vec2 uv = (SCREEN_UV + uv_offset) * BG_COORDS.zw + BG_COORDS.xy;
uv *= vec2(tiling);
ALBEDO = texture(sky_texture, uv).rgb;
}
Can someone explain how to use it, i dont understand it
Easiest way to use it:
could you offer the template texture you used in the gif? that looks very helpful incase you wanna make custom backgrounds
Oh, sure: https://imgur.com/a/L4suJ8B
Godot 3.5???
shader_type spatial;
render_mode unshaded;
uniform sampler2D sky_texture : hint_albedo;
uniform bool lock_aspect = false;
uniform float aspect_ratio = 1.3333333;
uniform vec2 fov = vec2(180.0, 90.0);
//uniform ivec2 tiling = ivec2(1, 1);
uniform vec2 offset = vec2(0.0, 0.0);
const float PI = 3.14159;
varying vec2 BG_COORDS;
varying vec2 BG_SCALE;
void vertex() {
//Camera YX rotation per Basis.get_euler source code
float y = atan(CAMERA_MATRIX[0][2], CAMERA_MATRIX[2][2]);
float x = asin(CAMERA_MATRIX[1][2]);
//Map rotation to screen space
BG_COORDS = vec2(y * 0.5, -x) * -(1.0 / PI);
BG_COORDS.y += 0.5;
BG_SCALE.y = fov.y * (1.0 / 180.0);
BG_SCALE.x = !lock_aspect ?
fov.x * (1.0 / 360.0) :
VIEWPORT_SIZE.x / (VIEWPORT_SIZE.y * aspect_ratio) * BG_SCALE.y;
//Keep background centered vertically when FOV changes
BG_COORDS.y *= BG_SCALE.y > 1.0 ? 0.0 : 1.0 - BG_SCALE.y;
}
void fragment() {
vec2 uv_offset = vec2(-offset.x, offset.y);
vec2 uv = (SCREEN_UV + uv_offset) * BG_SCALE + BG_COORDS;
// uv *= vec2(tiling);
ALBEDO = texture(sky_texture, uv).rgb;
}
(I took tiling out cause it seems to break it)
This works perfectly, thank you! But I have a question – is it possible to use nearest neighbor interpolation instead of linear interpolation here?
Replace:
uniform sampler2D sky_texture : source_color;
with:
uniform sampler2D sky_texture : source_color, filter_nearest;
Hey! nice shader. I have bug and i cannot use it.
https://imgur.com/a/pENKo6u
Thanks for pointing it out, it’ll work correctly if you change BG_COORDS to BG_COORDS.xy on that line
Thank you!!! it workssssss
What about
EYEDIR
? It’s available in sky shaders (but not spatial shaders, interestingly).The way this shader works, it needs to know the actual rotation of the camera. I don’t think that could be derived from EYEDIR, but maybe if you also use the view space position? If you think it’s possible I’d be interested to know.
AW HELL NAW PALESTINES BEING INVADED BY CARTOONS NOW?!????