Dissolution
Une texture de bruit générée en GDScript et un discard dans le shader, avec un bord incandescent au seuil.
L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.
Classes Godot utilisées
MeshInstance3DNoiseTexture2DFastNoiseLite
Le code
scripts/main.gd
extends Node
var shapes: Node3D
func _ready() -> void:
_add_environment()
_add_light()
var material: ShaderMaterial = ShaderMaterial.new()
material.shader = Get.shader('dissolve')
material.set_shader_parameter('noise_texture', _make_noise())
shapes = Node3D.new()
add_child(shapes)
var meshes: Array[Mesh] = [SphereMesh.new(), BoxMesh.new(), TorusMesh.new()]
for i in meshes.size():
var item: MeshInstance3D = MeshInstance3D.new()
item.mesh = meshes[i]
item.material_override = material
item.position = Vector3((i - 1) * 1.9, 0, 0)
shapes.add_child(item)
var camera: Camera3D = Camera3D.new()
camera.position = Vector3(0, 1.1, 4.6)
add_child(camera)
camera.look_at(Vector3.ZERO, Vector3.UP)
camera.current = true
print('the noise texture comes from GDScript, the discard happens in the shader')
func _process(delta: float) -> void:
for shape in shapes.get_children():
shape.rotate_y(delta * 0.6)
func _make_noise() -> NoiseTexture2D:
var noise: FastNoiseLite = FastNoiseLite.new()
noise.noise_type = FastNoiseLite.TYPE_SIMPLEX
# a high frequency shreds the mesh into dust and the burning edge goes with it
noise.frequency = 0.012
var texture: NoiseTexture2D = NoiseTexture2D.new()
texture.noise = noise
texture.seamless = true
texture.width = 256
texture.height = 256
return texture
func _add_environment() -> void:
var sky_material: ProceduralSkyMaterial = ProceduralSkyMaterial.new()
sky_material.sky_top_color = Color(0.04, 0.05, 0.1)
sky_material.sky_horizon_color = Color(0.12, 0.14, 0.22)
sky_material.ground_bottom_color = Color(0.02, 0.02, 0.04)
sky_material.ground_horizon_color = Color(0.09, 0.1, 0.15)
var sky: Sky = Sky.new()
sky.sky_material = sky_material
var env: Environment = Environment.new()
env.background_mode = Environment.BG_SKY
env.sky = sky
env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
env.ambient_light_energy = 0.7
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(-45, -35, 0)
light.light_energy = 1.8
add_child(light)shaders/dissolve.gdshader
shader_type spatial;
render_mode cull_disabled;
uniform sampler2D noise_texture;
uniform vec3 base_color: source_color = vec3(0.12, 0.32, 0.75);
uniform vec3 edge_color: source_color = vec3(1.0, 0.5, 0.1);
uniform float edge_width = 0.07;
uniform float speed = 0.35;
void fragment() {
float n = texture(noise_texture, UV).r;
// the range stops at 0.72, at 1.0 the whole mesh is gone and the scene is empty
float threshold = mix(0.05, 0.72, abs(sin(TIME * speed)));
if (n < threshold) {
discard;
}
float edge = 1.0 - smoothstep(threshold, threshold + edge_width, n);
ALBEDO = base_color;
ROUGHNESS = 0.4;
EMISSION = edge_color * edge * 4.0;
}