Skip to content

Instantly share code, notes, and snippets.

@partybusiness
Last active November 7, 2024 22:29
Show Gist options
  • Save partybusiness/d7594590435217214d9d7d34c7dc9e34 to your computer and use it in GitHub Desktop.
Save partybusiness/d7594590435217214d9d7d34c7dc9e34 to your computer and use it in GitHub Desktop.
@tool
extends EditorScript
# converts an equirectangular panoramic texture to a skyamid format
var source_panorama:String = "res://skybox_example_pano_left.png"
var target_skyamid:String = "res://skyamid.png"
func _run() -> void:
# load source
var source:Image = Image.load_from_file(source_panorama)
var new_image:Image = Image.create(source.get_height(), source.get_height(), false, source.get_format())
#source.get_height()
var last_average:Color = Color.BLACK
var half_size:int = source.get_height()/2
var quadrant_size:int = source.get_width()/4
for ty in range(0, half_size):
last_average = Color.MAGENTA
last_average.a = 0.0
for quad_index in range(0, 4): # per quadrant
for tx in range(-ty, ty):
var get_average:Color = Color.BLACK
get_average.a = 0
var count:int = 0
var quadrant_offset:int = quad_index * quadrant_size - quadrant_size * 0.5 + source.get_width() + 1 # offset to make it match original sky
var vx:int = (float(tx) / (float(ty) * 2.0) + 0.5) * float(quadrant_size)
var vx2:int = (float(tx+1.0) / (float(ty) * 2.0) + 0.5) * float(quadrant_size)
var y_offset:Vector2i = Vector2i(0, 0)
var x_offset:Vector2i = Vector2i(0, 0)
match quad_index:
0:
y_offset = Vector2i(0, -1)
x_offset = Vector2i(1, 0)
1:
y_offset = Vector2i(1, 0)
x_offset = Vector2i(0, 1)
2:
y_offset = Vector2i(0, 1)
x_offset = Vector2i(-1, 0)
3:
y_offset = Vector2i(-1, 0)
x_offset = Vector2i(0, -1)
for avx in range(vx, vx2):
get_average += source.get_pixel( (avx + quadrant_offset) % source.get_width(), ty)
count += 1
if count == 0: # this will happen if panorama source is less than twice the height
new_image.set_pixel(
half_size + tx * x_offset.x + ty * y_offset.x,
half_size + tx * x_offset.y + ty * y_offset.y, last_average)
else:
get_average /= float(count)
new_image.set_pixel(
half_size + tx * x_offset.x + ty * y_offset.x,
half_size + tx * x_offset.y + ty * y_offset.y, get_average)
last_average = get_average
#fill in transparent pixels from neighbours
for x in range(0, new_image.get_width()):
for y in range(0, new_image.get_height()):
var test_colour:Color = new_image.get_pixel(x,y)
if test_colour.a < 0.01:
var get_average:Color = Color.BLACK
var count:int =0
get_average.a = 0.0
var sample:Color = new_image.get_pixel(clamp(x+1, 0, new_image.get_width()-1), y)
if sample.a >= 0.1:
get_average += sample
count += 1
sample = new_image.get_pixel(clamp(x-1, 0, new_image.get_width()-1), y)
if sample.a >= 0.1:
get_average += sample
count += 1
sample = new_image.get_pixel(x, clamp(y+1, 0, new_image.get_height()-1))
if sample.a >= 0.1:
get_average += sample
count += 1
sample = new_image.get_pixel(x, clamp(y-1, 0, new_image.get_height()-1))
if sample.a >= 0.1:
get_average += sample
count += 1
if (count > 0):
get_average /= float(count)
new_image.set_pixel(x, y, get_average)
#save result
new_image.save_png(target_skyamid)
shader_type sky;
uniform sampler2D skyTexture:source_color;
vec2 get_skyamid_uv(vec3 eyedir) {
float ax = abs(eyedir.x);
float xs = sign(eyedir.x);
float az = abs(eyedir.z);
float zs = sign(eyedir.z);
float ay = abs(eyedir.y);
float y = 1.0 - atan(ay, length(vec2(ax,az))) / 1.5708;
float x = 0.0;
if (ax > az) {
x = xs * atan(eyedir.z, ax) / 1.5708;
return vec2(0.5 + y * 0.5 * xs, 0.5 + y * x * xs);
}
else {
x = zs * atan(eyedir.x, az) / 1.5708;
return vec2(0.5 + y * x * zs, 0.5 + y * 0.5 * zs);
}
}
void sky() {
vec2 uv = get_skyamid_uv(EYEDIR);
COLOR = texture(skyTexture, uv).rgb;
}
shader_type spatial;
render_mode unshaded;
uniform sampler2D skyTexture:source_color;
vec2 get_skyamid_uv(vec3 eyedir) {
float ax = abs(eyedir.x);
float xs = sign(eyedir.x);
float az = abs(eyedir.z);
float zs = sign(eyedir.z);
float ay = abs(eyedir.y);
float y = 1.0 - atan(ay, length(vec2(ax,az))) / 1.5708;
float x = 0.0;
if (ax > az) {
x = xs * atan(eyedir.z, ax) / 1.5708;
return vec2(0.5 + y * 0.5 * xs, 0.5 + y * x * xs);
}
else {
x = zs * atan(eyedir.x, az) / 1.5708;
return vec2(0.5 + y * x * zs, 0.5 + y * 0.5 * zs);
}
}
varying vec3 world_position;
void vertex()
{
world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment() {
vec3 view_dir = normalize(world_position - CAMERA_POSITION_WORLD);
vec2 uv = get_skyamid_uv(view_dir);
ALBEDO = texture(skyTexture, uv).rgb;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment