How to make this colors more realistic?

Godot Version

4.5.1

Question

The code is this:

extends Node3D

var velocidad = 30.0
var sensibilidad = 0.002
var camara : Camera3D # Definimos el tipo de variable claramente

func _ready():
	setup_lighting_and_env()
	generar_mundo()
	
	# 1. CREAR CÁMARA CORRECTAMENTE
	camara = Camera3D.new()
	add_child(camara) # Primero se añade al mundo...
	camara.make_current() # ...y luego se activa
	camara.position = Vector3(0, 0, 0) # Posición inicial elevada
	
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

var yaw = 0.0   # Rotación izquierda/derecha
var pitch = 0.0 # Rotación arriba/abajo

func _unhandled_input(event):
	# Captura/Liberación de mouse
	if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
		if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
			Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		else:
			Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
		# Actualizamos los ángulos basados en el movimiento del ratón
		# Invertimos el signo aquí para cambiar la dirección de rotación
		yaw -= event.relative.x * sensibilidad 
		pitch -= event.relative.y * sensibilidad
		
		# Limitamos el ángulo vertical para no dar la vuelta
		pitch = clamp(pitch, deg_to_rad(-89), deg_to_rad(89))

func _process(delta):
	if not camara: return
	
	# 1. DIRECCIÓN DE LA MIRADA (Seno y Coseno)
	var direccion_mirada = Vector3(
		sin(yaw) * cos(pitch),
		sin(pitch),
		cos(yaw) * cos(pitch)
	)
	
	# 2. APLICAR LOOK_AT
	# Importante: Miramos hacia adelante (sumando la dirección a la posición actual)
	camara.look_at(camara.global_position + direccion_mirada, Vector3.UP)

	# 3. MOVIMIENTO
	var movimiento = Vector3.ZERO
	
	# Calculamos 'adelante' basado solo en el giro horizontal (yaw)
	# Nota: En Godot -Z es hacia adelante, por eso usamos los signos así:
	var adelante = Vector3(sin(yaw), 0, cos(yaw)) 
	var derecha = Vector3(sin(yaw + PI/2), 0, cos(yaw + PI/2))
	
	
	if Input.is_key_pressed(KEY_W): movimiento += adelante # Ir hacia adelante
	if Input.is_key_pressed(KEY_S): movimiento -= adelante # Ir hacia atrás
	if Input.is_key_pressed(KEY_A): movimiento += derecha  # Ir izquierda
	if Input.is_key_pressed(KEY_D): movimiento -= derecha  # Ir derecha
	
	# 4. APLICAR MOVIMIENTO AL NODO PRINCIPAL
	if movimiento != Vector3.ZERO:
		camara.position += movimiento.normalized() * velocidad * delta
	if Input.is_key_pressed(KEY_E): camara.position.y += velocidad * delta  # Ir arriba.
	if Input.is_key_pressed(KEY_Q): camara.position.y -= velocidad * delta  # Ir abajo.

func generar_mundo():
	var tamaño = 100
	var noise = FastNoiseLite.new()
	noise.frequency = 0.005
	
	# --- CARGAMOS LA TEXTURA AQUÍ ---
	var textura_tierra = load("res://dirt.jpg")
	
	var container = Node3D.new()
	add_child(container)
	
	# Configuramos el material base con Triplanar
	var material_comun = StandardMaterial3D.new()
	material_comun.albedo_texture = textura_tierra
	material_comun.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
	
	# ESTO ES LO QUE EVITA QUE SE ESTIRE LA TEXTURA EN EL GREEDY
	material_comun.uv1_triplanar = true
	material_comun.uv1_world_triplanar = true
	material_comun.uv1_scale = Vector3(1, 1, 1) # Repetir cada 1 metro
	
	for x in range(tamaño):
		for z in range(tamaño):
			var altura_max = int(round(noise.get_noise_2d(x, z) * 100) + 20)
			
			var y = 0
			while y < altura_max:
				var inicio_y = y
				var color_actual = obtener_color_por_altura(y, altura_max)
				
				while y < altura_max and obtener_color_por_altura(y, altura_max) == color_actual:
					y += 1
				
				var altura_segmento = y - inicio_y
				
				var mesh_instance = MeshInstance3D.new()
				var mesh_res = BoxMesh.new()
				
				mesh_res.size = Vector3(1, altura_segmento, 1)
				mesh_instance.mesh = mesh_res
				
				var pos_y = inicio_y + (float(altura_segmento) / 2.0)
				mesh_instance.position = Vector3(x, pos_y, z)
				
				# Aplicamos el material duplicado para mantener el color único
				var mat_unico = material_comun.duplicate()
				mat_unico.albedo_color = color_actual
				mesh_instance.material_override = mat_unico
				
				container.add_child(mesh_instance)

