-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Anisotropy direction parametrization #155
Comments
It would be useful to see some renders. Is it not possible to avoid this discontinuity by computing the tangent vector before the interpolation? (That is, blend vectors, not angles). |
@portsmouth Yes, I believe that is the custom filtering that @virtualzavie is referring to:
|
As discussed in the meeting, I take it that the proposal is to replace the with From the discussion, it also seemed to be desirable to have Or is some other parametrization preferable? |
Another thought, perhaps it could be convenient to keep the existing rotation angle parameter as well as the This would cover the cases where the rotation angle is the preferred parametrization (for convenience say, despite the potential filtering issues). Obviously, if the flow map is supplied and the rotation left untouched, the filtering artifact would not occur. |
@elalish How does the proposals/discussion here align with what you've specified in glTF? (You mentioned you came up with a scheme for handling anisotropy interpolation artifacts). |
Mostly, you can see ours here. We did the vec2 direction plus a 3rd channel for strength to avoid various texture filtering problems like the ones you've described. We also have a scalar rotation angle, but that is not textured, given the filtering issues. I'm not sure if you have the concept of factors that are separate from textures like glTF has. |
@elalish OK thanks, that all makes sense. Perhaps for consistency with your approach we could define our "flow map" with the same parametrization, i.e. a We can also keep the anisotropy rotation angle, with the understanding that usage of this instead of a flow map can lead to interpolation artifacts. (We don't have the concept of non-texturable quantities at present). @virtualzavie thoughts? |
Yes, that's exactly how I envision this.
This one is a bit tricky. I originally was wondering whether to have a normalised vector and a separate strength, or just having a single 2D vector whose norm would represent the strength, but one aspect makes me lean strongly toward the former. In case of a low resolution texture, the norm of the vector is going to altered by the texture filtering. For that reason, I think it's safer to assume a normalised 2D vector indicating the direction of the flow, and a 1D anisotropy strength. Thus, the direction vector can be normalised in the shader to reduce artifacts introduced by filtering, just like is typically done for normal maps.
Yes, that was my conclusion as well. I'm happy to see we independently came to the same conclusion on those various points.
I'm not sure I see the benefit of allowing two different parametrisations. I'll draft a PR specifying this. |
Agreed - at glTF we originally wanted to use a vec2 where the length was the strength, but upon implementation we found serious interpolation artifacts as you suggest, particularly bad when interpolating across large rotations, which end up with low intermediate strength values. It was more eye-catching than we expected. |
Though if we keep the existing Also it seems potentially like it could be convenient for artists to be able to modify the angle directly (either as a constant/uniform, or texturing it), rather than having to work with a more complex flow-map parametrization. It's quite intuitive to change the angle and see the highlights rotating, and it seems to me a shame to remove that functionality. (We can just warn that if textured the angle may generate interpolation artifacts due to the discontinuity at 360°, and the flow-map is preferable in production to avoid that). As noted, in the implementation it would trivially just be rotating the T' given by the flow map through an additional angle (defaulting to zero, so does nothing). Seems worth considering at least. |
Proposal PR to address this issue: #170. I'm also considering the following changes: Specify anisotropy direction in terms of NDFThe current state of the specification states:
When possible we should probably specify in terms of properties of the BSDF rather than the result of shading. Moreover, although it is strictly equivalent from a technical point of view, from an intuition point of view it might make more sense to consider that the vector indicate the direction of the grooves. Combining the two considerations, I think it would be more rigorous and less ambiguous to specify instead:
NamingWe have:
There seem to be a slight inconsistency here, where on one side anisotropy parameters are named as a property of the slab, and on the other side anisotropy parameters are named as a parameter to a property of a slab. Although more verbose, I would argue the latter is more rigorous. So I would suggest something like:
|
By the way, it was suggested during the discussion to specify the vector as values in What is the consensus here? I lean slightly toward a texture workflow friendly specification, but I certainly don't feel strongly about it either, as I see pros and cons to both. |
The [0,1] convention seems best to me, as the flow maps can then be authored simply as the 8-bit RG channels of a PNG say, rather than requiring floating point textures. (Also more easily visualized as colors, than a float texture with negative values in it). Though it could be argued that [-1, 1] channels are more appropriate for this use case, even though it could be more cumbersome to work with. |
The lower texture format requirements is a very good point. Thanks. |
There's a bit of detail I have trouble wrapping my head around. Maybe you'll have some insight. In the spec, we mostly consider the normal map to be outside of the scope, and assume we are given a With that, I have everything I need for anisotropy: all that is left are the Another point that's bothering me, is that by 100% mimicking the normal map and letting the definition outside of the scope, I'm introducing unnecessary choices. It would be simpler to just define the flow map as a UNORM RG texture with values remapped to Do you have thoughts on the topic? |
We said in the "Normal maps" section:
So I think there is no need for a separate In contrast, it makes sense to have a separate Can you clarify what naming you're unhappy with? I thought in #170 we had settled on the following, which seems fine (the consistency of the
|
What do you mean by "by letting the definition outside of the scope, I'm introducing unnecessary choices"? Do you want to not state a formula for how the flow map components affect the tangent, and leave that open to interpretation? That would be bad I think, since it's then not clear what to do in the implementation. These formulas need to be explicitly stated, I think: #170 (comment) |
Thank you for your input. Just to clarify, my thought is twofold. My first observation is the anisotropy direction is just a modification of the local tangent space. If we have a perturbed My second observation is that we can express that modification of the local tangent space very similarly to how we do with normal maps. Furthermore, I think we should take advantage of that similarity so we have a workflow that require less adaptation. I believe users used to thinking of normal maps as an RGB texture that paints the local normal, would gain from thinking of tangent maps as an RG texture that paints the local tangent direction.
If
If we consider the anisotropy direction to effectively be the In the end, the choice is between:
Both approaches have their own tradeoff, and it's not clear to me which is preferable. |
Addendum: after discussing the choice with a couple of people, there are some additional arguments that make me lean more towards having a The rationalisation to justify having the two maps described at different levels would be one of scale, as anisotropy is concerned with microgeometry, thus it doesn't belong to the "geometry" section, unlike the normal map. |
OK I see what you mean. The flow-map parametrization we're discussing is analogous to a normal-mapping convention, but we don't try to pin down any particular such convention in that case (because there is no universal convention it seems). I agree actually, this flow-map idea seems out of scope to me, in a similar sense to normal maps. It seems similarly uncomfortable to be trying to pin down some particular option for the meaning of the components, when we don't even know if there are tools that generate the maps in the form we're assuming. It would technically be fine to just assume that Actually, it makes little sense to me to have both the
I disagree with this, as the tangent vector field is not about macro- or micro-geometry per se, it's just an arbitrary reference direction at every point on the surface, defining a local coordinate system. You can use it for whatever you want, e.g. stretching the NDF, texturing etc. It is more geometric than shading I suppose, since it is just a vector field associated with the geometry. It seems to me you only need to specify the tangent vector field in one place -- We also already explicitly said that coat and spec share the tangent, used for the NDF:
So that was inconsistent with having the coat have its own rotation direction. If you think we really need to allow for separate stretch directions for coat and spec, suggest a plausible use case (I can't think of one). So IMO, we should:
So in summary, the NDF parametrization then consists entirely of:
and we can stop talking about flow maps. I like the sound of that. What's your view on this:
|
Yes, that seems sufficient, and simplicity is an argument for it. Moreover, nothing would prevent from adding a
If the tangent is used for several things, the NDF should have its own tangent, as we may not want to link all of them to the same local tangent space. But in the context of OpenPBR, I can't think of anything but the NDF.
Having two different anisotropic specular lobes but having both of them use the same direction sounds surprising to me. In Adobe Standard Material, only the base layer specular is anisotropic. In Autodesk Standard Surface, it seems both the base layer and the coat have anisotropic reflection, and they have separate rotation parameters. Was this not used?
After talking with artists, I think it's irrelevant to the workflow. So we can either pick a side (I agree T for creases seems sensible), or try to align with an existing industry consensus if we identify any. |
If we really want separate anisotropy directions for coat and specular lobes, then obviously it's not sufficient to rely on I suppose you could argue that it makes sense for Just it's more elaborate and I'm not sure it's necessary. |
I don't have a strong preference either way, but I'll note that the open implementation of Autodesk Standard Surface supports independent rotations for specular and coat layers: https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/standard_surface.mtlx#L151 Our reference implementation of OpenPBR inherits support for these independent controls as well: https://github.com/AcademySoftwareFoundation/OpenPBR/blob/main/reference/open_pbr_surface.mtlx#L133 |
If we need to retain the independent base/coat lobe rotation, I'd like to suggest a third option:
The flow map components for the coat then have the easy to understand meaning as giving the relative rotation of base and coat anisotropy. |
I went through the documentation of various tools, to try to see if there was a consensus.
It looks like there's somewhat of a preference towards stretching the NDF along T, so I'm inclined to follow that trend, although I wouldn't object aligning the micro-grooves with T instead. Hopefully I didn't confuse things. Another takeaway is that models often lack clarity on that topic; some don't even say what the reference is. |
The current OpenPBR specification proposes to control the anisotropy with a
specular_anisotropy
(respectivelycoat_anisotropy
) and the direction of the specular highlight elongation with aspecular_rotation
(respectivelycoat_rotation
).In the case those inputs are given with a texture, or more generally if some filtering is involved, the
specular_rotation
will require special care to avoid artifacts due to the discontinuity at the 360° / 0° angle. At a minimum, this requires the ability to specify a nearest-neighbor filter, but obtaining a level of quality consistent with bilinear, trilinear or anisotropic filtering involves implementing a custom filtering scheme to handle the discontinuity case. Such a custom filtering has to be implemented deep into the shader, requires more texture fetches, and represents a non trivial amount of work for the developer of the renderer.An alternative approach is to specify the direction with a flow map of the anisotropy direction 2D vectors. This parametrization is more suitable to texture filtering implemented in most renderers and 3D hardware, does not require a special case, and is very similar to normal maps which are widely supported.
Although it may seem expressing an angle (1 parameter) as a vector (2 parameters) might incur an additional bandwidth cost, factoring
specular_anisotropy
into the vector norm should lead to an equivalent cost (or lesser since no custom filtering with additional fetches is involved).glTF expresses the anisotropy direction and strength as a 3 component texture though, so pro and cons of the two solutions would have to be weighted.
It may also seem that authoring a flow map directly is more difficult, but authoring a rotation map directly is in fact difficult as well and better performed with a dedicated tool anyway.
The text was updated successfully, but these errors were encountered: