mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-13 23:50:09 +00:00
244 lines
8.7 KiB
ReStructuredText
244 lines
8.7 KiB
ReStructuredText
|
..
|
||
|
Copyright 2015 Pixar
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||
|
with the following modification; you may not use this file except in
|
||
|
compliance with the Apache License and the following modification to it:
|
||
|
Section 6. Trademarks. is deleted and replaced with:
|
||
|
|
||
|
6. Trademarks. This License does not grant permission to use the trade
|
||
|
names, trademarks, service marks, or product names of the Licensor
|
||
|
and its affiliates, except as required to comply with Section 4(c) of
|
||
|
the License and to reproduce the content of the NOTICE file.
|
||
|
|
||
|
You may obtain a copy of the Apache License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the Apache License with the above modification is
|
||
|
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
KIND, either express or implied. See the Apache License for the specific
|
||
|
language governing permissions and limitations under the Apache License.
|
||
|
|
||
|
|
||
|
OSD Tessellation shader Interface
|
||
|
---------------------------------
|
||
|
|
||
|
.. contents::
|
||
|
:local:
|
||
|
:backlinks: none
|
||
|
|
||
|
Basic
|
||
|
=====
|
||
|
|
||
|
From 3.0, **Osd** tessellation shaders can be used as a set of functions from
|
||
|
client shader code. In order to tessellate **Osd** patches, client shader
|
||
|
code should perform following processes (regular B-spline patch case):
|
||
|
|
||
|
* In a tessellation control shader
|
||
|
1. fetch a PatchParam for the current patch
|
||
|
2. call OsdComputePerPatchVertexBSpline() to compute OsdPerPatchVertexBezier.
|
||
|
3. compute tessellation level. To prevent cracks on transition patches,
|
||
|
two vec4 parameters (tessOuterHi, tessOuterLo) will be needed in addition to built-in gl_TessLevelInner/Outers.
|
||
|
|
||
|
* In a tessellation evaluation shader
|
||
|
1. call OsdGetTessParameterization() to remap gl_TessCoord to a patch parameter to evaluated at.
|
||
|
2. call OsdEvalPatchBezier()/OsdEvalPatchGregory() to evaluate the current patch.
|
||
|
|
||
|
The following is a minimal example of GLSL code explaining how client shader code
|
||
|
uses OpenSubdiv shader function to tessellate patches of patch table.
|
||
|
|
||
|
|
||
|
Tessellation Control Shader example (for BSpline patches)
|
||
|
*********************************************************
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
layout (vertices = 16) out;
|
||
|
in vec3 position[];
|
||
|
patch out vec4 tessOuterLo, tessOuterHi;
|
||
|
out OsdPerPatchVertexBezier v;
|
||
|
|
||
|
void main()
|
||
|
{
|
||
|
// Get a patch param from texture buffer.
|
||
|
ivec3 patchParam = OsdGetPatchParam(gl_PrimitiveID);
|
||
|
|
||
|
// Compute per-patch vertices.
|
||
|
OsdComputePerPatchVertexBSpline(patchParam, gl_InvocationID, position, v);
|
||
|
|
||
|
// Compute tessellation factors.
|
||
|
if (gl_InvocationID == 0) {
|
||
|
vec4 tessLevelOuter = vec4(0);
|
||
|
vec2 tessLevelInner = vec2(0);
|
||
|
OsdGetTessLevelsUniform(patchParam,
|
||
|
tessLevelOuter, tessLevelInner,
|
||
|
tessOuterLo, tessOuterHi);
|
||
|
|
||
|
gl_TessLevelOuter[0] = tessLevelOuter[0];
|
||
|
gl_TessLevelOuter[1] = tessLevelOuter[1];
|
||
|
gl_TessLevelOuter[2] = tessLevelOuter[2];
|
||
|
gl_TessLevelOuter[3] = tessLevelOuter[3];
|
||
|
|
||
|
gl_TessLevelInner[0] = tessLevelInner[0];
|
||
|
gl_TessLevelInner[1] = tessLevelInner[1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
Tessellation Evaluation Shader example (for BSpline patches)
|
||
|
************************************************************
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
layout(quads) in;
|
||
|
patch in vec4 tessOuterLo, tessOuterHi;
|
||
|
in OsdPerPatchVertexBezier v[];
|
||
|
uniform mat4 mvpMatrix;
|
||
|
|
||
|
void main()
|
||
|
{
|
||
|
// Compute tesscoord.
|
||
|
vec2 UV = OsdGetTessParameterization(gl_TessCoord.xy, tessOuterLo, tessOuterHi);
|
||
|
|
||
|
vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0);
|
||
|
vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0);
|
||
|
ivec3 patchParam = inpt[0].v.patchParam;
|
||
|
|
||
|
// Evaluate patch at the tess coord UV
|
||
|
OsdEvalPatchBezier(patchParam, UV, v, P, dPu, dPv, N, dNu, dNv);
|
||
|
|
||
|
// Apply model-view-projection matrix.
|
||
|
gl_Position = mvpMatrix * vec4(P, 1);
|
||
|
}
|
||
|
|
||
|
Basis Conversion
|
||
|
================
|
||
|
|
||
|
B-spline patch
|
||
|
**************
|
||
|
|
||
|
The following diagram shows how **Osd** shader processes b-spline patches.
|
||
|
|
||
|
.. image:: images/osd_shader_bspline.png
|
||
|
|
||
|
While regular patches are expressed as b-spline patches in Far::PatchTable,
|
||
|
**Osd** shader converts them into Bezier basis patches, for simplicity and efficiency.
|
||
|
This conversion is performed in the tessellation control stage. The boundary edge evaluation
|
||
|
and single crease matrix evaluation are also resolved during this conversion.
|
||
|
OsdComputePerPatchVertexBSpline() can be used for this process.
|
||
|
The resulting Bezier control vertices are stored in OsdPerPatchVertexBezier struct.
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
void OsdComputePerPatchVertexBSpline(
|
||
|
ivec3 patchParam, int ID, vec3 cv[16], out OsdPerPatchVertexBezier result);
|
||
|
|
||
|
The tessellation evaluation shader takes an array of OsdPerPatchVertexBezier struct,
|
||
|
and then evaluates the patch using OsdEvalPatchBezier() function.
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
void OsdEvalPatchBezier(ivec3 patchParam, vec2 UV,
|
||
|
OsdPerPatchVertexBezier cv[16],
|
||
|
out vec3 P, out vec3 dPu, out vec3 dPv,
|
||
|
out vec3 N, out vec3 dNu, out vec3 dNv)
|
||
|
|
||
|
|
||
|
Gregory Basis patch
|
||
|
*******************
|
||
|
|
||
|
In a similar way, gregory basis patches are processed as follows:
|
||
|
|
||
|
.. image:: images/osd_shader_gregory.png
|
||
|
|
||
|
OsdComputePerPatchVertexGregoryBasis() can be used for the gregory patches
|
||
|
(although no basis conversion involved for the gregory patches) and the resulting vertices
|
||
|
are stored in OsdPerPatchVertexGreogryBasis struct.
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
void OsdComputePerPatchVertexGregoryBasis(
|
||
|
ivec3 patchParam, int ID, vec3 cv, out OsdPerPatchVertexGregoryBasis result)
|
||
|
|
||
|
The tessellation evaluation shader takes an array of OsdPerPatchVertexGregoryBasis struct,
|
||
|
and then evaluates the patch using OsdEvalPatchGregory() function.
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
void
|
||
|
OsdEvalPatchGregory(ivec3 patchParam, vec2 UV, vec3 cv[20],
|
||
|
out vec3 P, out vec3 dPu, out vec3 dPv,
|
||
|
out vec3 N, out vec3 dNu, out vec3 dNv)
|
||
|
|
||
|
|
||
|
Legacy Gregory patch (2.x compatibility)
|
||
|
****************************************
|
||
|
|
||
|
OpenSubdiv 3.0 also supports 2.x style gregory patch evaluation (see far_overview).
|
||
|
In order to evaluate a legacy gregory patch, client needs to bind extra buffers and
|
||
|
to perform extra steps in the vertex shader as shown in the following diagram:
|
||
|
|
||
|
.. image:: images/osd_shader_legacy_gregory.png
|
||
|
|
||
|
|
||
|
|
||
|
Tessellation levels
|
||
|
===================
|
||
|
|
||
|
**Osd** provides both uniform and screen-space adaptive tessellation level computation.
|
||
|
|
||
|
Uniform tessellation
|
||
|
OsdGetTessLevelsUniform()
|
||
|
|
||
|
Screen-space adaptive tessellation
|
||
|
OsdGetTessLevelsAdaptiveLimitPoints()
|
||
|
|
||
|
Because of the nature of `feature adaptive subdivision <far_overview.html>`__,
|
||
|
we need to pay extra attention for patch's outer tessellation level for the screen-space
|
||
|
adaptive case so that cracks won't appear.
|
||
|
|
||
|
An edge of the patch marked as a transition edge is split into two segments (Hi and Lo).
|
||
|
|
||
|
.. image:: images/osd_shader_patch.png
|
||
|
|
||
|
**Osd** shader uses these two segment to ensure the same tessellation along the
|
||
|
edge between different levels of subdivision. In the following example, suppose the left hand side
|
||
|
patch has determined the tessellation level of its right edge to 5. gl_TessLevelOuter is set to
|
||
|
5 for the edge, and at the same time we also pass 2 and 3 to the tessellation evaluation shader
|
||
|
as separate levels for the two segments of the edge split at the middle.
|
||
|
|
||
|
.. image:: images/osd_shader_transition.png
|
||
|
|
||
|
Then the tessellation evaluation shader takes gl_TessCoord and those two values, and remaps
|
||
|
gl_TessCoord using OsdGetTessParameterization() to ensure the parameters are consistent
|
||
|
across adjacent patches.
|
||
|
|
||
|
.. image:: images/osd_shader_param_remap.png
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
vec2 OsdGetTessParameterization(vec2 uv, vec4 tessOuterLo, vec4 tessOuterHi)
|
||
|
|
||
|
These tessellation levels can be computed by OsdGetTessLevelsAdaptiveLimitPoints()
|
||
|
in the tessellation control shader. Note that this function requires all 16 bezier control
|
||
|
points, you need to call barrier() to ensure the conversion is done for all invocations.
|
||
|
See osd/glslPatchBSpline.glsl for more detail.
|
||
|
|
||
|
.. code:: glsl
|
||
|
|
||
|
void OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
|
||
|
ivec3 patchParam,
|
||
|
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
||
|
out vec4 tessOuterLo, out vec4 tessOuterHi)
|
||
|
|
||
|
.. container:: impnotip
|
||
|
|
||
|
**Release Notes (3.0.0)**
|
||
|
|
||
|
* Currently OsdGetTessParameterization doesn't support fraction spacing.
|
||
|
It will be fixed in the future release.
|
||
|
|