mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-09 22:00:06 +00:00
711 lines
38 KiB
ReStructuredText
711 lines
38 KiB
ReStructuredText
..
|
|
Copyright 2022 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.
|
|
|
|
|
|
BFR Overview
|
|
------------
|
|
|
|
.. contents::
|
|
:local:
|
|
:backlinks: none
|
|
|
|
Base Face Representation (Bfr)
|
|
==============================
|
|
|
|
*Bfr* is an alternate API layer that treats a subdivision mesh provided
|
|
by a client as a `piecewise parameteric surface primitive
|
|
<subdivision_surfaces.html#piecewise-parametric-surfaces>`__.
|
|
|
|
The name *Bfr* derives from the fact that the concepts and classes of
|
|
this interface all relate to the "base faces" of a mesh. Concepts such
|
|
as *parameterization*, *evaluation* and *tessellation* all refer to and
|
|
are embodied by classes that deal with a specific face of the original
|
|
unrefined mesh.
|
|
|
|
The *Bfr* interfaces allow the limit surface for a single face to be
|
|
identified and evaluated independently of all other faces without any
|
|
global pre-processing. While concepts and utilities from the *Far*
|
|
interface are used internally, the details of their usage is hidden.
|
|
There is no need to coordinate adaptive refinement with tables of
|
|
patches, stencils, Ptex indices, patch maps, etc.
|
|
|
|
The resulting evaluation interface is much simpler, more flexible and
|
|
more scalable than those assembled with the *Far* classes -- providing
|
|
a preferable alternative for many CPU-based use cases.
|
|
|
|
The main classes in *Bfr* include:
|
|
|
|
+------------------+----------------------------------------------------------+
|
|
| SurfaceFactory | A light-weight interface to a mesh that constructs |
|
|
| | pieces of limit surface for specified faces of a mesh |
|
|
| | in the form of Surfaces. |
|
|
+------------------+----------------------------------------------------------+
|
|
| Surface | A class encapsulating the limit surface of a face with |
|
|
| | methods for complete parametric evaluation. |
|
|
+------------------+----------------------------------------------------------+
|
|
| Parameterization | A simple class defining the available parameterizations |
|
|
| | of faces and for identifying that of a particular face. |
|
|
+------------------+----------------------------------------------------------+
|
|
| Tessellation | A simple class providing information about a specified |
|
|
| | tessellation pattern for a given Parameterization. |
|
|
+------------------+----------------------------------------------------------+
|
|
|
|
*Bfr* is well suited to cases where evaluation of the mesh may be sparse,
|
|
dynamically determined or iterative (Newton, gradient descent, etc).
|
|
It is not intended to replace the cases for which *Far* has been designed
|
|
(i.e. repeated evaluation of a fixed set of points) but is intended to
|
|
complement them. While simplicity, flexibility and reasonable performance
|
|
were the main goals of *Bfr*, its current implementation often outperforms
|
|
the table-based solutions of *Far* for many common use cases -- both in terms
|
|
of execution time and memory use.
|
|
|
|
An area that *Bfr* does not address, and where *Far* remains more suited,
|
|
is capturing a specific representation of the limit surface for external
|
|
use. *Bfr* intentionally keeps internal implementation details private to
|
|
allow future improvements or extensions. Those representation details may
|
|
be publicly exposed in future releases, but until then, use of *Far* is
|
|
required for such purposes.
|
|
|
|
----
|
|
|
|
.. _bfr-navlink-evaluation:
|
|
|
|
Evaluation
|
|
==========
|
|
|
|
Since subdivision surfaces are piecewise parametric surfaces, the main
|
|
operation of interest is evaluation.
|
|
|
|
*Bfr* deals with the limit surface of a mesh as a whole by associating
|
|
pieces of surface with each face of the mesh. These pieces of surface
|
|
are referred to in the context of *Bfr* simply as "surfaces" and
|
|
represented by Bfr::Surface.
|
|
|
|
Each face of the mesh has an implicit local 2D parameterization and
|
|
individual coordinates of that parameterization are used to evaluate its
|
|
corresponding Surface. In general, 3- and 4-sided faces use the same
|
|
parameterizations for quad and triangular patches used elsewhere in
|
|
OpenSubdiv:
|
|
|
|
+--------------------------------------+--------------------------------------+
|
|
| .. image:: images/param_uv.png | .. image:: images/param_uv2xyz.png |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/param_uv.png | :target: images/param_uv2xyz.png |
|
|
+--------------------------------------+--------------------------------------+
|
|
|
|
Parameterizations are defined for other faces (more details to follow), so
|
|
Surfaces for all faces can be evaluated given any 2D parametric coordinate
|
|
of its face.
|
|
|
|
Given an instance of a mesh, usage first requires the creation of a
|
|
Bfr::SurfaceFactory corresponding to that mesh -- from which Surfaces
|
|
can then be created for evaluation. Construction of the SurfaceFactory
|
|
involves no pre-processing and Surfaces can be created and discarded
|
|
as needed. The processes of constructing and evaluating Surfaces are
|
|
described in more detail below.
|
|
|
|
Bfr::SurfaceFactory
|
|
*******************
|
|
|
|
Construction of Bfr::Surfaces requires an instance of Bfr::SurfaceFactory.
|
|
|
|
An instance of SurfaceFactory is a light-weight interface to an instance
|
|
of a mesh that requires little to no construction cost or memory. The
|
|
SurfaceFactory does no work until a Surface is requested for a particular
|
|
face -- at which point the factory inspects the mesh topology around that
|
|
face to assemble the Surface.
|
|
|
|
.. image:: images/bfr_eval_surfacefactory.png
|
|
:align: center
|
|
|
|
SurfaceFactory is actually a base class that is inherited to provide a
|
|
consistent construction interface for Surfaces. Subclasses are derived
|
|
to support a particular class of connected mesh -- to implement the
|
|
topology inspection around each face required to construct the Surface.
|
|
Use of these subclasses is very simple given the public interface of
|
|
SurfaceFactory, but defining such a subclass is not. That more complex
|
|
use case of SurfaceFactory will be described in detail later with other
|
|
more advanced topics.
|
|
|
|
In many cases, it is not necessary to explicitly define a subclass of
|
|
SurfaceFactory, as the tutorials for *Bfr* illustrate.
|
|
If already using OpenSubdiv for other reasons, a Far::TopologyRefiner
|
|
will have been constructed to represent the initial base mesh before
|
|
refinement. *Bfr* provides a subclass of SurfaceFactory using
|
|
Far::TopologyRefiner as the base mesh (ignoring any levels of
|
|
refinement) for immediate use in such cases.
|
|
|
|
For those cases when no connected mesh representation is available at
|
|
all (i.e. only raw, unconnected mesh data exists) construction of a
|
|
Far::TopologyRefiner provides a reasonably efficient connected mesh
|
|
representation (see the *Far* tutorials for construction details),
|
|
whose provided subclass for SurfaceFactory is then readily available.
|
|
|
|
Given the different interpolation types for mesh data (i.e. "vertex",
|
|
"varying" and "face-varying"), the common interface for SurfaceFactory
|
|
provides methods to construct Surfaces explicitly for all data types.
|
|
So for positions, the methods for "vertex" data must be used to obtain
|
|
the desired Surface, while for texture coordinates the methods for
|
|
"face-varying" are usually required, e.g.:
|
|
|
|
.. code:: c++
|
|
|
|
Surface * CreateVertexSurface( Index faceIndex) const;
|
|
Surface * CreateVaryingSurface( Index faceIndex) const;
|
|
Surface * CreateFaceVaryingSurface(Index faceIndex) const;
|
|
|
|
The Surfaces created by these construction methods may all be
|
|
distinct as the underlying representations of the Surfaces and the
|
|
indices of the data that define them will often differ. For
|
|
example, the position data may require a bicubic patch while the
|
|
face-varying texture data may be linear or a different type of
|
|
bicubic patch (given the different interpolation rules for
|
|
face-varying and the possibility of seams).
|
|
|
|
While the internal representations of the Surfaces constructed for
|
|
different data interpolation types may differ, since they are all
|
|
constructed as Surfaces, the functionality used to evaluate them is
|
|
identical.
|
|
|
|
Bfr::Surface
|
|
************
|
|
|
|
The Surface class encapsulates the piece of limit surface associated
|
|
with a particular face of the mesh. The term "surface" is used rather
|
|
than "patch" to emphasize that the Surface may itself be a piecewise
|
|
parametric surface composed of more than one patch (potentially
|
|
even a complex set of patches).
|
|
|
|
Surface is also a class template selected by floating point precision,
|
|
and so typically declared as Bfr::Surface<float>. Just as a simpler
|
|
type name is likely to be declared when used, the simple name Surface
|
|
will be used to refer to it here. And where code fragments may be
|
|
warranted, "float" will be substituted for the template parameter for
|
|
clarity.
|
|
|
|
Once created, there are two steps required to evaluate a Surface:
|
|
|
|
* preparation of associated data points from the mesh
|
|
* the actual calls to evaluation methods using these data points
|
|
|
|
The latter is straight-forward, but the former warrants a little more
|
|
explanation.
|
|
|
|
The shape of a Surface for a base face is influenced by the set of data
|
|
points associated with both the vertices of the face and a subset of
|
|
those in its immediate neighborhood. These "control points" are
|
|
identified when the Surface is initialized and are publicly available
|
|
for inspection if desired. The control points are sufficient to define
|
|
the Surface if the face and its neighborhood are regular, but any
|
|
irregularity (an extra-ordinary vertex, crease, etc.) usually requires
|
|
additional, intermediate points to be computed from those control points
|
|
in order to evaluate the Surface efficiently.
|
|
|
|
Having previously avoided use of the term "patch" in favor of "surface",
|
|
the term "patch points" is now used to refer to these intermediate points.
|
|
Patch points always include the control points as a subset and may be
|
|
followed by points needed for any additional patches required to represent
|
|
a more complex Surface. While the patch points are assembled in a local
|
|
array for direct use by the Surface, the control points can either be
|
|
gathered and accessed locally or indexed from buffers associated with the
|
|
mesh for other purposes (e.g. computing a bounding box of the Surface):
|
|
|
|
.. image:: images/bfr_eval_surface.png
|
|
:align: center
|
|
|
|
Once the patch points for a Surface are prepared, they can be passed to
|
|
the main evaluation methods with the desired parametric coordinates.
|
|
As previously noted, since the Surface class is a template for floating
|
|
point precision, evaluation is supported in single or double precision
|
|
by constructing a Surface for the desired precision. Evaluation methods
|
|
are overloaded to obtain simply position or including all first or second
|
|
derivatives. So preparation and evaluation can be achieved with the
|
|
following:
|
|
|
|
.. code:: c++
|
|
|
|
// Preparing patch points:
|
|
void PreparePatchPoints(
|
|
float const * meshPoints, PointDescriptor meshPointDescriptor,
|
|
float * patchPoints, PointDescriptor patchPointDescriptor) const;
|
|
|
|
// Evaluating position and 1st derivatives:
|
|
void Evaluate(float const uv[2],
|
|
float const * patchPoints, PointDescriptor patchPointDescriptor,
|
|
float * P, float * dPdu, float * dPdv) const;
|
|
|
|
The PointDescriptor class here is a simple struct defining the size and
|
|
stride of the associated array of points. Any use of mesh points, control
|
|
points or patch points generally requires an accompanying descriptor.
|
|
|
|
Depending on the complexity of the limit surface, this preparation of
|
|
patch points can be costly -- especially if only evaluating the Surface
|
|
once or twice. In such cases, it is worth considering evaluating
|
|
"limit stencils", i.e. sets of coefficients that combine the original
|
|
control vertices of the mesh without requiring the computation of
|
|
intermediate values.
|
|
The cost of evaluating stencils is considerably higher than direct
|
|
evaluation, but that added overhead is often offset by avoiding the
|
|
use of patch points.
|
|
|
|
Surfaces should be considered a class for transient use as retaining
|
|
them for longer term usage can reduce their benefits. The relatively
|
|
high cost of initialization of irregular Surfaces can be a deterrent
|
|
and often motivates their retention despite increased memory costs.
|
|
Retaining all Surfaces of a mesh for random sampling is a situation
|
|
that should be undertaken with caution and will be discussed in more
|
|
detail later with other advanced topics.
|
|
|
|
----
|
|
|
|
.. _bfr-navlink-parameterization:
|
|
|
|
Parameterization
|
|
================
|
|
|
|
Each face of a mesh has an implicit local 2D parameterization whose 2D
|
|
coordinates are used to evaluate the Surface for that face.
|
|
|
|
*Bfr* adopts the parameterizations defined elsewhere in OpenSubdiv for
|
|
quadrilateral and triangular patches, for use quadrilateral and
|
|
triangular faces:
|
|
|
|
+----------------------------------------------+----------------------------------------------+
|
|
| .. image:: images/bfr_param_patch_quad.png | .. image:: images/bfr_param_patch_tri.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_param_patch_quad.png | :target: images/bfr_param_patch_tri.png |
|
|
+----------------------------------------------+----------------------------------------------+
|
|
|
|
But the parameterization of a face is also dependent on the subdivision
|
|
scheme applied to it.
|
|
|
|
Subdivision schemes that divide faces into quads are ultimately represented
|
|
by quadrilateral patches. So a face that is a quad can be parameterized as
|
|
a single quad, but other non-quad faces are parameterized as a set of quad
|
|
"sub-faces", i.e. faces resulting from subdivision:
|
|
|
|
+-------------------------------------------+
|
|
| .. image:: images/bfr_param_subfaces.png |
|
|
| :align: center |
|
|
| :width: 100% |
|
|
| :target: images/bfr_param_subfaces.png |
|
|
+-------------------------------------------+
|
|
|
|
A triangle subdivided with a quad-based scheme (e.g. Catmull-Clark) will
|
|
therefore not have the parameterization of the triangular patch indicated
|
|
previously, but another defined by its quad sub-faces illustrated above
|
|
(to be described in more detail below).
|
|
|
|
Subdivision schemes that divide faces into triangles are currently restricted
|
|
to triangles only, so all faces are parameterized as single triangles. (If
|
|
Loop subdivision is extended to non-triangles in future, a parameterization
|
|
involving triangular sub-faces will be necessary.)
|
|
|
|
Note that triangles are often parameterized elsewhere in terms of barycentric
|
|
coordinates (u,v,w) where *w = 1 - u - v*. As is the case elsewhere in
|
|
OpenSubdiv, *Bfr* considers parametric coordinates as 2D (u,v) pairs for all
|
|
purposes. All faces have an implicit 2D local parameterization and all
|
|
interfaces requiring parametric coordinates consider only the (u,v) pair.
|
|
If interaction with some other tool set requiring barycentric coordinates
|
|
for triangles is necessary, it is left to users to compute the implicit *w*
|
|
accordingly.
|
|
|
|
Bfr::Parameterization
|
|
*********************
|
|
|
|
Bfr::Parameterization is a simple class that fully defines the parameterization
|
|
for a particular face.
|
|
|
|
An instance of Parameterization is fully defined on construction given the
|
|
"size" of a face and the subdivision scheme applied to it (where the face
|
|
"size" is its number of vertices/edges). Since any parameterization of
|
|
*N*-sided faces requires *N* in some form, the face size is stored as a member
|
|
and made publicly available.
|
|
|
|
Each Surface has the Parameterization of its face assigned internally as part
|
|
of its construction, and that is used internally by the Surface in many of its
|
|
methods. The need to deal directly with the explicit details of the
|
|
Parameterization class is not generally necessary. Often it is sufficient
|
|
to retrieve the Parameterization from a Surface for use in some other context
|
|
(e.g. passed to Bfr::Tessellation).
|
|
|
|
The enumerated type Parameterization::Type currently defines three kinds of
|
|
parameterizations -- one of which is assigned to each instance on construction
|
|
according to the properties of the face:
|
|
|
|
+---------------+--------------------------------------------------------------+
|
|
| QUAD | Applied to quadrilateral faces with a quad-based |
|
|
| | subdivision scheme (e.g. Catmark or Bilinear). |
|
|
+---------------+--------------------------------------------------------------+
|
|
| TRI | Applied to triangular faces with a triangle-based |
|
|
| | subdivision scheme (e.g. Loop). |
|
|
+---------------+--------------------------------------------------------------+
|
|
| QUAD_SUBFACES | Applied to non-quad faces with a quad-based subdivision |
|
|
| | scheme -- dividing the face into quadrilateral sub-faces. |
|
|
+---------------+--------------------------------------------------------------+
|
|
|
|
Parameterizations that involve subdivision into sub-faces, e.g. QUAD_SUBFACES,
|
|
may warrant some care as they are not continuous. Depending on how they are
|
|
defined, the sub-faces may be disjoint (e.g. *Bfr*) or overlap in parametric
|
|
space (e.g. Ptex). To help these situations, methods to detect the presence
|
|
of sub-faces and deal with their local parameterizations are made available.
|
|
|
|
Discontinuous Parameterizations
|
|
*******************************
|
|
|
|
When a face does not have a regular parameterization, the division of the
|
|
parameterization into sub-faces can create complications -- as noted and
|
|
addressed elsewhere in OpenSubdiv.
|
|
|
|
Bfr::Parameterization defines a quadrangulated sub-face parameterization
|
|
differently from the *Far* and *Osd* interfaces. For an *N*-sided face,
|
|
*Far* uses a parameterization adopted by Ptex. In this case, all quad
|
|
sub-faces are parameterized over the unit square and require an additional
|
|
index of the sub-face to identify them. So Ptex coordinates require three
|
|
values: the index and (u,v) of the sub-face.
|
|
|
|
To embed sub-face coordinates in a single (u,v) pair, *Bfr* tiles the
|
|
sub-faces in disjoint regions in parameter space. This tiling is similar
|
|
to the Udim convention for textures, where a UDim on the order of *sqrt(N)*
|
|
is used to preserve accuracy for increasing *N*:
|
|
|
|
+---------------------------------------------+------------------------------------------------------------+
|
|
| .. image:: images/bfr_param_subfaces_5.png | .. image:: images/bfr_param_subfaces_5_uv.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_param_subfaces_5.png | :target: images/bfr_param_subfaces_5_uv.png |
|
|
+---------------------------------------------+------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
+--------------------------------------------------+--------------------------------------------------+
|
|
| .. image:: images/bfr_param_subfaces_3.png | .. image:: images/bfr_param_subfaces_3_uv.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_param_subfaces_3.png | :target: images/bfr_param_subfaces_3_uv.png |
|
|
+--------------------------------------------------+--------------------------------------------------+
|
|
|
|
Note also that the edges of each sub-face are of parametric length 0.5,
|
|
which results in a total parametric length of 1.0 for all base edges.
|
|
This differs again from Ptex, which parameterizes sub-faces with edge
|
|
lengths of 1.0, and so can lead to inconsistencies in parametric scale
|
|
(typically with derivatives) across edges of the mesh if not careful.
|
|
|
|
As previously mentioned, care may be necessary when dealing with the
|
|
discontinuities that exist in parameterizations with sub-faces. This is
|
|
particularly true if evaluating data at sampled locations of the face
|
|
and needing to evaluate at other locations interpolated from these.
|
|
|
|
+--------------------------------------------------+--------------------------------------------------+
|
|
| .. image:: images/bfr_param_subfaces_abc.png | .. image:: images/bfr_param_subfaces_abc_uv.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_param_subfaces_abc.png | :target: images/bfr_param_subfaces_abc_uv.png |
|
|
+--------------------------------------------------+--------------------------------------------------+
|
|
| Interpolation between parametric locations, e.g. A, B and C, should be avoided when discontinuous. |
|
|
+-----------------------------------------------------------------------------------------------------+
|
|
|
|
In many cases, dealing directly with coordinates of the sub-faces
|
|
is unavoidable, e.g. interpolating Ptex coordinates for sampling of
|
|
textures assigned explicitly to the sub-faces. Methods are provided
|
|
to convert from *Bfr*'s tiled parameterization to and from other
|
|
representations that use a local parameterization for each sub-face.
|
|
|
|
----
|
|
|
|
.. _bfr-navlink-tessellation:
|
|
|
|
Tessellation
|
|
============
|
|
|
|
Once a Surface can be evaluated it can be tessellated. Given a 2D
|
|
parameterization, a tessellation consists of two parts:
|
|
|
|
* a set of parametric coordinates sampling the Parameterization
|
|
* a set of faces connecting these coordinates that covers the
|
|
entire Parameterization
|
|
|
|
Once evaluated, the resulting set of sample points and the faces
|
|
connecting them effectively define a mesh for that parameterization.
|
|
|
|
For the sake of brevity both here and in the programming interface,
|
|
the parametric coordinates or sample points are referred to simply as
|
|
"coords" or "Coords" -- avoiding the term "points", which is already
|
|
a heavily overloaded term. Similarly the faces connecting the coords
|
|
are referred to as "facets" or "Facets" -- avoiding the term "face" to
|
|
avoid confusion with the base face of the mesh being tessellated.
|
|
|
|
*Bfr* provides a simple class to support a variety of tessellation patterns
|
|
for the different Parameterization types and methods for retrieving its
|
|
associated coords and facets. In many cases the patterns they define are
|
|
similar to those of GPU hardware tessellation -- which may be more familiar
|
|
to many -- but they do differ in several ways, as noted below.
|
|
|
|
Bfr::Tessellation
|
|
*****************
|
|
|
|
In *Bfr* a Tessellation is a simple class defined by a Parameterization and
|
|
a given set of tessellation rates (and a few additional options). These two
|
|
elements define a specific tessellation pattern for all faces sharing that
|
|
Parameterization. An instance of Tessellation can then be inspected to
|
|
identify all or subsets of its coords or facets.
|
|
|
|
The process of tessellation in other contexts usually generates triangular
|
|
facets, but that is not the case with *Bfr*. While producing triangular
|
|
facets is the default, options are available to have Tessellation include
|
|
quads in patterns for parameterizations associated with quad-based
|
|
subdivision schemes. For simple uniform patterns, these produce patterns
|
|
that are similar in topology to those resulting from subdivision:
|
|
|
|
+--------------------------------------------+--------------------------------------------+
|
|
| .. image:: images/bfr_tess_quad_quads.png | .. image:: images/bfr_tess_quad_tris.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_quad_quads.png | :target: images/bfr_tess_quad_tris.png |
|
|
+--------------------------------------------+--------------------------------------------+
|
|
| .. image:: images/bfr_tess_pent_quads.png | .. image:: images/bfr_tess_pent_tris.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_pent_quads.png | :target: images/bfr_tess_pent_tris.png |
|
|
+--------------------------------------------+--------------------------------------------+
|
|
| Tessellation of 4- and 5-sided faces of a quad-based scheme using quadrilateral facets |
|
|
| (left) and triangular (right) |
|
|
+-----------------------------------------------------------------------------------------+
|
|
|
|
The name "Tessellation" was chosen rather than "Tessellator" as it is a
|
|
passive class that simply holds information define its pattern. It doesn't
|
|
do much other than providing information about the pattern when requested.
|
|
A few general properties about the pattern are determined and retained on
|
|
construction, after which an instance is immutable. So it does not maintain
|
|
any additional state between queries.
|
|
|
|
In order to provide flexibility when dealing with tessellations of adjacent
|
|
faces, the coords arising from an instance of Tessellation are ordered and
|
|
are retrievable in ways to help identify points along edges that may be
|
|
shared between two or more faces. The coords of a Tessellation are generated
|
|
in concentric rings, beginning with the outer ring and starting with the first
|
|
vertex:
|
|
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| .. image:: images/bfr_tess_quad_order.png | .. image:: images/bfr_tess_tri_order.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_quad_order.png | :target: images/bfr_tess_tri_order.png |
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| Ordering of coords around boundary for quad and tri parameterizations. |
|
|
+-------------------------------------------------------------------------------------------+
|
|
|
|
Methods of the Tessellation class allow the coords associated with specific
|
|
vertices or edges to be identified, as well as providing the coords for the
|
|
entire ring around the boundary separately from those of the interior if
|
|
desired. While the ordering of coords in the interior is not defined (and
|
|
so not to be relied upon), the ordering of the boundary coords is
|
|
specifically fixed to support the correlation of potentially shared coords
|
|
between faces.
|
|
|
|
The Tessellation class is completely independent of the Surface class.
|
|
Tessellation simply takes a Parameterization and tessellation rates and
|
|
provides the coords and facets that define its pattern. So Tessellation can
|
|
be used in any other evaluation context where the Parameterizations are
|
|
appropriate.
|
|
|
|
Tessellation Rates
|
|
******************
|
|
|
|
For a particular Parameterization, the various tessellation patterns are
|
|
determined by one or more tessellation rates.
|
|
|
|
The simplest set of patterns uses a single tessellation rate and is said
|
|
to be "uniform", i.e. all edges and the interior of the face are split to
|
|
a similar degree:
|
|
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| .. image:: images/bfr_tess_uni_quad_5.png | .. image:: images/bfr_tess_uni_quad_8.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_uni_quad_5.png | :target: images/bfr_tess_uni_quad_8.png |
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| .. image:: images/bfr_tess_uni_tri_5.png | .. image:: images/bfr_tess_uni_tri_8.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_uni_tri_5.png | :target: images/bfr_tess_uni_tri_8.png |
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| Uniform tessellation of a quadrilateral and triangle with rates of 5 and 8. |
|
|
+-------------------------------------------------------------------------------------------+
|
|
|
|
More complex non-uniform patterns allow the edges of the face to be split
|
|
independently from the interior of the face. Given rates for each edge, a
|
|
suitable uniform rate for the interior can be either inferred or specified
|
|
explicitly. These are typically referred to as the "outer rates" and the
|
|
"inner rate". (The single rate specified for a simple uniform tessellation
|
|
is essentially the specification of a single inner rate while the outer
|
|
rates for all edges are inferred as the same.)
|
|
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| .. image:: images/bfr_tess_nonuni_quad_A.png | .. image:: images/bfr_tess_nonuni_quad_B.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_nonuni_quad_A.png | :target: images/bfr_tess_nonuni_quad_B.png |
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| .. image:: images/bfr_tess_nonuni_tri_A.png | .. image:: images/bfr_tess_nonuni_tri_B.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_nonuni_tri_A.png | :target: images/bfr_tess_nonuni_tri_B.png |
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| .. image:: images/bfr_tess_nonuni_pent_A.png | .. image:: images/bfr_tess_nonuni_pent_B.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_nonuni_pent_A.png | :target: images/bfr_tess_nonuni_pent_B.png |
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| Non-uniform tessellation of a quadrilateral, triangle and 5-sided face |
|
|
| with various outer and inner rates. |
|
|
+-------------------------------------------------------------------------------------------------+
|
|
|
|
In the case of Parameterizations for quads, it is common elsewhere to
|
|
associate two inner rates with the opposing edges. So two separate
|
|
inner rates are available for quad parameterizations -- to be specified
|
|
or otherwise inferred:
|
|
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| .. image:: images/bfr_tess_mXn_quad_A.png | .. image:: images/bfr_tess_mXn_quad_B.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_mXn_quad_A.png | :target: images/bfr_tess_mXn_quad_B.png |
|
|
+---------------------------------------------+---------------------------------------------+
|
|
| Quad tessellations with differing inner rates with matching (left) and varying outer |
|
|
| rates (right). |
|
|
+-------------------------------------------------------------------------------------------+
|
|
|
|
Differences from Hardware Tessellation
|
|
**************************************
|
|
|
|
Since the specifications for hardware tessellation often leave some details
|
|
of the patterns as implementation dependent, no two hardware implementations
|
|
are necessarily the same. Typically there may be subtle differences in the
|
|
non-uniform tessellation patterns along boundaries, and that is to be executed
|
|
here.
|
|
|
|
*Bfr* does provide some obvious additional functionality not present in
|
|
hardware tessellation and vice versa, e.g. *Bfr* provides the following (not
|
|
supported by hardware tessellation):
|
|
|
|
* patterns for parameterizations other than quads and tris (e.g. N-sided)
|
|
* preservation of quad facets of quad-based parameterizations
|
|
|
|
while hardware tessellation provides the following (not supported by *Bfr*):
|
|
|
|
* patterns for so-called "fractional" tessellation (non-integer rates)
|
|
|
|
The lack of fractional tessellation in *Bfr* is something that may be
|
|
addressed in a future release.
|
|
|
|
Where the functionality of *Bfr* and hardware tessellation overlap, a few
|
|
other differences are worth noting:
|
|
|
|
* indexing of edges and their associated outer tessellation rates
|
|
* uniform tessellation patterns for triangles differ significantly
|
|
|
|
For the indexing of edges and rates, when specifying an outer rate associated
|
|
with an edge, the array index for rate *i* is expected to correspond to edge
|
|
*i*. *Bfr* follows the convention established elsewhere in OpenSubdiv of
|
|
labeling/indexing edges 0, 1, etc. between vertex pairs [0,1], [1,2], etc.
|
|
So outer rate [0] corresponds to the edge between vertices [0,1]. In contrast,
|
|
hardware tessellation associates the rate for the edge between vertices [0,1]
|
|
as outer rate [1] -- its outer rate [0] is between vertices [N-1,0]. So an
|
|
offset of 1 is warranted when comparing the two.
|
|
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| .. image:: images/bfr_tess_diff_edges_osd.png | .. image:: images/bfr_tess_diff_edges_gpu.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_diff_edges_osd.png | :target: images/bfr_tess_diff_edges_gpu.png |
|
|
+------------------------------------------------+------------------------------------------------+
|
|
| Outer edge tessellation rates of {1,3,5,7} applied to a quad with *Bfr* (left) and GPU |
|
|
| tessellation (right). |
|
|
+-------------------------------------------------------------------------------------------------+
|
|
|
|
For the uniform tessellation of triangles, its well known that the needs of
|
|
hardware implementation led designers to factor the patterns for triangles
|
|
to make use of the same hardware necessary for quads. As a result, many edges
|
|
are introduced into a simple tessellation of a triangle that are not parallel
|
|
to one of its three edges.
|
|
|
|
*Bfr* uses patterns more consistent with those resulting from the subdivision
|
|
of triangles. Only edges parallel to the edges of the triangle are introduced,
|
|
which creates more uniform facets (both edge lengths and area) and reduces
|
|
their number (by one third). This can reduce artifacts that sometimes arise
|
|
with use of the hardware patterns at lower tessellation rates:
|
|
|
|
+----------------------------------------------+----------------------------------------------+
|
|
| .. image:: images/bfr_tess_diff_tri_osd.png | .. image:: images/bfr_tess_diff_tri_gpu.png |
|
|
| :align: center | :align: center |
|
|
| :width: 100% | :width: 100% |
|
|
| :target: images/bfr_tess_diff_tri_osd.png | :target: images/bfr_tess_diff_tri_gpu.png |
|
|
+----------------------------------------------+----------------------------------------------+
|
|
| Uniform tessellation of a triangle with *Bfr* (left) and GPU tessellation (right). |
|
|
+---------------------------------------------------------------------------------------------+
|
|
|
|
These triangular patterns have been referred to as "integer spacing"
|
|
for triangular patches in early work on hardware tessellation. But use of
|
|
these patterns was generally discarded in favor of techniques that split
|
|
the triangle into three quads -- allowing the hardware solution for quad
|
|
tessellation to be reused.
|
|
|
|
----
|
|
|
|
.. _bfr-navlink-surfacefactory:
|
|
|
|
More on Bfr::SurfaceFactory
|
|
===========================
|
|
|
|
Work in progress -- topics to include:
|
|
|
|
* Bfr::RefinerSurfaceFactory as an example
|
|
* Bfr::SurfaceFactoryCache and its thread-safety
|
|
* thread-safe declaration and usage of SurfaceFactory
|
|
* using an external SurfaceFactoryCache with multiple meshes
|
|
|
|
* serial
|
|
* parallel
|
|
|
|
----
|
|
|
|
.. _bfr-navlink-customizing:
|
|
|
|
Customizing a Bfr::SurfaceFactory
|
|
=================================
|
|
|
|
Work in progress -- topics to include:
|
|
|
|
* SurfaceFactory and Bfr::SurfaceFactoryMeshAdapter
|
|
* fulfilling the SurfaceFactoryMeshAdapter interface
|
|
|
|
* retrieving simple properties of a face
|
|
* retrieving indices at all face-vertices
|
|
* retrieving indices for the neighborhood around a face-vertex
|
|
* accelerated retrieval for regular face neighborhoods
|
|
|
|
* customizing a subclass of SurfaceFactory
|
|
|