mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-02 22:42:24 -06:00
Merge pull request #1704
This commit is contained in:
@@ -320,7 +320,12 @@ fn pack(s: &Scene) -> [Vec<u8>; 7] {
|
||||
let lit = !(s.lights.is_empty() && s.env.is_none() && s.ambient == [0.0; 3]);
|
||||
globals.extend([e.rotation, lit as u32 as f32, 0.0, 0.0]);
|
||||
let mats = s.materials.iter().flat_map(|m| {
|
||||
let flags = (m.double_sided as u32) | (m.unlit as u32) << 1 | (m.accepts_lights as u32) << 2 | (m.receives_shadows as u32) << 3 | (m.alpha_mode << 8);
|
||||
let flags = (m.double_sided as u32)
|
||||
| (m.unlit as u32) << 1
|
||||
| (m.accepts_lights as u32) << 2
|
||||
| (m.receives_shadows as u32) << 3
|
||||
| (m.shadows_only as u32) << 4
|
||||
| (m.alpha_mode << 8);
|
||||
[
|
||||
m.base[0],
|
||||
m.base[1],
|
||||
|
||||
@@ -288,6 +288,53 @@ struct FOut {
|
||||
@location(1) depth: u32,
|
||||
};
|
||||
|
||||
// shade::to_light: unit direction to the light (xyz) and its distance (w).
|
||||
fn to_light(kind: u32, lpos: vec3<f32>, ldir: vec3<f32>, pos: vec3<f32>) -> vec4<f32> {
|
||||
if (kind == 0u) {
|
||||
return vec4<f32>(-ldir, 1e30);
|
||||
}
|
||||
let d = lpos - pos;
|
||||
let len = sqrt(dot(d, d));
|
||||
if (len < 1e-6) {
|
||||
return vec4<f32>(0.0, 0.0, -1.0, 0.0);
|
||||
}
|
||||
return vec4<f32>(d / len, len);
|
||||
}
|
||||
|
||||
// shade::shadow_only: the strongest shadow any light casts on the fragment.
|
||||
fn shadow_only_amount(unlit: bool, normal: vec3<f32>, front: bool, pos: vec3<f32>) -> f32 {
|
||||
var amount = 0.0;
|
||||
if (unlit) {
|
||||
return amount;
|
||||
}
|
||||
var n = norm3(normal);
|
||||
if (!front) {
|
||||
n = -n;
|
||||
}
|
||||
let nl_count = u32(g.fwd.w);
|
||||
for (var li = 0u; li < nl_count; li = li + 1u) {
|
||||
let lb = li * LIGHT_STRIDE;
|
||||
let l0 = lights[lb];
|
||||
let l1 = lights[lb + 1u];
|
||||
let l2 = lights[lb + 2u];
|
||||
let l3 = lights[lb + 3u];
|
||||
let l4 = lights[lb + 4u];
|
||||
let kind = u32(l0.w);
|
||||
let tl = to_light(kind, l0.xyz, l1.xyz, pos);
|
||||
let to_l = tl.xyz;
|
||||
let dist = tl.w;
|
||||
if (attenuation(kind, u32(l3.x), l3.y, l3.z, l2.w, l1.w, l1.xyz, to_l, dist) <= 0.0) {
|
||||
continue;
|
||||
}
|
||||
let n_l = dot(n, to_l);
|
||||
if (n_l <= 0.0) {
|
||||
continue;
|
||||
}
|
||||
amount = max(amount, 1.0 - light_shadow(li, kind, l0.xyz, i32(l3.w), l4.x, pos, n_l));
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs(i: VOut, @builtin(front_facing) front: bool) -> FOut {
|
||||
let mb = i.material * MAT_STRIDE;
|
||||
@@ -302,6 +349,7 @@ fn fs(i: VOut, @builtin(front_facing) front: bool) -> FOut {
|
||||
let unlit = (flags & 2u) != 0u;
|
||||
let accepts_lights = (flags & 4u) != 0u;
|
||||
let receives_shadows = (flags & 8u) != 0u;
|
||||
let shadows_only = (flags & 16u) != 0u;
|
||||
let alpha_mode = (flags >> 8u) & 3u;
|
||||
if (!front && !double_sided) {
|
||||
discard;
|
||||
@@ -330,6 +378,10 @@ fn fs(i: VOut, @builtin(front_facing) front: bool) -> FOut {
|
||||
}
|
||||
var out: FOut;
|
||||
out.depth = bitcast<u32>(dot(g.view_z.xyz, i.pos) + g.view_z.w);
|
||||
if (shadows_only) {
|
||||
out.color = vec4<f32>(0.0, 0.0, 0.0, alpha * shadow_only_amount(unlit || !accepts_lights, i.normal, front, i.pos));
|
||||
return out;
|
||||
}
|
||||
if (unlit || !accepts_lights || g.env2.y < 0.5) {
|
||||
let c = rgb + emissive;
|
||||
out.color = vec4<f32>(c * alpha, alpha);
|
||||
@@ -381,22 +433,9 @@ fn fs(i: VOut, @builtin(front_facing) front: bool) -> FOut {
|
||||
let l3 = lights[lb + 3u];
|
||||
let l4 = lights[lb + 4u];
|
||||
let kind = u32(l0.w);
|
||||
var to_l: vec3<f32>;
|
||||
var dist: f32;
|
||||
if (kind == 0u) {
|
||||
to_l = -l1.xyz;
|
||||
dist = 1e30;
|
||||
} else {
|
||||
let d = l0.xyz - i.pos;
|
||||
let len = sqrt(dot(d, d));
|
||||
if (len < 1e-6) {
|
||||
to_l = vec3<f32>(0.0, 0.0, -1.0);
|
||||
dist = 0.0;
|
||||
} else {
|
||||
to_l = d / len;
|
||||
dist = len;
|
||||
}
|
||||
}
|
||||
let tl = to_light(kind, l0.xyz, l1.xyz, i.pos);
|
||||
let to_l = tl.xyz;
|
||||
let dist = tl.w;
|
||||
let k = attenuation(kind, u32(l3.x), l3.y, l3.z, l2.w, l1.w, l1.xyz, to_l, dist);
|
||||
if (k <= 0.0) {
|
||||
continue;
|
||||
|
||||
@@ -155,6 +155,18 @@ fn gpu_matches_cpu_unlit_and_full_frames() {
|
||||
assert!((diff as f64) < 0.02 * cpu.data.len() as f64, "{diff} pixels differ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gpu_matches_cpu_shadow_catcher() {
|
||||
// #1691: the floor plane as a shadow catcher ("Accepts Shadows: Only").
|
||||
let Some(g) = gpu() else { return };
|
||||
let (mut p, cid) = scene_project();
|
||||
let floor = p.comp_mut(cid).unwrap().layers.last_mut().unwrap();
|
||||
set(floor, "materialOptions/acceptsShadows", Value::Enum(2));
|
||||
let s = scene(&p, cid);
|
||||
assert!(s.materials.iter().any(|m| m.shadows_only) && !s.shadows.is_empty());
|
||||
compare(&s, &g);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gpu_raster_perf_smoke() {
|
||||
let Some(g) = gpu() else { return };
|
||||
|
||||
Reference in New Issue
Block a user