# Surface Attachment Attributes In many contexts curves are attached to a surface. This attachment is used to propagate data from the surface to the curves and to deform curves when the surface is deformed. It's important that the attachment information can also handle procedural topology changes on the surface (like using a subdivision surface modifier). ## Attachment We decided to use a uv map to store a reference to a point on a mesh surface. Using a uv map works well because: * Many mesh editing operations, even ones that change topology, keep uv maps intact. * UV maps are a concept that is well known to users and thus no new concept has to be learned. * UV maps can be generated, accessed and modified using geometry nodes. * UV maps exist on surface usually anyway, so there is no extra cost on propagating it for other usages. The main downsides to using uv maps are: * A uv coordinate can correspond to an arbitrary number points on a surface. In practice for our use case we need a uv islands shouldn't overlap for predictable results. * Doing a reverse lookup from uv coordinates to positions on a mesh comes at a cost. However, it is a problem that can be optimized well in isolation. Furthermore, the lookup results are relatively straight forward to cache over time (given a good caching framework). Just storing a uv coordinate for every curve is not enough to be able to deform curves when the surface was deformed though. It would only be enough when two conditions are true. The root point of the curve has to start exactly on the surface and the surface deformation must only imply a translation (no rotation). For the hair use case, the first condition is usually true. However, the second condition rarely is. ## Deformation Correct deformation we have to know the original and deformed position as well as the original and deformed orientation of the surface. In the remaining document "transform" will refer to the combination of position and orientation. The deformed transform can be computed based on the deformed mesh and a uv coordinate already. Information about the original transform has to come from somewhere else. There seem to be two main approaches, which are different in what geometry the data is stored on: 1. The original position and orientation of the surface is stored on each curve. 2. The original position of each vertex is stored on the surface. Both approaches have their reasons for existence. The rest of this document will compare both approaches. It should be noted that long term this doesn't have to be a either-or situation. However, we have to pick one approach now so that we can build the tooling for it. ### Memory Usage It's difficult to compare the memory usage, because it depends on the number of curves compares to the number of vertices on the evaluated surface. The first approach needs 7 floats per curve (3 for the position and 4 for a rotation encoded as a quaternion). The second approach needs 3 floats per evaluated vertex. ### Propagation Cost There is little to no propagation cost for storing the transform on each curve. That's because this data generally doesn't have to be touched until the final deformation comes. Contrary to that, there is a fairly high cost to propagating a original position (`rest_position`) attribute on the surface. In cases where the rest position is needed anyway (e.g. for procedural shaders), it's essentially free though. ### Update curves after changes to the original surface If the uv coordinates stored on the curves are not valid anymore, one has to re-attach the curves to the surface by finding e.g. the closest point on the mesh. That's the same for both approaches. If the uv coordinates are still valid, the first approach allows for a "perfect update" to the new base surface mesh, because the old and new position and deformation information is available. With the second approach, that is not possible, because the base mesh does not store the rest position attribute usually. With that approach one could only translate the curves to the new surface position, orientation data is lost. ### Deformation Cost When doing the actual deformation on the deformed surface, one has to have the original and deformed transform of the surface. The deformed transform has to be computed based on deformed vertex positions and the uv coordinates. That's the same for both approaches. However, with the first approach the original transform is available already and does not have to be recomputed again. It's essentially cached on the curves already. With the second approach, the original transform has to be computed exactly like the deformed transform, which has a higher computational cost. In theory, when using the second approach, the computed original deformation can also be cached. Correct cache invalidation might be a bit harder here though, unless the deformed rest position and uv map attribute are cached as well (which they could). ### Multiple Deformations This section is a bit speculative, because I'm not sure if there are better ways to do it, or if this actually comes up in practice. Sometimes it might be necessary to deform hair based on a deformed surface a first time, then deform the surface a bit more, and then deform the hair based on the newly deformed surface. A possible use case might be where attributes on the curves depend on the final pose of a character in a shot. In that case, one could first deform the curves to the final pose, initialize some attributes, and then deform it to the pose at the current frame. This kind of double deformation requires some extra work after the first deformation. With the first approach, the original transform stored on each curve has to be updated to the current deformed transform. With the second approach, one would have to update the rest position attribute to the deformed position, or more likely, one would have to add a new separate rest position attribute. Depending on the context, one or the other might be easier. ### Add hair during simulation Imagine the situation where hair curves are dynamically added to a simulated surface over time (e.g. whenever a particle hits a simulated piece of cloth). Newly added curves should stick to the surface correctly. With the first approach, this would "just work". That's because it is ok when different curves are added at different types when the surface has changed, as long as the surface deformation at the time of creation is stored on the curves correctly. With the second approach, when a new curve is added, one would have to "reverse transform" it based on a rest position attribute on the surface. Alternatively, one would have to update the curve positions and rest positions on the surface in every frame (then "rest position" becomes more like "previous position" which is also common). This way, all curves are based on the same rest positions. ### Tangents To compute the rotational part of the original and deformed transform, one needs the surface normal as well as a tangent. For the tangent it is important that it is choosen consistently for both the original and deformed transform. Otherwise, the curves would rotate around the surface normal in seemingly unpredictable ways. With the first approach, ensuring consistent tangents might proof to be difficult when the base and deformed mesh have different topology (possibly due to subdivisions or other operations). Even with taking the uv map into account, it's not clear how the tangents can be computed in a consistent way. The second approach is much easier in that regard. Since the original and deformed tangents is computed in the same place and on the same topology, cheaper algorithms can be used to compute tangents that are consistent enough. One might not even have to take the uv map into account. If the rotational part of the transform is not important, or the topology does not change, both approaches work fine.