Shader language's texture() function retrieves white color for vec2(0,0) input

Godot Version



Apologies in advance for the lack of pictures. I have plenty of great screenshots to demonstrate this bug, but because I’m a new user, I’m limited to one embedded upload per post.

I am following this (dated) tutorial on YouTube, and I’ve encountered some strange behavior regarding a shader and the texture() function in the GLSL language.

I have a ShaderMaterial applied to the Material Override of a MeshInstance3D within my scene. Here is a the shader file code:

shader_type spatial;

uniform float min_height;
uniform float max_height;
uniform sampler2D height_color: source_color;

varying float height;

void vertex() {
	height = length(VERTEX);

void fragment() {
	float t = height / (max_height - min_height) - (min_height / (max_height - min_height));
	vec3 color = texture(height_color, vec2(t, 0.0)).rgb;
	ALBEDO = color;

The uniform sampler2D height_color variable is passed an instance of GradientTexture1D with the following metadata:

[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://dpje5idhfvvy3"]

[sub_resource type="Gradient" id="Gradient_waokt"]
offsets = PackedFloat32Array(0, 0.03, 0.159686, 0.32199, 0.534031, 0.67801, 0.863874)
colors = PackedColorArray(0.0339462, 0.0841454, 0.507958, 1, 0.95, 0.922767, 0.5415, 1, 0.0666667, 0.25098, 0.141176, 1, 0.0666667, 0.25098, 0.141176, 1, 0.388235, 0.376471, 0.360784, 1, 0.388235, 0.376471, 0.360784, 1, 1, 1, 1, 1)

gradient = SubResource("Gradient_waokt")
width = 128

Nothing fancy; just a simple gradient that starts at a deep blue (for water), then transitions through several colors before finishing off at white (for snow-capped mountains). The gradient renders just fine, with one problem: the oceans aren’t blue; they’re white!


At first, I thought the issue was with my vertex calculations, but then I discovered what eventually led me to creating this post. I found if I add the following line to my fragment() function, the oceans turn blue:

void fragment() {
	// Note: `t` now has a minimum value of 0.004
	float t = max(0.004, height / (max_height - min_height) - (min_height / (max_height - min_height)));
	vec3 color = texture(height_color, vec2(t, 0.0)).rgb;
	ALBEDO = color;

My next thought was, perhaps there is some weird floating-point bugs occurring because I’m subtracting two almost-zero but not quite zero floating-point values and getting a negative result. To test, I changed my fragment() function again:

void fragment() {
	float t = 0.0;
	vec3 color = texture(height_color, vec2(t, 0.0)).rgb;
	ALBEDO = color;

And the result confirmed the critical code was not with my floating-point arithmetic, but with the texture() function. The whole planet is white! Compare this to if I hardcode float t = 0.004. The planet becomes all-blue!

Now that I’ve provided (what I hope to be) sufficient background, my question is simple: why does the texture() function return a white color when evaluated at 0? One can see in my GradientTexture1D config file that I am starting with the deep blue color right from the start (offsets = PackedFloat32Array(0, 0.03, ...), colors = PackedColorArray(0.0339462, 0.0841454, 0.507958, 1, ...). Is this a bug in the texture() function? Or is this expected behavior? Perhaps I’m using the wrong class to define my color gradient to be used in a shader?

Any clarification at all would be greatly appreciated! Thank you, Godot community!