func obtener_color_por_altura(y, surface):
	var color_bloque = Color("00ff00ff") # Marrón
	if y < surface - 2: color_bloque = Color("aa8866")
	if y < 25: color_bloque = Color("ff7700") # Amarillo
	return color_bloque

func setup_lighting_and_env():
	# 1. LUZ (Sol)
	var sol = DirectionalLight3D.new()
	sol.shadow_enabled = true
	sol.rotation_degrees = Vector3(-45, 0, -45) 
	add_child(sol)
	
	# 2. MATERIAL DEL CIELO (Procedural)
	var sky_material = ProceduralSkyMaterial.new()
	# Colores exactos para el degradado horizontal
	sky_material.sky_top_color = Color(0.0, 0.498, 1.0, 1.0) 
	sky_material.sky_horizon_color = Color(0.0, 1.0, 1.0, 1.0)
	sky_material.ground_bottom_color = Color(0.2, 0.17, 0.15)
	sky_material.ground_horizon_color = Color(0.65, 0.72, 0.81) # Igual al horizonte del cielo
	
	# Creamos el temporizador
	var timer_sol = Timer.new()
	add_child(timer_sol)
	timer_sol.wait_time = 0.1  # Se ejecuta cada 0.1 segundos
	timer_sol.autostart = true
	# Conectamos el timer a la rotación
	timer_sol.timeout.connect(func():
		if sol:
			sol.light_energy = 3.0
			sol.light_color = Color(1.0, 1.0, 1.0)
			# Rotamos 0.5 grados en cada intervalo
			sol.rotate_x(deg_to_rad(0.01))
			sol.rotate_z(deg_to_rad(0.01))
			# ESTO TE DIRÁ EN LA CONSOLA SI ESTÁ ROTANDO O NO
			print("SOL ROTANDO: ", sol.rotation_degrees.x)
# 2. Calcular "Factor de Luz" (0.0 es noche total, 1.0 es mediodía)
			# Usamos el seno de la rotación para saber qué tan arriba está el sol
			var angulo_rad = sol.rotation.x
			var factor_luz = clamp(-sin(angulo_rad), 0.0, 1.0)
			
			# 3. Aplicar oscuridad a los colores originales
			# Multiplicamos el color por el factor_luz para que se apague en la noche
			var color_top_base = Color(0.0, 0.498, 1.0)
			var color_hor_base = Color(0.0, 1.0, 1.0)
			
			sky_material.sky_top_color = color_top_base * factor_luz
			sky_material.sky_horizon_color = color_hor_base * factor_luz
			
			# Opcional: El suelo también debe oscurecerse
			sky_material.ground_horizon_color = sky_material.sky_horizon_color
			
			# 4. Ajustar la energía de la luz para que no haya sombras de noche
			sol.light_energy = factor_luz
	)
	
	timer_sol.start()
	
	# 3. CONFIGURACIÓN DEL ENTORNO
	var sky_res = Sky.new()
	sky_res.sky_material = sky_material
	
	var env_res = Environment.new()
	env_res.background_mode = Environment.BG_SKY
	env_res.sky = sky_res
	
	# Iluminación indirecta para que las sombras no sean negras
	env_res.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
	env_res.ambient_light_sky_contribution = 0.01
	
	var env_node = WorldEnvironment.new()
	env_node.environment = env_res
	add_child(env_node)

And the result is this:


I need to make sand in the bottom more realistic. How to do it?

Hi!

Does changing the color on this line not work?

if y < 25: color_bloque = Color("ff7700") # Amarillo

Yes, but it doesnt how me a yellow color…

Maybe try fff000, it’s a bit more yellow than ff7700. :four_leaf_clover:

I want it more like orange than the code you gave to me, as this:

1 Like

You might get limited by the texture you gave your blocks var textura_tierra = load("res://dirt.jpg"). Maybe try some different textures.


The same result happens…

