bevy_mod_raycast icon indicating copy to clipboard operation
bevy_mod_raycast copied to clipboard

Make `DefaultRaycastPlugin` respect the material `cull_mode`

Open thmxv opened this issue 1 year ago • 1 comments

It would be nice if a hit was detected on all visible faces. For the moment object with a material with a cull_mode of None (no backface culling) are not hit.

thmxv avatar Mar 11 '24 21:03 thmxv

I think I found a way to make this in the application using bevy and the raycast add-on. I am not sure if this is totally correct or if it is worth including the code in this add-on to avoid users wanting the same functionality the work I have done. But here is my code:

fn make_raycast_nobfc_respect_material(
    commands: &mut Commands,
    entity: Entity,
    entity_has_raycast_nobfc_component: bool,
    material_cull_mode: Option<Face>,
) {
    match material_cull_mode {
        None | Some(Face::Front) => {
            if !entity_has_raycast_nobfc_component {
                commands.entity(entity).insert(NoBackfaceCulling);
            }
        }
        Some(Face::Back) => {
            if entity_has_raycast_nobfc_component {
                commands.entity(entity).remove::<NoBackfaceCulling>();
            }
        }
    }
}

pub fn change_entity_raycast_backface_culling_system(
    mut commands: Commands,
    entities: Query<
        (
            Entity,
            &Handle<StandardMaterial>,
            Option<&NoBackfaceCulling>,
        ),
        Changed<Handle<StandardMaterial>>,
    >,
    materials: Res<Assets<StandardMaterial>>,
) {
    for (entity, material_handle, nobfc_opt) in entities.iter() {
        let material_cull_mode =
            materials.get(material_handle).unwrap().cull_mode;
        make_raycast_nobfc_respect_material(
            &mut commands,
            entity,
            nobfc_opt.is_some(),
            material_cull_mode,
        );
    }
}

pub fn change_asset_raycast_backface_cullin_system(
    mut commands: Commands,
    entities: Query<
        (
            Entity,
            &Handle<StandardMaterial>,
            Option<&NoBackfaceCulling>,
        ),
        With<Handle<StandardMaterial>>,
    >,
    mut ev_asset: EventReader<AssetEvent<StandardMaterial>>,
    materials: Res<Assets<StandardMaterial>>,
) {
    for ev in ev_asset.read() {
        match ev {
            AssetEvent::Modified { id } => {
                let material_cull_mode = materials.get(*id).unwrap().cull_mode;
                for (entity, material_handle, nobfc_opt) in entities.iter() {
                    if *id == material_handle.id() {
                        make_raycast_nobfc_respect_material(
                            &mut commands,
                            entity,
                            nobfc_opt.is_some(),
                            material_cull_mode,
                        );
                    }
                }
            }
            _ => {}
        }
    }
}

thmxv avatar Mar 31 '24 17:03 thmxv