Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions native/shared/shaders/impulse_field.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
// `info` — world bounds, decay factor, queued splats.
// Output: `dst` — this frame's field.
//
// Per texel: value = previous * decay + sum(splat strength × 1-d/r).
// Per texel: value = min(previous * decay + sum(splat strength × (1-d/r)²), 1).
// The clamp keeps repeated splats at the same spot (a player wading
// through water submits one every few frames) from accumulating far
// past 1.0 — an unclamped field takes seconds of decay to drop back
// under 1.0, which reads as a stuck full-strength splat.

struct Splat {
pos: vec2<f32>, // world xz
Expand Down Expand Up @@ -49,5 +53,5 @@ fn cs_main(@builtin(global_invocation_id) gid: vec3<u32>) {
}
}

textureStore(dst, vec2<i32>(gid.xy), vec4<f32>(value, 0.0, 0.0, 0.0));
textureStore(dst, vec2<i32>(gid.xy), vec4<f32>(min(value, 1.0), 0.0, 0.0, 0.0));
}
34 changes: 29 additions & 5 deletions native/shared/src/ffi_core/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,15 @@ macro_rules! __bloom_ffi_models {
if eng.renderer.cache_model_if_static(handle_bits, &model.meshes) {
eng.renderer.draw_model_cached(handle_bits, position, scale as f32, tint);
} else {
// Skinned model (uncacheable): ONE staged pose per
// drawModel call, shared by every primitive. Letting
// each primitive pop its own pose starved the second
// primitive of multi-primitive models onto joint
// offset 0 — another model's matrices.
let joint_offset = eng.renderer.take_staged_skin_offset();
for mesh in &model.meshes {
let tex_idx = mesh.texture_idx.unwrap_or(0);
eng.renderer.draw_model_mesh_tinted(&mesh.vertices, &mesh.indices, position, scale as f32, tint, tex_idx);
eng.renderer.draw_model_mesh_tinted_with_joints(&mesh.vertices, &mesh.indices, position, scale as f32, tint, tex_idx, joint_offset);
}
}
}
Expand Down Expand Up @@ -80,11 +86,29 @@ macro_rules! __bloom_ffi_models {
let position = [x as f32, y as f32, z as f32];
let scale = scale as f32;
let tint = [r, g, b, a];
for mesh in &model.meshes {
let tex_idx = mesh.texture_idx.unwrap_or(0);
eng.renderer.draw_model_mesh_tinted_rotated(
&mesh.vertices, &mesh.indices, position, scale, tint, tex_idx, rot_y as f32,
let handle_bits = handle.to_bits();
// Static models go through the cached scene pipeline
// (alpha cutout, normal/MR maps, foliage wind +
// transmission, cutout shadows, planar reflections) —
// the immediate path below has none of that and used
// to render cutout foliage as opaque cards. Skinned
// models stay on the immediate fallback, matching
// bloom_draw_model.
if eng.renderer.cache_model_if_static(handle_bits, &model.meshes) {
eng.renderer.draw_model_cached_rotated(
handle_bits, position, scale, rot_y as f32, tint,
);
} else {
// Same one-pose-per-model rule as bloom_draw_model
// (see there) — primitives of a skinned model share
// the staged pose.
let joint_offset = eng.renderer.take_staged_skin_offset();
for mesh in &model.meshes {
let tex_idx = mesh.texture_idx.unwrap_or(0);
eng.renderer.draw_model_mesh_tinted_rotated_with_joints(
&mesh.vertices, &mesh.indices, position, scale, tint, tex_idx, rot_y as f32, joint_offset,
);
}
}
}
})
Expand Down
13 changes: 13 additions & 0 deletions native/shared/src/renderer/material_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,19 @@ impl MaterialSystem {
Some(Some(m)) => m,
_ => continue,
};
// Probe passes (use_reflection_pipeline) present the
// 4-attachment opaque G-buffer layout. Translucent-
// profile pipelines are single-target — binding one
// there is a wgpu validation panic — and reads_scene
// materials expect a group-4 bind the probe pass never
// provides. Skip both; `last_material` stays latched on
// the previously bound material, which is correct
// because no pipeline/bind state changes here.
if use_reflection_pipeline
&& (matches!(mat.profile, FragmentProfile::Translucent) || mat.reads_scene)
{
continue;
}
let pipeline = if use_reflection_pipeline {
mat.reflection_pipeline.as_ref().unwrap_or(&mat.pipeline)
} else {
Expand Down
Loading
Loading