I now found a better algorithm of rendering:

extends Node3D

— AJUSTES —

const AREA = 500 # 150x150 = 22,500 columnas (Equivale a millones de bloques de tu script anterior)
var velocidad = 40.0
var sensibilidad = 0.002
var camara : Camera3D

var yaw = 0.0
var pitch = 0.0

func _ready():
# 1. Seguridad: Esperar un frame para que el motor inicialice
await get_tree().process_frame

setup_lighting_and_env()
generar_mundo_seguro()

# Cámara
camara = Camera3D.new()
add_child(camara)
camara.make_current()
camara.position = Vector3(AREA/2, 100, AREA/2)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

func _unhandled_input(event):
# Captura/Liberación de mouse
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
# Actualizamos los ángulos basados en el movimiento del ratón
# Invertimos el signo aquí para cambiar la dirección de rotación
yaw -= event.relative.x * sensibilidad
pitch -= event.relative.y * sensibilidad

	# Limitamos el ángulo vertical para no dar la vuelta
	pitch = clamp(pitch, deg_to_rad(-89), deg_to_rad(89))

func _process(delta):
if not camara: return

# 1. DIRECCIÓN DE LA MIRADA (Seno y Coseno)
var direccion_mirada = Vector3(
	sin(yaw) * cos(pitch),
	sin(pitch),
	cos(yaw) * cos(pitch)
)

# 2. APLICAR LOOK_AT
# Importante: Miramos hacia adelante (sumando la dirección a la posición actual)
camara.look_at(camara.global_position + direccion_mirada, Vector3.UP)

# 3. MOVIMIENTO
var movimiento = Vector3.ZERO

# Calculamos 'adelante' basado solo en el giro horizontal (yaw)
# Nota: En Godot -Z es hacia adelante, por eso usamos los signos así:
var adelante = Vector3(sin(yaw), 0, cos(yaw)) 
var derecha = Vector3(sin(yaw + PI/2), 0, cos(yaw + PI/2))


if Input.is_key_pressed(KEY_W): movimiento += adelante # Ir hacia adelante
if Input.is_key_pressed(KEY_S): movimiento -= adelante # Ir hacia atrás
if Input.is_key_pressed(KEY_A): movimiento += derecha  # Ir izquierda
if Input.is_key_pressed(KEY_D): movimiento -= derecha  # Ir derecha

# 4. APLICAR MOVIMIENTO AL NODO PRINCIPAL
if movimiento != Vector3.ZERO:
	camara.position += movimiento.normalized() * velocidad * delta
if Input.is_key_pressed(KEY_E): camara.position.y += velocidad * delta  # Ir arriba.
if Input.is_key_pressed(KEY_Q): camara.position.y -= velocidad * delta  # Ir abajo.

— GENERACIÓN ROBUSTA —

func generar_mundo_seguro():
var noise = FastNoiseLite.new()
noise.seed = randi()
noise.frequency = 0.01

var mm_instance = MultiMeshInstance3D.new()
var mm = MultiMesh.new()

# Configuración obligatoria antes de asignar el count
mm.transform_format = MultiMesh.TRANSFORM_3D
mm.use_colors = true 
mm.mesh = BoxMesh.new()

# Importante: El count debe ser exacto
mm.instance_count = AREA * AREA

# Material con protección por si no tienes la textura "dirt.jpg"
var mat = StandardMaterial3D.new()
if FileAccess.file_exists("res://dirt.jpg"):
	mat.albedo_texture = load("res://dirt.jpg")
else:
	# Color base si falla la textura para evitar el crash de carga
	mat.albedo_color = Color(0.4, 0.3, 0.2)
	
mat.vertex_color_use_as_albedo = true
mat.uv1_triplanar = true
mat.uv1_world_triplanar = true
mat.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
mm.mesh.material = mat

mm_instance.multimesh = mm
add_child(mm_instance)

var i = 0
for x in range(AREA):
	for z in range(AREA):
		var amplitud = 100.0   # Ajusta esto para la altura máxima
		var frecuencia = 0.01 # Menor valor = terreno más estirado horizontalmente
		noise.frequency = frecuencia 
		# Esta es la función optimizada:
		var h = int((noise.get_noise_2d(x, z) + 1.0) * 0.5 * amplitud)
		
		# Creamos la transformación: Escala en Y = Altura, Posición Y = Altura/2
		var t = Transform3D()
		t = t.scaled(Vector3(1, h, 1))
		t.origin = Vector3(float(x), h / 2.0, float(z))
		
		mm.set_instance_transform(i, t)
		mm.set_instance_color(i, _get_color(h))
		i += 1

