If you want the defaults to apply whether the parameters are passed by name or not, after you have initialized parameters from the values passed in to your sub you could simply say something like this (untested):
foreach my $k (keys %args) {
if (!defined($args{$k})) {
$args{$k} = $defaults->{$k};
}
}