mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-02 00:00:07 +00:00
1294e1b0c1
This updates much of the initial overview documentation to make a clearer distinction between topology refinement and primvar refinement and describes the different classes and methods that are used.
586 lines
26 KiB
ReStructuredText
586 lines
26 KiB
ReStructuredText
..
|
|
Copyright 2013 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.
|
|
|
|
|
|
FAR Overview
|
|
------------
|
|
|
|
.. contents::
|
|
:local:
|
|
:backlinks: none
|
|
|
|
.. image:: images/api_layers_3_0.png
|
|
:width: 100px
|
|
:target: images/api_layers_3_0.png
|
|
|
|
Feature Adaptive Representation (Far)
|
|
=====================================
|
|
|
|
*Far* is the primary API layer for processing client-supplied mesh data
|
|
into subdivided surfaces.
|
|
|
|
The *Far* interface may be used directly and also may be used to prepare
|
|
mesh data for further processing by `Osd <osd_overview.html#Osd>`__.
|
|
|
|
The two main aspects of the subdivision process are *Topology Refinement*
|
|
and *Primvar Refinement*.
|
|
|
|
Topology Refinement
|
|
*******************
|
|
|
|
Topology refinement is the process of splitting the mesh topology
|
|
according to the specified subdivison rules to generate new topological
|
|
vertices, edges, and faces. This process is purely topological and does
|
|
not depend on the speciific values of any primvar data (point positions, etc).
|
|
|
|
Topology refinement can be either uniform or adaptive, where extraordinary
|
|
features are automatically isolated (see `feature adaptive subdivision <subdivision_surfaces.html#feature-adaptive-subdivision>`__).
|
|
|
|
The *Far* topology classes present a public interface for the refinement
|
|
functionality provided in `Vtr <vtr_overview.html#Vtr>`__,
|
|
|
|
The main classes in *Far* related to topology refinement are:
|
|
|
|
+-------------------------------+---------------------------------------------+
|
|
| TopologyRefiner | A class encapsulating mesh refinement. |
|
|
+-------------------------------+---------------------------------------------+
|
|
| TopologyLevel | A class representing one level of |
|
|
| | refinement within a TopologyRefiner. |
|
|
+-------------------------------+---------------------------------------------+
|
|
| TopologyRefinerFactory<MESH> | A factory class template specialized in |
|
|
| | terms of the application's mesh |
|
|
| | representation used to construct |
|
|
| | TopologyRefiner instances. |
|
|
+-------------------------------+---------------------------------------------+
|
|
|
|
Primvar Refinement
|
|
******************
|
|
|
|
Primvar refinement is the process of computing values for primvar data (points,
|
|
colors, normals, texture coordinates, etc) by applying weights determined by
|
|
the specified subdivision rules. There are many advantages gained by
|
|
distinguishing between topology refinement and primvar interpolation
|
|
including the ability to apply a single static topological refinement to
|
|
multiple primvar instances or to different animated primvar time samples.
|
|
|
|
*Far* supports methods to refine primvar data at the locations of topological
|
|
vertices and at arbitrary locations on the subdivision limit surface.
|
|
|
|
The main classes in *Far* related to primvar refinement are:
|
|
|
|
+-----------------------+--------------------------------------------------+
|
|
| PrimvarRefiner | A class implementing refinement of primvar data |
|
|
| | at the locations of topological vertices. |
|
|
+-----------------------+--------------------------------------------------+
|
|
| PatchTable | A representation of the refined surface topology |
|
|
| | that can be used for efficient evaluation of |
|
|
| | primvar data at arbitrary locations. |
|
|
+-----------------------+--------------------------------------------------+
|
|
| StencilTable | A representation of refinement weights suitable |
|
|
| | for efficient parallel processing of primvar |
|
|
| | refinement. |
|
|
+-----------------------+--------------------------------------------------+
|
|
| LimitStencilTable | A representation of refinement weights suitable |
|
|
| | for efficient parallel processing of primvar |
|
|
| | refinement at arbitrary limit surface locations. |
|
|
+-----------------------+--------------------------------------------------+
|
|
|
|
Far::TopologyRefiner
|
|
====================
|
|
|
|
TopologyRefiner is the building block for many other useful classes in
|
|
*Far*. It performs refinement of an arbitrary mesh and provides access to
|
|
the refined mesh topology. It can be used for primvar refinement directly
|
|
using PrimvarRefiner or indirectly by being used to create
|
|
`stencil table <#patch-table>`__, `patch table <#patch-table>`__, etc.
|
|
|
|
TopologyRefiner has public the refinement methods
|
|
*RefineUniform()* and *RefineAdapative()* which perform refinement
|
|
operations using Vtr and provides access to the refined topology via
|
|
TopologyLevel instances.
|
|
|
|
.. image:: images/topology_refiner.png
|
|
:align: center
|
|
|
|
Far::TopologyRefinerFactory
|
|
===========================
|
|
|
|
Consistent with other classes in Far, instances of TopologyRefiner are created
|
|
by a factory class -- in this case Far::TopologyRefinerFactory. This class
|
|
is an important entry point for clients its task is to map/convert data in a
|
|
client's mesh into the internal `Vtr <vtr_overview.html>`__ representation as
|
|
quickly as possible.
|
|
|
|
The TopologyRefinerFactory class is a class template parameterized by and
|
|
specialized for the client's mesh class, i.e. TopologyRefinerFactory<MESH>.
|
|
Since a client' mesh representation knows best how to identify the topological
|
|
neighborhoods required, no generic implementation would provide the most
|
|
direct means of conversion possible, and so we rely on specialization. For
|
|
situations where mesh data is not defined in a boundary representation, a
|
|
simple container for raw mesh data is provided (TopologyDescriptor) along
|
|
with a Factory specialized to construct TopologyRefiners from it.
|
|
|
|
So there are two ways to create TopologyRefiners:
|
|
|
|
* use the existing TopologyRefinerFactory<TopologyDescriptor> with a
|
|
populated instance of TopologyDescriptor
|
|
* specialize TopologyRefinerFactory<class MESH> for more efficient
|
|
conversion
|
|
|
|
TopologyDescriptor is a simple struct with pointers to raw mesh data in a
|
|
form common to mesh constructors. Topologically, the minimal requirement
|
|
consists of:
|
|
|
|
* the number of vertices and faces of the mesh
|
|
* an array containing the number of vertices per face
|
|
* an array containing the vertices assigned to each face
|
|
|
|
These last two define one of the six topological relations that are needed
|
|
internally by Vtr, but this one relation is sufficient to construct the rest.
|
|
Additional members are available to assign sharpness values per edge and/or
|
|
vertex, hole tags to faces, or to define multiple sets (channels) of
|
|
face-varying data.
|
|
|
|
Specialization of TopologyRefinerFactory<class MESH> should be done with care
|
|
as the goal here is to maximize the performance of the conversion and so
|
|
minimize overhead due to runtime validation. The template provides the
|
|
high-level construction of the required topology vectors of the underlying
|
|
Vtr. It requires the specification/specialization of two methods with the
|
|
following purpose:
|
|
|
|
* specify the sizes of topological data so that vectors can be pre-allocated
|
|
* assign the topological data to the newly allocated vectors
|
|
|
|
As noted above, the assumption here is that the client's boundary-rep knows best
|
|
how to retrieve the data that we require most efficiently. After the factory class
|
|
gathers sizing information and allocates appropriate memory, the factory provides
|
|
the client with locations of the appropriate tables to be populated (using the
|
|
same `Array <vtr_overview.html#arry-type>`__ classes and interface used to access
|
|
the tables). The client is expected to load a complete topological description
|
|
along with additional optional data, i.e.:
|
|
|
|
* the six topological relations required by Vtr, oriented when manifold
|
|
* sharpness values for edges and/or vertices (optional)
|
|
* additional tags related to the components, e.g. holes (optional)
|
|
* values-per-face for face-varying channels (optional)
|
|
|
|
While there is plenty of opportunity for user error here, that is no different
|
|
from any other conversion process. Given that Far controls the construction
|
|
process through the Factory class, we do have ample opportunity to insert
|
|
runtime validation, and to vary that level of validation at any time on an
|
|
instance of the Factory.
|
|
|
|
A common base class has been created for the factory class, i.e.:
|
|
|
|
.. code:: c++
|
|
|
|
template <class MESH>
|
|
class TopologyRefinerFactory : public TopologyRefinerFactoryBase
|
|
|
|
both to provide common code independent of <MESH> and also potentially to
|
|
protect core code from unwanted specialization.
|
|
|
|
Far::PrimvarRefiner
|
|
===================
|
|
|
|
PrimvarRefiner supports refinement of arbitrary primvar data at the locations
|
|
of topological vertices. A PrimvarRefiner accesses topology data directly
|
|
from a TopologyRefiner.
|
|
|
|
Different methods are provided to support three different classes of primvar
|
|
interpolation. These methods may be used to refine primvar data to a specified
|
|
refinement level.
|
|
|
|
+-------------------------------+-------------------------------------------+
|
|
| Interpolate(...) | Interpolate using vertex weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
| InterpolateVarying(...) | Interpolate using linear weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
| InterpolateFaceVarying(...) | Interpolate using face-varying weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
|
|
Additional methods allow primvar data to be interpolated to the final limit
|
|
surface including the calculation of first derivative tangents.
|
|
|
|
+-------------------------------+-------------------------------------------+
|
|
| Limit(dst) | Interpolate to the limit surface using |
|
|
| | vertex weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
| Limit(dst, dstTan1, dstTan2) | Interpolate including first derivatives |
|
|
| | to the limit surface using vertex weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
| LimitFaceVarying(...) | Interpolate to the limit surface using |
|
|
| | face-varying weights |
|
|
+-------------------------------+-------------------------------------------+
|
|
|
|
PrimarRefiner provides a straightforward interface for refining primvar data,
|
|
but depending on the application use case, it can be more efficient to create
|
|
and use a `StencilTable <#patch-table>`__, or `PatchTable <#patch-table>`__,
|
|
to refine primvar data.
|
|
|
|
Far::PatchTable
|
|
================
|
|
|
|
The patch table is a serialized topology representation. This container is
|
|
generated using *Far::PatchTableFactory* from an instance
|
|
*Far::TopologyRefiner* after a refinement has been applied. The
|
|
FarPatchTableFactory traverses the data-structures of the TopologyRefiner and
|
|
serializes the sub-faces into collections of bi-linear and bi-cubic patches as
|
|
dictated by the refinement mode (uniform or adaptive). The patches are then
|
|
sorted into arrays based on their types.
|
|
|
|
.. container:: notebox
|
|
|
|
**Release Notes (3.0.0)**
|
|
|
|
The organization and API of Far::PatchTable is likely to change
|
|
in the 3.1 release to accommodate additional functionality including:
|
|
smooth face-varying interpolation on patches, and dynamic feature
|
|
adaptive isolation (DFAS), and patch evaluation of Loop subdivision
|
|
surfaces.
|
|
|
|
Patch Arrays
|
|
************
|
|
|
|
The patch table is a collection of control vertex indices. Meshes are decomposed
|
|
into a collection of patches, which can be of different types. Each type
|
|
has different requirements for the internal organization of its
|
|
control-vertices. A PatchArray contains a sequence of multiple patches that
|
|
share a common set of attributes.
|
|
|
|
While all patches in a PatchArray will have the same type, each patch in the
|
|
array is associated with a distinct *PatchParam* which specifies additional
|
|
information about the individual patch.
|
|
|
|
Each PatchArray contains a patch *Descriptor* that provides the fundamental
|
|
description of the patches in the array.
|
|
|
|
The PatchArray *ArrayRange* provides the indices necessary to track the records
|
|
of individual patches in the table.
|
|
|
|
.. image:: images/far_patchtables.png
|
|
:align: center
|
|
:target: images/far_patchtables.png
|
|
|
|
Patch Types
|
|
***********
|
|
|
|
The following are the different patch types that can be represented in the
|
|
PatchTable:
|
|
|
|
+---------------------+------+---------------------------------------------+
|
|
| Patch Type | #CVs | Description |
|
|
+=====================+======+=============================================+
|
|
| NON_PATCH | n/a | *"Undefined"* patch type |
|
|
+---------------------+------+---------------------------------------------+
|
|
| POINTS | 1 | Points : useful for cage drawing |
|
|
+---------------------+------+---------------------------------------------+
|
|
| LINES | 2 | Lines : useful for cage drawing |
|
|
+---------------------+------+---------------------------------------------+
|
|
| QUADS | 4 | Bi-linear quads-only patches |
|
|
+---------------------+------+---------------------------------------------+
|
|
| TRIANGLES | 3 | Bi-linear triangles-only mesh |
|
|
+---------------------+------+---------------------------------------------+
|
|
| LOOP | n/a | Loop patch (currently unsupported) |
|
|
+---------------------+------+---------------------------------------------+
|
|
| REGULAR | 16 | B-spline Basis patches |
|
|
+---------------------+------+---------------------------------------------+
|
|
| GREGORY | 4 | Legacy Gregory patches |
|
|
+---------------------+------+---------------------------------------------+
|
|
| GREGORY_BOUNDARY | 4 | Legacy Gregory Boundary patches |
|
|
+---------------------+------+---------------------------------------------+
|
|
| GREGORY_BASIS | 20 | Gregory Basis patches |
|
|
+---------------------+------+---------------------------------------------+
|
|
|
|
|
|
The type of a patch dictates the number of control vertices expected in the
|
|
table as well as the method used to evaluate values.
|
|
|
|
Patch Parameterization
|
|
**********************
|
|
|
|
Each patch represents a specific portion of the parametric space of the
|
|
coarse topological face identified by the PatchParam FaceId. As topological
|
|
refinement progresses through successive levels, each resulting patch
|
|
corresponds to a smaller and smaller subdomain of the face.
|
|
The PatchParam UV origin describes the mapping from the uv domain of the
|
|
patch to the uv subdomain of the topological face. We encode this uv
|
|
origin using log2 integer values for compactness and efficiency.
|
|
|
|
It is important to note that this uv parameterization is the intrinsic
|
|
parameterization within a given patch or coarse face and is distinct
|
|
from any client specified face-varying channel data.
|
|
|
|
Patches which result from irregular coarse faces (non-quad faces in the
|
|
Catmark scheme, or non-trianglular faces in the Loop scheme) are offset
|
|
by the one additional level needed to "quadrangulate" or "triangulate"
|
|
the irregular face.
|
|
|
|
.. image:: images/far_patchUV.png
|
|
:align: center
|
|
:target: images/far_patchUV.png
|
|
|
|
A patch along an interpolated boundary edge is supported by an incomplete
|
|
sets of control vertices. For consistency, patches in the PatchTable always
|
|
have a full set of control vertex indices and the PatchParam Boundary bitmask
|
|
identifies which control vertices are incomplete (the incomplete control
|
|
vertex indices are assigned values which duplicate the first valid index).
|
|
Each bit in the boundary bitmask corresponds to one edge of the patch
|
|
starting from the edge from the first vertex and continuing around the
|
|
patch. With feature adaptive refinement, regular B-spline basis patches
|
|
along interpolated boundaries will fall into one of the eight cases
|
|
(four boundary and four corner) illustrated below:
|
|
|
|
.. image:: images/far_patchBoundary.png
|
|
:align: center
|
|
:target: images/far_patchBoundary.png
|
|
|
|
Transition edges occur during feature adaptive refinement where a patch
|
|
at one level of refinement is adjacent to pairs of patches at the next
|
|
level of refinement. These T-junctions do not pose a problem when evaluating
|
|
primvar data on patches, but they must be taken into consideration when
|
|
tessellating patches (e.g. while drawing) in order to avoid cracks.
|
|
The PatchParam Transition bitmask identifies the transition edges of
|
|
a patch. Each bit in the bitmask corresponds to one edge of the patch
|
|
just like the encoding of boundary edges.
|
|
|
|
After refining an arbitrary mesh, any of the 16 possible transition edge
|
|
configurations might occur. The method of handling transition edges is
|
|
delegated to patch drawing code.
|
|
|
|
.. image:: images/far_patchTransition.png
|
|
:align: center
|
|
:target: images/far_patchTransition.png
|
|
|
|
Single-Crease Patches
|
|
**************************
|
|
|
|
Using single-crease patches allows a mesh with creases to be represented
|
|
with many fewer patches than would be needed otherwise. A single-crease
|
|
patch is a variation of a regular BSpline patch with one additional crease
|
|
sharpness parameter.
|
|
|
|
.. container:: notebox
|
|
|
|
**Release Notes (3.0.0)**
|
|
|
|
Currently, the crease sharpness parameter is encoded as a separate
|
|
PatchArray within the PatchTable. This parameter may be combined
|
|
with the other PatchParam values in future releases. Also, evaluation
|
|
of single-crease patches is currently only implemented for OSD patch
|
|
drawing, but we expect to implement support in all of the evaluation
|
|
code paths for future releases.
|
|
|
|
Local Points
|
|
************
|
|
|
|
The control vertices represented by a PatchTable are primarily refined points,
|
|
i.e. points which result from applying the subdivision scheme uniformly or
|
|
adaptively to the points of the coarse mesh. However, the final patches
|
|
generated from irregular faces, e.g. patches incident on an extraordinary
|
|
vertex might have a representation which requires additional local points.
|
|
|
|
.. container:: notebox
|
|
|
|
**Release Notes (3.0.0)**
|
|
|
|
Currently, representations which require local points also require
|
|
the use of a StencilTable to compute the values of local points.
|
|
This requirement, as well as the rest of the API related to local
|
|
points may change in future releases.
|
|
|
|
Legacy Gregory Patches
|
|
**********************
|
|
|
|
Using Gregory patches to approximate the surface at the final patches
|
|
generated from irregular faces is an alternative representation which does
|
|
not require any additional local points to be computed. Instead, when
|
|
Legacy Gregory patches are used, the PatchTable must also have an alternative
|
|
representation of the mesh topology encoded as a vertex valence table
|
|
and a quad offsets table.
|
|
|
|
.. container:: notebox
|
|
|
|
**Release Notes (3.0.0)**
|
|
|
|
The encoding and support for Legacy Gregory patches may change
|
|
in future releases. The current encoding of the vertex valence
|
|
and quad offsets tables may be prohibitively expensive for some
|
|
use cases.
|
|
|
|
Far::StencilTable
|
|
==================
|
|
|
|
The base container for stencil data is the StencilTable class. As with most
|
|
other Far entities, it has an associated StencilTableFactory that requires a
|
|
TopologyRefiner:
|
|
|
|
Advantages
|
|
**********
|
|
|
|
Stencils are used to factorize the interpolation calculations that subdivision
|
|
schema apply to vertices of smooth surfaces. If the topology being subdivided
|
|
remains constant, factorizing the subdivision weights into stencils during a
|
|
pre-compute pass yields substantial amortizations at run-time when re-posing
|
|
the control cage.
|
|
|
|
Factorizing the subdivision weights also allows to express each subdivided
|
|
vertex as a weighted sum of vertices from the control cage. This step effectively
|
|
removes any data inter-dependency between subdivided vertices : the computations
|
|
of subdivision interpolation can be applied to each vertex in parallel without
|
|
any barriers or constraint. The Osd::Compute module leverages these properties
|
|
on massively parallel GPU architectures to great effect.
|
|
|
|
.. image:: images/far_stencil5.png
|
|
:align: center
|
|
|
|
Principles
|
|
**********
|
|
|
|
Iterative subdivision algorithms converge towards the limit surface by
|
|
successively refining the vertices of the coarse control cage. Each successive
|
|
iteration interpolates the new vertices by applying polynomial weights to a
|
|
*basis of supporting vertices*.
|
|
|
|
The interpolation calculations for any given vertex can be broken down into
|
|
sequences of multiply-add operations applied to the supporting vertices.
|
|
Stencil table encodes a factorization of these weighted sums : each stencils is
|
|
created by combining the list of control vertices from the 1-ring.
|
|
|
|
With iterative subdivision, each refinement step is dependent upon the previous
|
|
subdivision step being completed, and a substantial number of steps may be
|
|
required in order approximate the limit : each subdivision step incurs an
|
|
O(4\ :superscript:`n`) growing amount of computations.
|
|
|
|
Instead, once the weights of the contributing coarse control vertices for a
|
|
given refined vertex have been factorized, it is possible to apply the stencil
|
|
and directly obtain the interpolated vertex data without having to process the
|
|
data for the intermediate refinement levels.
|
|
|
|
.. image:: images/far_stencil7.png
|
|
:align: center
|
|
|
|
Cascading Stencils
|
|
******************
|
|
|
|
Client-code can control the amount of factorization of the stencils : the tables can be
|
|
generated with contributions all the way from a basis of coarse vertices, or
|
|
reduced only to contributions from vertices from the previous level of
|
|
refinement.
|
|
|
|
The latter mode allows client-code to access and insert modifications to the
|
|
vertex data at set refinement levels (see `hierarchical vertex edits
|
|
<subdivision_surfaces.html#hierarchical-edits>`_). Once the edits have been
|
|
applied by the client-code, another set of stencils can be used to smoothe the
|
|
vertex data to a higher level of refinement.
|
|
|
|
.. image:: images/far_stencil8.png
|
|
:align: center
|
|
|
|
See implementation details, see the Far cascading stencil `tutorial
|
|
<tutorials.html>`_
|
|
|
|
Limit Stencils
|
|
**************
|
|
|
|
Stencil tables can be trivially extended from discrete subdivided vertices to
|
|
arbitrary locations on the limit surface. Aside from extraordinary points, every
|
|
location on the limit surface can be expressed as a closed-form weighted
|
|
average of a set of coarse control vertices from the 1-ring surrounding the
|
|
face.
|
|
|
|
The weight accumulation process is similar : the control cage is adaptively
|
|
subdivided around extraordinary locations. A stencil is then generated for each
|
|
limit location simply by factorizing the bi-cubic Bspline patch weights over
|
|
those of the contributing basis of control-vertices.
|
|
|
|
The use of bi-cubic patches also allows the accumulation of analytical
|
|
derivatives, so limit stencils carry a set of weights for tangent vectors.
|
|
|
|
.. image:: images/far_stencil0.png
|
|
:align: center
|
|
|
|
Once the stencil table has been generated, limit stencils are the most direct
|
|
and efficient method of evaluation of specific locations on the limit of a
|
|
subdivision surface, starting from the coarse vertices of the control cage.
|
|
|
|
Also: just as discrete stencils, limit stencils that are factorized from coarse
|
|
control vertices do not have inter-dependencies and can be evaluated in
|
|
parallel.
|
|
|
|
For implementation details, see the `glStencilViewer <glStencilViewer.html>`_
|
|
code example.
|
|
|
|
Sample Location On Extraordinary Faces
|
|
**************************************
|
|
|
|
Each stencil is associated with a singular parametric location on the coarse
|
|
mesh. The parametric location is defined as face location and local [0.0 - 1.0]
|
|
(u,v) triplet:
|
|
|
|
In the case of face that are not quads, a parametric sub-face quadrant needs to
|
|
be identified. This can be done either explicitly or implicitly by using the
|
|
unique ptex face indices for instance.
|
|
|
|
.. image:: images/far_stencil6.png
|
|
:align: center
|
|
|
|
Code example
|
|
************
|
|
|
|
When the control vertices (controlPoints) move in space, the limit locations can
|
|
be very efficiently recomputed simply by applying the blending weights to the
|
|
series of coarse control vertices:
|
|
|
|
.. code:: c++
|
|
|
|
class StencilType {
|
|
public:
|
|
|
|
void Clear() {
|
|
memset( &x, 0, sizeof(StencilType));
|
|
}
|
|
|
|
void AddWithWeight( StencilType const & cv, float weight ) {
|
|
x += cv.x * weight;
|
|
y += cv.y * weight;
|
|
z += cv.z * weight;
|
|
}
|
|
|
|
float x,y,z;
|
|
};
|
|
|
|
std::vector<StencilType> controlPoints,
|
|
points,
|
|
utan,
|
|
vtan;
|
|
|
|
// Update points by applying stencils
|
|
controlStencils.UpdateValues<StencilType>( reinterpret_cast<StencilType const *>(
|
|
&controlPoints[0]), &points[0] );
|
|
|
|
// Update tangents by applying derivative stencils
|
|
controlStencils.UpdateDerivs<StencilType>( reinterpret_cast<StencilType const *>(
|
|
&controlPoints[0]), &utan[0], &vtan[0] );
|
|
|