func _get_color(y):
if y > 70: return Color(0.8, 1.0, 1.0) # Nieve
if y > 30: return Color(0.4, 0.3, 0.2) # Piedra
return Color(0.9, 0.5, 0.0) # Arena.

— ILUMINACIÓN —

func setup_lighting_and_env():
# 1. LUZ (Sol)
var sol = DirectionalLight3D.new()
sol.shadow_enabled = true
sol.rotation_degrees = Vector3(-45, 0, -45)
add_child(sol)

# 2. MATERIAL DEL CIELO (Procedural)
var sky_material = ProceduralSkyMaterial.new()
# Colores exactos para el degradado horizontal
sky_material.sky_top_color = Color(0.0, 0.498, 1.0, 1.0) 
sky_material.sky_horizon_color = Color(0.0, 1.0, 1.0, 1.0)
sky_material.ground_bottom_color = Color(0.2, 0.17, 0.15)
sky_material.ground_horizon_color = Color(0.65, 0.72, 0.81) # Igual al horizonte del cielo

# Creamos el temporizador
var timer_sol = Timer.new()
add_child(timer_sol)
timer_sol.wait_time = 0.1  # Se ejecuta cada 0.1 segundos
timer_sol.autostart = true
# Conectamos el timer a la rotación
timer_sol.timeout.connect(func():
	if sol:
		sol.light_color = Color(2.0, 2.0, 2.0)
		# Rotamos 0.5 grados en cada intervalo
		sol.rotate_x(deg_to_rad(0.01))
		sol.rotate_z(deg_to_rad(0.01))
		# ESTO TE DIRÁ EN LA CONSOLA SI ESTÁ ROTANDO O NO
		print("SOL ROTANDO: ", sol.rotation_degrees.x)

2. Calcular “Factor de Luz” (0.0 es noche total, 1.0 es mediodía)

		# Usamos el seno de la rotación para saber qué tan arriba está el sol
		var angulo_rad = sol.rotation.x
		var factor_luz = clamp(-sin(angulo_rad), 0.0, 1.0)
		
		# 3. Aplicar oscuridad a los colores originales
		# Multiplicamos el color por el factor_luz para que se apague en la noche
		var color_top_base = Color(0.0, 0.498, 1.0)
		var color_hor_base = Color(0.0, 1.0, 1.0)
		
		sky_material.sky_top_color = color_top_base * factor_luz
		sky_material.sky_horizon_color = color_hor_base * factor_luz
		
		# Opcional: El suelo también debe oscurecerse
		sky_material.ground_horizon_color = sky_material.sky_horizon_color
		
		# 4. Ajustar la energía de la luz para que no haya sombras de noche
		sol.light_energy = factor_luz
)

timer_sol.start()

# 3. CONFIGURACIÓN DEL ENTORNO
var sky_res = Sky.new()
sky_res.sky_material = sky_material

var env_res = Environment.new()
env_res.background_mode = Environment.BG_SKY
env_res.sky = sky_res

# Iluminación indirecta para que las sombras no sean negras
env_res.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
env_res.ambient_light_sky_contribution = 0.01

var env_node = WorldEnvironment.new()
env_node.environment = env_res
add_child(env_node)

But I have lost another one, the original color commands…

It looks same at this image:

For start, add some ambient color to the environment. Those pitch black shadows are far from realistic.

I did it… ?

Another shadow map is this:


Do u recommend it?

Still too much black for an outdoor scene. Exteriors typically have a lot of blue ambient light as well as some distance fog. Those things can make a scene look significantly more realistic.

This is the most lightly the shadows can be made…

The code is this:

extends Node3D

— AJUSTES —

const AREA = 500 # 150x150 = 22,500 columnas (Equivale a millones de bloques de tu script anterior)
var velocidad = 5.0
var sensibilidad = 0.001
var camara : Camera3D

var yaw = 0.0
var pitch = 0.0

var amplitud = 200.0   # Ajusta esto para la altura máxima
var frecuencia = 0.005 # Menor valor = terreno más estirado horizontalmente
var noise = FastNoiseLite.new()

