mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-14 03:42:05 +00:00
feat: lit particle shader for nebula dust weather effect
Replace NebulaDust's flat unshaded glow material with a custom ShaderMaterial: a fake per-pixel puff normal on the billboarded quad feeds a light() override so motes catch the directional light and a nebula-core color bias, alpha gets a depth-texture soft-particle fade so motes no longer hard-clip through boundary/decoration geometry, and a per-particle hash adds subtle sparkle.
This commit is contained in:
+10
-12
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=15 format=3]
|
||||
[gd_scene load_steps=16 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/arena.gd" id="1_iywne"]
|
||||
[ext_resource type="PackedScene" path="res://objects/arena_boundary.tscn" id="2_bndry"]
|
||||
@@ -8,6 +8,7 @@
|
||||
[ext_resource type="PackedScene" path="res://assets/models/nebula_debris.glb" id="9_debris"]
|
||||
[ext_resource type="Texture2D" path="res://assets/textures/particle_glow.png" id="10_dust"]
|
||||
[ext_resource type="PackedScene" path="res://assets/models/nebula_planet.glb" id="11_planet"]
|
||||
[ext_resource type="Shader" path="res://shaders/nebula_dust.gdshader" id="12_dust_shader"]
|
||||
|
||||
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_nebula"]
|
||||
panorama = ExtResource("7_nebula")
|
||||
@@ -39,19 +40,16 @@ adjustment_brightness = 1.0
|
||||
adjustment_contrast = 1.05
|
||||
adjustment_saturation = 1.08
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dust"]
|
||||
transparency = 1
|
||||
shading_mode = 0
|
||||
billboard_mode = 1
|
||||
vertex_color_use_as_albedo = true
|
||||
albedo_color = Color(1, 0.75, 0.9, 1)
|
||||
albedo_texture = ExtResource("10_dust")
|
||||
emission_enabled = true
|
||||
emission = Color(1, 0.6, 0.85, 1)
|
||||
emission_energy_multiplier = 2.5
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_dust"]
|
||||
shader = ExtResource("12_dust_shader")
|
||||
shader_parameter/albedo_tex = ExtResource("10_dust")
|
||||
shader_parameter/core_bias_color = Color(1, 0.6, 0.85, 1)
|
||||
shader_parameter/core_bias_amount = 0.35
|
||||
shader_parameter/emission_strength = 2.5
|
||||
shader_parameter/soft_fade_distance = 1.0
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_dust"]
|
||||
material = SubResource("StandardMaterial3D_dust")
|
||||
material = SubResource("ShaderMaterial_dust")
|
||||
size = Vector2(0.4, 0.4)
|
||||
|
||||
[sub_resource type="Gradient" id="Gradient_dust"]
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
shader_type spatial;
|
||||
render_mode blend_mix, depth_draw_never, cull_disabled, specular_disabled;
|
||||
|
||||
uniform sampler2D albedo_tex : source_color;
|
||||
uniform sampler2D depth_tex : hint_depth_texture, filter_linear_mipmap;
|
||||
uniform vec3 core_bias_color : source_color = vec3(1.0, 0.6, 0.85);
|
||||
uniform float core_bias_amount : hint_range(0.0, 1.0) = 0.35;
|
||||
uniform float emission_strength : hint_range(0.0, 5.0) = 2.5;
|
||||
uniform float soft_fade_distance : hint_range(0.0, 5.0) = 1.0;
|
||||
|
||||
varying float v_flicker;
|
||||
|
||||
void vertex() {
|
||||
// true billboard: strip rotation from the per-instance modelview, keep translation + scale
|
||||
mat4 mv = MODELVIEW_MATRIX;
|
||||
mv[0].xyz = vec3(length(mv[0].xyz), 0.0, 0.0);
|
||||
mv[1].xyz = vec3(0.0, length(mv[1].xyz), 0.0);
|
||||
mv[2].xyz = vec3(0.0, 0.0, length(mv[2].xyz));
|
||||
VERTEX = (mv * vec4(VERTEX, 1.0)).xyz;
|
||||
|
||||
// INSTANCE_CUSTOM.x is GPUParticles3D's per-particle random seed, baked at spawn
|
||||
float seed = INSTANCE_CUSTOM.x;
|
||||
float flicker_hash = fract(sin((seed + floor(TIME * 6.0)) * 127.1) * 43758.5453);
|
||||
v_flicker = 0.85 + 0.15 * flicker_hash;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
// fake a puff/sphere normal from local UV so a camera-facing billboard can still catch directional light;
|
||||
// the quad is billboarded to face the camera in vertex(), so this normal is already view-space aligned
|
||||
vec2 centered = UV * 2.0 - 1.0;
|
||||
float r2 = dot(centered, centered);
|
||||
float mask = clamp(1.0 - r2, 0.0, 1.0);
|
||||
NORMAL = normalize(vec3(centered, sqrt(max(mask, 0.001))));
|
||||
|
||||
vec4 tex = texture(albedo_tex, UV);
|
||||
ALBEDO = tex.rgb * mix(vec3(1.0), core_bias_color, core_bias_amount);
|
||||
EMISSION = core_bias_color * tex.rgb * emission_strength * 0.15;
|
||||
ALPHA = tex.a * COLOR.a * mask;
|
||||
|
||||
float raw_depth = texture(depth_tex, SCREEN_UV).r;
|
||||
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, raw_depth);
|
||||
vec4 view_pos = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
|
||||
view_pos.xyz /= view_pos.w;
|
||||
float scene_depth = -view_pos.z;
|
||||
float particle_depth = -VERTEX.z;
|
||||
ALPHA *= clamp((scene_depth - particle_depth) / soft_fade_distance, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void light() {
|
||||
float ndotl = clamp(dot(NORMAL, LIGHT), 0.0, 1.0);
|
||||
DIFFUSE_LIGHT += LIGHT_COLOR * ndotl * ALBEDO * emission_strength * v_flicker * ATTENUATION;
|
||||
}
|
||||
Reference in New Issue
Block a user