Névoa por profundidade
Um quad na frente da câmera lendo a DEPTH_TEXTURE, então a névoa sabe a que distância está cada pixel.
O editor acima está rodando este projeto. Mude uma linha e ele recarrega.
Classes do Godot usadas
QuadMeshCamera3DShaderMaterial
O código
scripts/main.gd
extends Node
func _ready() -> void:
_add_environment()
_add_light()
_add_ground()
for i in 12:
_add_pillar(Vector3(-3.5 if i % 2 == 0 else 3.5, 0, -float(i) * 3.4))
var camera: Camera3D = Camera3D.new()
camera.position = Vector3(0, 2.4, 6)
add_child(camera)
camera.look_at(Vector3(0, 1.6, -20), Vector3.UP)
camera.current = true
# the quad rides in front of the camera and covers the screen, which is how it reads the scene depth
var material: ShaderMaterial = ShaderMaterial.new()
material.shader = Get.shader('depth_fog')
var mesh: QuadMesh = QuadMesh.new()
mesh.size = Vector2(2, 2)
var screen: MeshInstance3D = MeshInstance3D.new()
screen.mesh = mesh
screen.material_override = material
screen.extra_cull_margin = 1e5
camera.add_child(screen)
screen.position = Vector3(0, 0, -0.5)
print('the fog reads DEPTH_TEXTURE, so it knows how far each pixel is')
func _add_pillar(at: Vector3) -> void:
var mesh: BoxMesh = BoxMesh.new()
mesh.size = Vector3(1.2, 3.6, 1.2)
var material: StandardMaterial3D = StandardMaterial3D.new()
material.albedo_color = Color('#8da5f3')
material.roughness = 0.5
var pillar: MeshInstance3D = MeshInstance3D.new()
pillar.mesh = mesh
pillar.material_override = material
pillar.position = at + Vector3(0, 1.8, 0)
add_child(pillar)
func _add_ground() -> void:
var mesh: PlaneMesh = PlaneMesh.new()
mesh.size = Vector2(60, 120)
var material: StandardMaterial3D = StandardMaterial3D.new()
material.albedo_color = Color('#2a2f3d')
material.roughness = 0.9
var ground: MeshInstance3D = MeshInstance3D.new()
ground.mesh = mesh
ground.material_override = material
ground.position = Vector3(0, 0, -30)
add_child(ground)
func _add_environment() -> void:
var env: Environment = Environment.new()
env.background_mode = Environment.BG_COLOR
env.background_color = Color(0.35, 0.42, 0.6)
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color(0.2, 0.24, 0.35)
env.ambient_light_energy = 1.0
var world: WorldEnvironment = WorldEnvironment.new()
world.environment = env
add_child(world)
func _add_light() -> void:
var light: DirectionalLight3D = DirectionalLight3D.new()
light.rotation_degrees = Vector3(-45, -30, 0)
light.light_energy = 1.1
add_child(light)shaders/depth_fog.gdshader
shader_type spatial;
render_mode unshaded, depth_test_disabled, cull_disabled;
uniform sampler2D screen_texture: hint_screen_texture, filter_linear;
uniform sampler2D depth_texture: hint_depth_texture;
uniform vec3 fog_color: source_color = vec3(0.35, 0.42, 0.6);
uniform float fog_start = 6.0;
uniform float fog_end = 34.0;
void vertex() {
POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}
void fragment() {
float raw = texture(depth_texture, SCREEN_UV).r;
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, raw);
vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
view.xyz /= view.w;
float distance_to_camera = -view.z;
float fog = clamp((distance_to_camera - fog_start) / (fog_end - fog_start), 0.0, 1.0);
ALBEDO = mix(texture(screen_texture, SCREEN_UV).rgb, fog_color, fog);
}