func _ready():
# 1. ESTO EVITA QUE EL NARANJA SEA MARRÓN:
# Forzamos al motor a usar el espacio de color sRGB (Colores vivos)
# y no el Lineal (Colores realistas/apagados).
ProjectSettings.set_setting(“rendering/textures/canvas_textures/default_texture_filter”, 0)

# 2. EL TRUCO "FULL BRIGHT" EN EL READY:
# Esto hace que la luz ambiental no tenga dirección y no cree sombras sucias.
var scenario = get_world_3d().scenario
RenderingServer.scenario_set_fallback_environment(scenario, get_viewport().world_3d.fallback_environment)

# 3. LO QUE BUSCAS DE LOS COLORES:
# Si usas colores hexadecimales o Color.ORANGE, Godot los oscurece.
# Esta línea le dice al renderizador que no aplique corrección gamma.
OS.set_environment("GODOT_SRGB_COLORSPACE_CHECK", "0") 

# Cámara y captura
camara = Camera3D.new()
add_child(camara)
camara.make_current()
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
# 1. Seguridad: Esperar un frame para que el motor inicialice
await get_tree().process_frame

setup_lighting_and_env()
generar_mundo_seguro()

# Cámara
camara = Camera3D.new()
add_child(camara)
camara.make_current()
camara.position = Vector3(AREA/2, 100, AREA/2)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

func _unhandled_input(event):
# Captura/Liberación de mouse
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
# Actualizamos los ángulos basados en el movimiento del ratón
# Invertimos el signo aquí para cambiar la dirección de rotación
yaw -= event.relative.x * sensibilidad
pitch -= event.relative.y * sensibilidad

	# Limitamos el ángulo vertical para no dar la vuelta
	pitch = clamp(pitch, deg_to_rad(-89), deg_to_rad(89))

func _process(delta):
if not camara: return
# Así es como debe ir dentro del _process:
camara.position.y = 2+int((noise.get_noise_2d(camara.position.x, camara.position.z) + 1.0) * 0.5 * amplitud)

# 1. DIRECCIÓN DE LA MIRADA (Seno y Coseno)
var direccion_mirada = Vector3(
	sin(yaw) * cos(pitch),
	sin(pitch),
	cos(yaw) * cos(pitch)
)

# 2. APLICAR LOOK_AT
# Importante: Miramos hacia adelante (sumando la dirección a la posición actual)
camara.look_at(camara.global_position + direccion_mirada, Vector3.UP)

# 3. MOVIMIENTO
var movimiento = Vector3.ZERO

# Calculamos 'adelante' basado solo en el giro horizontal (yaw)
# Nota: En Godot -Z es hacia adelante, por eso usamos los signos así:
var adelante = Vector3(sin(yaw), 0, cos(yaw)) 
var derecha = Vector3(sin(yaw + PI/2), 0, cos(yaw + PI/2))


if Input.is_key_pressed(KEY_W): movimiento += adelante # Ir hacia adelante
if Input.is_key_pressed(KEY_S): movimiento -= adelante # Ir hacia atrás
if Input.is_key_pressed(KEY_A): movimiento += derecha  # Ir izquierda
if Input.is_key_pressed(KEY_D): movimiento -= derecha  # Ir derecha
# 4. APLICAR MOVIMIENTO AL NODO PRINCIPAL
if movimiento != Vector3.ZERO:
	camara.position += movimiento.normalized() * velocidad * delta

— GENERACIÓN ROBUSTA —

func generar_mundo_seguro():
noise.seed = randi()
noise.frequency = 0.01

var mm_instance = MultiMeshInstance3D.new()
var mm = MultiMesh.new()

# Configuración obligatoria antes de asignar el count
mm.transform_format = MultiMesh.TRANSFORM_3D
mm.use_colors = true 
mm.mesh = BoxMesh.new()

# Importante: El count debe ser exacto
mm.instance_count = AREA * AREA

# Material con protección por si no tienes la textura "dirt.jpg"
var mat = StandardMaterial3D.new()
if FileAccess.file_exists("res://dirt.jpg"):
	mat.albedo_texture = load("res://dirt.jpg")
else:
	# Color base si falla la textura para evitar el crash de carga
	mat.albedo_color = Color(0.4, 0.3, 0.2)
	
