Is there a demo that demonstrates a simple use case for the samplerCube (cubemap) in Godot's shader editor?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By natw2000F2

I am asking this question because beyond the cubemap object itself ( Cubemap — Godot Engine (stable) documentation in English ), I cannot seem to find information on a simple isolated cubemap reflection shader in Godot’s shader documentation.
If anyone knows of/has a sample project where a samplerCube uniform is used that would be ideal.

There appear to be some GLSL tutorials on the subject, but I am somewhat new to shaders and my attempts to translate the syntax used in these tutorials to that used by Godot has not worked well, and I think I may have missed something.

Unfortunately bookofshaders does not appear to have the cubemap chapter ready either.

I also thought a water shader demo may contain some details on this (for fake refraction), but it does not appear to concern itself with cubemaps.

I am under the impression the difference between a UV and a cubemap is that a uv uses two coordinates, u and v to determine the fragment colour for a 2D texture.
A cubemap is a 3D cube whose 2D surface surrounds a central origin, and the coordinates that determine the fragment colour are the points on the cube surface that 3d directional vectors intersect from the origin.

I am unsure how the shader decides where the fragment colour from the cubemap should go although I’m guessing it just maps the cubemap surface coordinates onto the UV somehow, and this is handled by the texture(cubemap, vector) function.

This being so, I thought I could test this using a normalised version of VERTEX in the fragment function, and a populated cubemap assigned to a samplerCube uniform on a shader attached to a cube:

uniform samplerCube cubemap; // Populated with 6 1024 x 1354 image resources
// via the editor

void fragment(){
ALBEDO = texture(cubemap, normalize(VERTEX))
}

As I understand, the texture function used like this returns a fragment colour from the cubemap depending on where the vector passed as the second argument points on the cube. Therefore, using this simple shader on a cube should project at least some colour on the cube interpolated between where the shader decides to put the fragment colours on the mesh.

However, when doing this I am left with a black (although not unshaded) cube, suggesting I am doing something wrong.

I think it may be something to do with the direct assignment of the texture function onto ALBEDO, as I am not sure how it would translate the cubemap colour coordinates onto the mesh surface, or maybe it was the attempt to use a directional vector in the fragment function (but I am new to shaders, so I am not entirely sure what the rules are).

Admittedly, this is a relatively simple cube and so I’m not sure the VERTEX function would return many points, but surely by this logic at least some interpolated colours should show up on the shader.

:bust_in_silhouette: Reply From: natw2000F2

I figured out the core issue myself after a bit of testing so I’ll post the things I found here in case anyone else has any issues.

  1. The editor does not always display the effects of the cubemap. I understand this is because the camera position must be updated, which only happens in game when done via a gd script update as I have done.

  2. The cubemap assets must have equal width/height (hence 1024 x 1354 was not working). Of course thinking about this for 2 seconds, this is obvious in hindsight as you can’t form a neat 3d shape from 6 rectangles so of course it wouldn’t work.

As a side note to use the cubemap make sure to import the images you want to use as the sides of the cubemap as ‘image’ or you will not be able to use it with the cubemap.

I will paste the shader I am using here, it’s far from perfect and is in no way a realistic reflection (for example, the whole cubemap appears to rotate faster than it should when the player is rotating (around 360 degrees for a 90 degree rotation from the player)), but hopefully a starting point in case anyone’s in the position I was. Make need to update the camera position uniform via gd script although it seems to work regardless? I’m not sure:

shader_type spatial;

varying vec3 position;
varying vec2 textureCoordinates;
varying vec3 normal;

varying vec3 pass_normal;
varying vec2 pass_textureCoordinates;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 cameraPosition;

uniform vec2 ratio = vec2(0.0);
uniform vec2 offset = vec2(0.0);

varying vec4 out_Colour;

uniform sampler2D tex;
uniform samplerCube cubemap;

const vec3 lightDirection = vec3(0, -1, 0);
const float ambient = 2.0;

void fragment()
{
	vec3 reflectedVector;
	//position = VERTEX.xyz;//vec3(0,-20,0);
	position = VERTEX.xyz;//vec3(0,-20,0);
	position.z*=-1.;
	textureCoordinates = UV*ratio-offset;
	normal = NORMAL;
	float brightness = max(dot(lightDirection, normalize(normal)), 0.0) + ambient;
	//out_Colour = texture(tex, textureCoordinates) * brightness;
	out_Colour = vec4(1, 0,0,1);
	
	vec4 worldPosition = WORLD_MATRIX * vec4(position.x, position.y, position.z, 1.0);
	
    // vec2 theta = ((UV.xy / worldPosition.xy) * 2. - 1.) * vec2(-3.14159265359, 1.57079632679);
	vec3 unitNormal = normalize(normal);
	vec3 viewVector = (worldPosition.xyz - cameraPosition);	
	//unitNormal.y = -1.*unitNormal.y;
	reflectedVector = reflect(viewVector, unitNormal);
	vec4 reflectedColour = texture(cubemap, reflectedVector, 1.0);//reflectedVector);
	out_Colour = mix(out_Colour, reflectedColour, 0.7);
	//out_Colour = mix(out_Colour, reflectedColour, 1.0);
	//out_Colour = vec4(reflectedVector,1);
	//out_Colour = reflectedColour;
	SPECULAR = 1.0;
	METALLIC = 1.0;
	ROUGHNESS = 0.0;
	//vec3 dir = vec3(reflectedVector.x, reflectedVector.y*cos(theta.y) + reflectedVector.z*sin(theta.y), reflectedVector.y*-sin(theta.y) + reflectedVector.z*cos(theta.y)); 
    //dir = vec3(dir.x*cos(theta.x) + dir.z*-sin(theta.x), dir.y, dir.x*sin(theta.x) + dir.z*cos(theta.x));
	
	//vec4 col = texture(cubemap, reflectedVector,1.0);
	ALBEDO = out_Colour.rgb;
	//ALPHA = 1.0;
}