ambient_decals 0.2.1

Ambient decals. Host-only.
Documentation

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0) texcoord: vec2<f32>,
    @location(1) world_position: vec4<f32>,
    @location(2) @interpolate(flat) instance_index: u32,
    @location(3) inv_local_to_world_0: vec4<f32>,
    @location(4) inv_local_to_world_1: vec4<f32>,
    @location(5) inv_local_to_world_2: vec4<f32>,
    @location(6) inv_local_to_world_3: vec4<f32>,
};

fn get_entity_primitive_mesh(loc: vec2<u32>, index: u32) -> u32 {
    let i = index >> 2u;
    let j = index & 3u;

    var meshes = get_entity_gpu_primitives_mesh(loc);
    return bitcast<u32>(meshes[i][j]);
}

@vertex
fn vs_main(@builtin(instance_index) instance_index: u32, @builtin(vertex_index) vertex_index: u32) -> VertexOutput {
    var out: VertexOutput;

    let primitive = primitives.data[instance_index];
    let entity_loc = primitive.xy;
    var mesh_index = get_entity_primitive_mesh(entity_loc, primitive.z);

    let mesh = get_mesh_base(mesh_index, vertex_index);

    out.instance_index = instance_index;
    out.texcoord = mesh.texcoord0;

    let local_to_world = get_entity_mesh_to_world(entity_loc);

    out.world_position = local_to_world * vec4<f32>(mesh.position, 1.);
    let vertex_transformed = global_params.projection_view * out.world_position;

    out.position = vertex_transformed;

    let inv_local_to_world = inverse(local_to_world);
    out.inv_local_to_world_0 = inv_local_to_world[0];
    out.inv_local_to_world_1 = inv_local_to_world[1];
    out.inv_local_to_world_2 = inv_local_to_world[2];
    out.inv_local_to_world_3 = inv_local_to_world[3];

    return out;
}

struct Decal {
    depth: f32,
    material_in: MaterialInput
}

fn get_decal(in: VertexOutput) -> Decal {
    let screen_size = vec2<f32>(textureDimensions(solids_screen_depth));
    let screen_tc = screen_pixel_to_uv(in.position.xy, screen_size);
    let screen_ndc = screen_uv_to_ndc(screen_tc);
    let screen_depth = get_solids_screen_depth(screen_ndc);
    var res: Decal;
    res.depth = screen_depth;
    let world_position = project_point(global_params.inv_projection_view, vec3<f32>(screen_ndc.x, screen_ndc.y, screen_depth));

    let inv_local_to_world = mat4x4<f32>(
        in.inv_local_to_world_0,
        in.inv_local_to_world_1,
        in.inv_local_to_world_2,
        in.inv_local_to_world_3,
    );
    let local_pos = project_point(inv_local_to_world, world_position);
    if local_pos.x < -0.5 || local_pos.x > 0.5 || local_pos.y < -0.5 || local_pos.y > 0.5 {
        discard;
    }

    var material_in: MaterialInput;
    material_in.position = in.position;
    // Note: Decals assume we're using a unit cube
    material_in.texcoord.y = (0.5 - local_pos.x);
    material_in.texcoord.x = (local_pos.y - 0.5);
    material_in.world_position = world_position;
    let screen_normal_mat = mat3_from_quat(get_solids_screen_normal_quat(screen_ndc));
    material_in.normal = screen_normal_mat * vec3<f32>(0., 0., 1.);
    material_in.normal_matrix = screen_normal_mat;
    material_in.instance_index = in.instance_index;
    res.material_in = material_in;

    return res;
}

@fragment
fn fs_shadow_main(in: VertexOutput, @builtin(front_facing) is_front: bool) -> @builtin(frag_depth) f32 {
    let decal = get_decal(in);
    var material = get_material(decal.material_in);

    if material.opacity < material.alpha_cutoff {
        discard;
    }
    return decal.depth;
}

fn get_outline(instance_index: u32) -> vec4<f32> {
    let entity_loc = primitives.data[instance_index].xy;
    return get_entity_outline_or(entity_loc, vec4<f32>(0., 0., 0., 0.));
}

struct FsOutputs {
  @builtin(frag_depth) depth: f32,
  @location(0) color: vec4<f32>
}

@fragment
fn fs_forward_lit_main(in: VertexOutput, @builtin(front_facing) is_front: bool) -> FsOutputs {
    let decal = get_decal(in);
    var material = get_material(decal.material_in);

    if material.opacity < material.alpha_cutoff {
        discard;
    }
    var res: FsOutputs;
    res.color = shading(material, vec4<f32>(decal.material_in.world_position, 1.));
    res.depth = decal.depth + 0.0001;
    return res;
}

@fragment
fn fs_forward_unlit_main(in: VertexOutput, @builtin(front_facing) is_front: bool) -> FsOutputs {
    let decal = get_decal(in);
    var material = get_material(decal.material_in);

    if material.opacity < material.alpha_cutoff {
        discard;
    }
    var res: FsOutputs;
    res.color = vec4<f32>(material.base_color, material.opacity);
    res.depth = decal.depth + 0.0001;
    return res;
}

@fragment
fn fs_outlines_main(in: VertexOutput, @builtin(front_facing) is_front: bool) -> @location(0) vec4<f32> {
    let decal = get_decal(in);
    var material = get_material(decal.material_in);

    if material.opacity < material.alpha_cutoff {
        discard;
    }
    return get_outline(in.instance_index);
}