mat.vertex_color_use_as_albedo = true
mat.uv1_triplanar = true
mat.uv1_world_triplanar = true
mat.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
mm.mesh.material = mat

mm_instance.multimesh = mm
add_child(mm_instance)

var i = 0
for x in range(AREA):
	for z in range(AREA):
		noise.frequency = frecuencia 
		# Esta es la función optimizada:
		var h = int((noise.get_noise_2d(x, z) + 1.0) * 0.5 * amplitud)
		
		# Creamos la transformación: Escala en Y = Altura, Posición Y = Altura/2
		var t = Transform3D()
		t = t.scaled(Vector3(1, h, 1))
		t.origin = Vector3(float(x), h / 2.0, float(z))
		
		mm.set_instance_transform(i, t)
		mm.set_instance_color(i, _get_color(h))
		i += 1

func _get_color(y):
if y > 75: return Color(0.4, 0.3, 0.2) # Piedra
return Color(0.9, 0.5, 0.0) # Arena.

— ILUMINACIÓN —

func setup_lighting_and_env():
# 1. LUZ (Sol)
var sol = DirectionalLight3D.new()
sol.shadow_enabled = true
sol.rotation_degrees = Vector3(-45, 0, -45)
add_child(sol)

# 2. MATERIAL DEL CIELO (Procedural)
var sky_material = ProceduralSkyMaterial.new()
# Colores exactos para el degradado horizontal
sky_material.sky_top_color = Color(0.0, 0.498, 1.0, 1.0) 
sky_material.sky_horizon_color = Color(0.0, 1.0, 1.0, 1.0)
sky_material.ground_bottom_color = Color(0.2, 0.17, 0.15)
sky_material.ground_horizon_color = Color(0.65, 0.72, 0.81) # Igual al horizonte del cielo

# Creamos el temporizador
var timer_sol = Timer.new()
add_child(timer_sol)
timer_sol.wait_time = 0.1  # Se ejecuta cada 0.1 segundos
timer_sol.autostart = true
# Conectamos el timer a la rotación
timer_sol.timeout.connect(func():
	if sol:
		sol.light_color = Color(2.0, 2.0, 2.0)
		# Rotamos 0.5 grados en cada intervalo
		sol.rotate_x(deg_to_rad(0.01))
		sol.rotate_z(deg_to_rad(0.01))
		# ESTO TE DIRÁ EN LA CONSOLA SI ESTÁ ROTANDO O NO
		print("SOL ROTANDO: ", sol.rotation_degrees.x)
		# 2. Calcular "Factor de Luz" (0.0 es noche total, 1.0 es mediodía)
		# Usamos el seno de la rotación para saber qué tan arriba está el sol
		var angulo_rad = sol.rotation.x
		var factor_luz = clamp(-sin(angulo_rad), 0.0, 1.0)
		
		# 3. Aplicar oscuridad a los colores originales
		# Multiplicamos el color por el factor_luz para que se apague en la noche
		var color_top_base = Color(0.0, 0.498, 1.0)
		var color_hor_base = Color(0.0, 1.0, 1.0)
		
		sky_material.sky_top_color = color_top_base * factor_luz
		sky_material.sky_horizon_color = color_hor_base * factor_luz
		
		# Opcional: El suelo también debe oscurecerse
		sky_material.ground_horizon_color = sky_material.sky_horizon_color
		
		# 4. Ajustar la energía de la luz para que no haya sombras de noche
		sol.light_energy = factor_luz
)

timer_sol.start()

# 3. CONFIGURACIÓN DEL ENTORNO
var sky_res = Sky.new()
sky_res.sky_material = sky_material

var env_res = Environment.new()
env_res.background_mode = Environment.BG_SKY
env_res.sky = sky_res

# Iluminación indirecta para que las sombras no sean negras
env_res.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
env_res.ambient_light_sky_contribution = 1.0

var env_node = WorldEnvironment.new()
env_node.environment = env_res
add_child(env_node)

No, it isn’t. Increase the ambient light color/energy in your world environment node.

I dont know how xd…

Add a WorldEnvironment node to your scene if you already don’t have one, add an Environment resource to it, and adjust its properties in the inspector.

Sorry but more than 1 script and default buttons crashes the engine, i had bad experiences… x_x

env_res.ambient_light_sky_contribution = 1000000.0 doesnt work… true?