Skip to content

Instantly share code, notes, and snippets.

@clayjohn
Created April 9, 2019 02:13
Show Gist options
  • Save clayjohn/38f669030c9921ac176b6fa2a9ea86b2 to your computer and use it in GitHub Desktop.
Save clayjohn/38f669030c9921ac176b6fa2a9ea86b2 to your computer and use it in GitHub Desktop.
Convert cubemap to panorama in Godot
shader_type canvas_item;
uniform sampler2D front;
uniform sampler2D left;
uniform sampler2D right;
uniform sampler2D back;
uniform sampler2D top;
uniform sampler2D bottom;
void fragment() {
COLOR.x = 1.0;
float theta = UV.y*3.14159;
float phi = UV.x*3.14159*2.0;
vec3 unit = vec3(0,0,0);
unit.x = sin(phi) * sin(theta) * -1.0;
unit.y = cos(theta) * -1.0;
unit.z = cos(phi) * sin(theta) * -1.0;
unit = normalize(unit);
vec2 st = vec2(0.0);
if (-unit.y>=abs(unit.x) && -unit.y>=abs(unit.z)) {
st = ((vec2(1.0, -1.0)*unit.xz)/abs(unit.y)+1.0)/2.0;
COLOR = texture(bottom, st);
} if (unit.y>=abs(unit.x) && unit.y>=abs(unit.z)) {
st = ((unit.xz)/abs(unit.y)+1.0)/2.0;
COLOR = texture(top, st);
} if (unit.x>=abs(unit.y) && unit.x>=abs(unit.z)) {
st = (-unit.zy/abs(unit.x)+1.0)/2.0;
COLOR = texture(left, st);
} if (-unit.x>=abs(unit.y) && -unit.x>=abs(unit.z)) {
st = ((vec2(1.0, -1.0)*unit.zy)/abs(unit.x)+1.0)/2.0;
COLOR = texture(right, st);
} if (unit.z>=abs(unit.x) && unit.z>=abs(unit.y)) {
st = ((vec2(1.0, -1.0)*unit.xy)/abs(unit.z)+1.0)/2.0;
COLOR = texture(back, st);
} if (-unit.z>=abs(unit.x) && -unit.z>=abs(unit.y)) {
st = ((vec2(-1.0)*unit.xy)/abs(unit.z)+1.0)/2.0;
COLOR = texture(front, st);
}
}
/*
in GDscript
# attach all faces
for key in faces:
$Viewport/ColorRect.material.set_shader_param(key, faces[key])
#Update once next frame
$Viewport.render_target_update_mode = Viewport.UPDATE_ONCE
#wait until next frame
yield(get_tree(), "idle_frame")
var texture_data = $Viewport2.get_texture().get_data()
var panorama = ImageTexture.new()
panorama.create_from_image(texture_data)
*/
@GalaxyCr8r
Copy link

GalaxyCr8r commented May 20, 2019

In the GDscript, is faces an enum of front, left, right, back, top, bottom or...?

@clayjohn
Copy link
Author

It is a dictionary where the key is "front", "left" etc. and the value is the corresponding ImageTexture.

Here is the full code for reference, it's not as easy to understand but it contains everything I used.

extends Spatial

var faces = {}

# Called when the node enters the scene tree for the first time.
func _ready():
	#wait until objects in frame
	yield(get_tree(), "idle_frame")
	yield(get_tree(), "idle_frame")
	
	#render cubemap
	render_face("front", 0.0)
	yield(get_tree(), "idle_frame")
	render_face("left", PI/2)
	yield(get_tree(), "idle_frame")
	render_face("back", PI)
	yield(get_tree(), "idle_frame")
	render_face("right", 3.0*PI/2.0)
	yield(get_tree(), "idle_frame")
	render_face("top", PI, PI/2.0)
	yield(get_tree(), "idle_frame")
	render_face("bottom", PI, -PI/2.0)

	#Render panorama sky
	yield(get_tree(), "idle_frame")
	for key in faces:
		$Viewport2/ColorRect.material.set_shader_param(key, faces[key])
	$Viewport2.render_target_update_mode = Viewport.UPDATE_ONCE
	yield(get_tree(), "idle_frame")

	var td = $Viewport2.get_texture().get_data()
	var gg = ImageTexture.new()
	gg.create_from_image(td)

	#Attach panorama sky
	var we = WorldEnvironment.new()
	var wee = Environment.new()
	wee.background_mode = Environment.BG_SKY
	wee.background_sky = PanoramaSky.new()
	wee.background_sky.panorama = gg
	we.environment = wee
	add_child(we)

func render_face(face, diry, dirx = 0.0):
	$Viewport/Camera.rotation.y = diry
	$Viewport/Camera.rotation.x = dirx
	yield(get_tree(), "idle_frame")

	faces[face] = ImageTexture.new()
	faces[face].create_from_image($Viewport.get_texture().get_data())
	faces[face].flags = 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment