Bevy-Rust-GPU / rust-gpu-sdf

Signed distance field library usable on both CPU and GPU.
Apache License 2.0
12 stars 1 forks source link

Non-distance attribute pipeline #9

Closed Shfty closed 1 year ago

Shfty commented 1 year ago

Normals are supported by the SignedDistanceField trait and have some local impls, as well as the normal approximation adapters, but these are currently inaccessible in practical terms since none of the other operators or adapters implement any attribute other than distance.

Need to create passthrough impls for all related types - Operator, adapters, etc.

Worth ruminating on how this might be extended, since it will require one explicit impl for each SignedDistanceField implementor for each attribute type - seems like a lot of work for users to extend.

Shfty commented 1 year ago

Generalizing operators over distance function I/O seems to be the most immediate solution, implementing new rust-gpu-bridge traits as needed to cover the various shading lang functions.

Longer-term, a way to split blanket impls out from specific impls is probably wise - i.e. an extra marker type param that can be generalized over in a consuming trait.

Shfty commented 1 year ago

The blanket / specific approach didn't work out, as the result would require the user to know blanket / specific impl details while specifying their SDF type in order to write the correct marker parameter.

However, this is progressing - field functions and operators are now standardized around implementing position / normal / uv, with tangent and color as wrapper-derived attributes.

In addition, support function (i.e. vector to nearest surface) has been added as a free-standing wrapper-first attribute. This fits nicely as a reference implementation for third-party attributes, since avoiding manual impl_passthrough_op! across the entire existing set is preferable.

The next step is to try and figure out a cons-based approach to evaluating several attributes from one function call, i.e.

let (normal, tangent, uv, color) = sdf.evaluate(
    (
        Normal<Vec3>::default(),
        Tangent<Vec3>::default(),
        Uv,
        Color
    ),
    pos
);

Where the Attr parameter is a type that implements Cons, which produces an Attribute type that also implements Uncons for automatic denesting before return.

However, a prior attempt at this was unsuccesful due to blanket impl conflicts. Will need to revisit, and possibly devise a solution around re-encoding Operator via cons cell (i.e. <(OpType, SdfType) as Operator>).

Shfty commented 1 year ago

The free-standing attribute approach may be viable for cons evaulation.

Shfty commented 1 year ago

This is now functional by way of a blanket cons implementation over FieldFunction. However, this comes at the cost of Operator extensibility; each of its impls are now manual over a concrete attribute type, which may prevent downstream crates from doing the same for a custom attribute.

As with FieldCons, the elegant way to solve this seems to be the introduction of extension traits; implementing FieldFunction as before (i.e. with no cons ability) and creating an extension trait to cover the cons list impl in a separate method.

Shfty commented 1 year ago

Should also be able to use an indirection trait to reflect evaluate<T>() / evaluate_cons<T>() onto FieldFunction types, allowing the attribute generic to be specified in the function position and removing the need for a concrete attribute parameter.

Shfty commented 1 year ago

Done; the trait machinery has been split into single and plural variants, with an extra layer of API traits to move the Attr generic into function position.