HD smoke: young trails drawn at least as wide as a grid cell (density scaled to keep the mass), gentler bulges, so a trail is a smooth ribbon and not a chain of puffs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-30 03:44:45 +03:00
committed by airdef
parent 4a6ab8117a
commit 43392aec6b
2 changed files with 13 additions and 1 deletions
+12
View File
@@ -46,6 +46,8 @@ const MAX_INDICES: usize = 120_000;
pub const MAX_LIGHTS: usize = 16;
/// How fast the wind carries smoke (blocks per second, x and z).
const WIND: [f32; 2] = [1.6, 1.2];
/// The thinnest a trail is drawn, in blocks of radius (a cell is `CELL`).
const MIN_TUBE: f32 = 3.6;
/// Smoke is on unless `HORIZON_HD_SMOKE=0`.
pub fn smoke_enabled() -> bool {
@@ -402,6 +404,16 @@ fn bake(s: &HdSmoke) -> Option<Baked> {
// Spreading thins it (the core's mass over a wider tube), and it fades out towards its end.
let thin = (r0 / radius).powf(0.5);
let density = s.shape[2] * (1.0 - u).powi(2) * thin * (t / 0.25).min(1.0).max(0.2);
// A tube thinner than the grid's cells is sampled unevenly (cells near its axis get it, their
// neighbours miss it): a chain of blobs. Trails are kept at least a cell and a bit wide, with
// the same mass per length, so a young trail is a continuous ribbon.
let d = [s.b[0] - s.a[0], s.b[1] - s.a[1], s.b[2] - s.a[2]];
let tube = d[0] * d[0] + d[1] * d[1] + d[2] * d[2] > 0.25;
let (radius, density) = if tube && radius < MIN_TUBE {
(MIN_TUBE, density * radius / MIN_TUBE)
} else {
(radius, density)
};
let heat = s.shape[3] * (-t / 1.5).exp();
let clear_amount = (1.0 - u).powf(0.8);
let clear = s.motion[1] * (1.0 + 0.4 * u);
@@ -40,7 +40,7 @@ fn fs_smoke_grid(in: FullOut) -> @location(0) vec4<f32> {
let seed = segs[i + 3u].x;
let len = sqrt(len2);
// Bulges along the tube, so it is not a pipe.
let r = pa.w * (1.0 + 0.22 * sin(along * len * 0.6 + seed * 40.0));
let r = pa.w * (1.0 + 0.07 * sin(along * len * 0.35 + seed * 40.0));
if d < r && pb.w > 0.0 {
let q = d / r;
var w = (1.0 - q * q);