From a performance point-of-view, writing the code directly against the tables is usually the better choice.
As for involving function, it depends on what sort of function we are talking about. If it is an inline table-function, this is essentially a parameterised view, and as such it does cause any overhead, since a view/inline table function is just a macro that is pasted into the query, and the optimizer works with the expanded query text. There is a caveat though: It could be that the view involves more tables needed for the operation, or that you need a column from one of the tables that is not exposed in the view. This may lead to that you join in the table explicitly, and now there is overhead.
For multi-statement table function and scalar functions, they typically always add overhead, since the function is an execution on its own, and a scalar function is typically executed row-by-row. True, since SQL 2019, scalar functions may be inlined, but there are many cases where this does not happen, so it is nothing you can assume.