PixarAnimationStudios / OpenSubdiv

An Open-Source subdivision surface library.
graphics.pixar.com/opensubdiv
Other
2.88k stars 558 forks source link

How to use precomupted tangents? #213

Closed ast3rX closed 10 years ago

ast3rX commented 11 years ago

Hello,

I'm trying to generate a TBN matrix using the smoothed normals and the tangents. If I handle the tangents in the Maya glsl shader similarly to the normals (vec3 T = input.v.tangent; etc.) it seems to return something useful, however if I display these tangents I get patches on the surface where the tangents are different/wrong. Is this a bug or am I doing something wrong? There are no examples in the code where these tangents are used, so not sure if my assumptions are good. My first approach was generating the TBN matrix from the smoothed normals only but the quality of the TBN matrix wasn't good enough.

Thanks.

tangent_artifact

manuelk commented 11 years ago

Hi

When you mention the Maya glsl shaders, are you referring to our "obsolete" Maya plugin examples ?

Also: the image you posted looks pretty smooth - could you point to the problems, or post an image of the patches you are seeing ?

ast3rX commented 11 years ago

A workaround I found is to generate the tangents for the faces which won't be smooth but will have the right direction. I can use these tangents in a faceforward function to flip the direction of the smoothed tangents, which eliminates most of these artifacts but there will still be some weird tangents at the poles.

Let me know if you need more explanation or samples. Thanks!

manuelk commented 11 years ago

I should have thought of asking for an OBJ export of the geo, but i think that i have an idea of whats going on...

The tangents are computed analytically from the first order derivative of the polynomial patches rendered. Since the faces in the geometry are broken up into sub-patches (uniformly or adaptively), each sub-face has a local normalized parametric space, but the origin of each local space rotates in 90 deg. CCW increments for each level of subdivision.

In order to scale / rotate back up to the parametric space of the parent coarse face, we export a texture buffer with some information for each patch. If you look into glslPatchCommon.glsl you will find OSD_COMPUTE_PTEX_COMPATIBLE_TANGENT functions that show how everything is unpacked and the tangents are computed for the pixel shader.

At the higher level though, there is no guarantee to the ordering of the vertices in the coarse faces is consistent: the (u,v) origin for each coarse face is always lined with the first vertex of each face. Unless the mesh is modeled very carefully (like a procedurally generated sphere...), tangent spaces are unlikely to line up, and most topologies will require seams and boundaries.

The only other solution that I know of for a "smooth" tangent space across a mesh is to orient the tangent plane of each pixel sample with the U (or V) direction of a face-varying unwrapped UV layout.

Disclaimer: the maya plugin code has not been kept up to date for a while, so the GLSL shader code is probably not the best example to look at...

ast3rX commented 11 years ago

I've been trying to implement your last suggestion. I assume you refer to something like this:

vec3 generateTangent(vec3 position, vec2 texCoord) { vec3 Q1 = dFdx(position); vec3 Q2 = dFdy(position); vec2 st1 = dFdx(texCoord.st); vec2 st2 = dFdy(texCoord.st); return normalize( Q1 * st2.t - Q2 * st1.t ); }

The issue with such an approach is that despite of the tangents are pointing to the same direction, the result looks faceted since it doesn't take smooth normals into consideration. This will cause artifacts in shading where tangents are needed (normal mapping and displacement especially).

tangent_artifact2

This was my first approach and I wanted to have something better, so I replaced this with the OSD tangents, which actually made the shader look worse.

If you check the YouTube video "Pixar OpenSubdiv1" at 0:48 it's quite obvious that you can see the original "faceted" topology in the reflections if displacement is applied. Maybe this is a similar issue as well.

manuelk commented 11 years ago

Not quite... I think the Maya sample code may not have feature-adaptive patch drawing, so this may require some work, but the gist of it is:

Mathematically this gets a little tricky though as it becomes a bi-variate derivation and you need to apply the chain rule to get the proper formulation (thank you Dr. DeRose). I have some Renderman shading language code that does this, so it does work, but we have not provided an equivalent GLSL solution (yet ?).

The original video was "faceted" because we had not implemented feature adaptive patches at the time and we reverted to facet normals due to lack of time. Our second video (with the Turtle Barbarian), which is using a screen-space derivative solution is suffering from another set of subtle (and not-so-subtle) rendering artifacts, which we are hoping to resolve soon-ish. Because the code for these demonstrations tends to be thrown together at the last minute, some of the finer details are sometimes glossed over a little bit...

Hope this helps

M.

ast3rX commented 11 years ago

Thank you for the explanation. Basically, it seems that implementing "robust" tangents needs the equivalent of your Renderman shading language code. Would a GLSL extension be on your short-term priority list? Do you have an ETA when this can be added to the OSD core on your side? This would be quite valuable in terms of production-quality shading.

Thank you, David

manuelk commented 11 years ago

The tangents that you are currently getting out of the feature adaptive bi-cubic patches are smooth and analytical derivatives of the limit surface. These are the same methods used by PRman and should work for most "production-shading" applications, including surface displacement.

I am assuming however that your original problem is the definition of a cross-patch continuous tangent space (for vector displacements ?). In this case, just like RSL's derivatives, tangents are local to the limit patches and will rotate along with the topology of the mesh. This can be partially overcome by using a UV layout to orient the surface-tangent plane of your TBN space, and there are several ways of doing this. You would probably need a way of obtaining an analytical derivative of face-varying data, which is a fairly complex problem (same reason that we currently do not support bi-cubic face-varying boundary interpolation rules (aka smooth UVs) in feature adaptive mode yet).

I do not have any estimate as to when we will be tackling smooth face-varying interpolation or tangent spaces yet. This requires some non-trivial improvements to our feature adaptive topological analysis. It also requires more data to be passed to the shaders (bandwidth cost) and doubles the number of bi-cubic interpolations (performance cost).

Before we get to it, we will probably want to replace our screen-space derivative displacement code with Loop's analytic displacement mapping solution along with introducing ptex mip-mapping. These simpler steps should go a long way towards improving the general quality of our displacement shading for a likely net improvement in performance instead.

manuelk commented 10 years ago

Minor update : Takahito just checked in an implementation of 'Analytic Displacement Mapping using Hardware Tessellation; Niessner and Loop [TOG 2013]'. It is now in release 2.3.0

This might be relevant to what you are trying to solve...

I am going to close this for now, please feel free to reopen the issue if you have more questions.