Grade infinita

Um plano e nenhuma textura. O fwidth mantém cada linha com um pixel de largura, não importa a distância da câmera.

O editor acima está rodando este projeto. Mude uma linha e ele recarrega.

Classes do Godot usadas

PlaneMeshShaderMaterialCamera3D

O código

scripts/main.gd
extends Node

var camera: Camera3D
var elapsed: float = 0.0


func _ready() -> void:
	_add_environment()
	_add_light()

	var mesh: PlaneMesh = PlaneMesh.new()
	mesh.size = Vector2(120, 120)

	var material: ShaderMaterial = ShaderMaterial.new()
	material.shader = Get.shader('grid')

	var floor_plane: MeshInstance3D = MeshInstance3D.new()
	floor_plane.mesh = mesh
	floor_plane.material_override = material
	add_child(floor_plane)

	for i in 5:
		_add_marker(Vector3(cos(i * 1.25) * 6.0, 0.6, sin(i * 1.25) * 6.0), float(i) / 5.0)

	camera = Camera3D.new()
	camera.position = Vector3(0, 3.4, 10)
	add_child(camera)
	camera.look_at(Vector3(0, 0.5, 0), Vector3.UP)
	camera.current = true

	print('one plane, no texture: fwidth keeps the line one pixel wide at any distance')


func _process(delta: float) -> void:
	elapsed += delta
	camera.position = Vector3(sin(elapsed * 0.2) * 10.0, 3.4, cos(elapsed * 0.2) * 10.0)
	camera.look_at(Vector3(0, 0.5, 0), Vector3.UP)


func _add_marker(at: Vector3, hue: float) -> void:
	var mesh: BoxMesh = BoxMesh.new()
	mesh.size = Vector3(1.2, 1.2, 1.2)

	var material: StandardMaterial3D = StandardMaterial3D.new()
	material.albedo_color = Color.from_hsv(hue, 0.5, 0.95)
	material.roughness = 0.4

	var marker: MeshInstance3D = MeshInstance3D.new()
	marker.mesh = mesh
	marker.material_override = material
	marker.position = at
	add_child(marker)


func _add_environment() -> void:
	var env: Environment = Environment.new()
	env.background_mode = Environment.BG_COLOR
	env.background_color = Color(0.02, 0.02, 0.04)
	env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
	env.ambient_light_color = Color(0.12, 0.14, 0.2)
	env.ambient_light_energy = 1.0
	env.glow_enabled = true

	var world: WorldEnvironment = WorldEnvironment.new()
	world.environment = env
	add_child(world)


func _add_light() -> void:
	var light: DirectionalLight3D = DirectionalLight3D.new()
	light.rotation_degrees = Vector3(-55, -30, 0)
	light.light_energy = 1.0
	add_child(light)
shaders/grid.gdshader
shader_type spatial;
render_mode cull_disabled;

uniform vec3 line_color: source_color = vec3(0.55, 0.65, 0.95);
uniform vec3 floor_color: source_color = vec3(0.04, 0.05, 0.08);
uniform float cell_size = 1.0;
uniform float line_width = 1.4;
uniform float fade_distance = 40.0;

varying vec3 world_position;

float grid_line(vec2 position, float size) {
	vec2 cell = abs(fract(position / size - 0.5) - 0.5) / fwidth(position / size);
	return 1.0 - min(min(cell.x, cell.y) / line_width, 1.0);
}

void vertex() {
	world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}

void fragment() {
	float thin = grid_line(world_position.xz, cell_size);
	float thick = grid_line(world_position.xz, cell_size * 10.0);

	float distance_fade = 1.0 - clamp(length(world_position.xz) / fade_distance, 0.0, 1.0);
	float line = max(thin * 0.35, thick) * distance_fade;

	ALBEDO = mix(floor_color, line_color, line);
	EMISSION = line_color * line * 0.6;
	ROUGHNESS = 0.9;
}

Mais exemplos de Shaders