diff --git a/documentation/images/far_tutorial_6.0.png b/documentation/images/far_tutorial_6.0.png new file mode 100644 index 00000000..cca45807 Binary files /dev/null and b/documentation/images/far_tutorial_6.0.png differ diff --git a/documentation/tutorials.rst b/documentation/tutorials.rst index aeb7aa6e..d2b62776 100644 --- a/documentation/tutorials.rst +++ b/documentation/tutorials.rst @@ -55,6 +55,10 @@ or in your local ``/turorials``. :width: 100px :target: images/far_tutorial_3.0.png +.. |far_tut_6| image:: images/far_tutorial_6.0.png + :width: 100px + :target: images/far_tutorial_6.0.png + .. list-table:: **Far Tutorials** :class: quickref :widths: 50 50 @@ -77,11 +81,11 @@ or in your local ``/turorials``. | |far_tut_1| | - | **Tutorial 3** - | Building on tutorial 0, this example shows how to instantiate a simple mesh, - refine it uniformly and then interpolate both 'vertex' and 'face-varying' - primvar data. - The resulting interpolated data is output as an 'obj' file, with the - 'face-varying' data recorded in the uv texture layout. + | Building on tutorial 0, this example shows how to instantiate a simple mesh, + refine it uniformly and then interpolate both 'vertex' and 'face-varying' + primvar data. + The resulting interpolated data is output as an 'obj' file, with the + 'face-varying' data recorded in the uv texture layout. | |far_tut_3| | | **Tutorial 4** @@ -93,6 +97,11 @@ or in your local ``/turorials``. FarStencilTables to interpolate 2 primvar data buffers: vertex positions and vertex colors. | + | **Tutorial 6** + | This tutorial shows how to interpolate surface limits at arbitrary + parametric locations using feature adaptive Far::PatchTables. + | |far_tut_6| + | ---- diff --git a/opensubdiv/far/patchTables.h b/opensubdiv/far/patchTables.h index 35007236..3588ab4a 100644 --- a/opensubdiv/far/patchTables.h +++ b/opensubdiv/far/patchTables.h @@ -480,7 +480,7 @@ public: /// /// @param dst Destination primvar buffer (limit surface data) /// - template void Interpolate(PatchHandle const & handle, + template void Limit(PatchHandle const & handle, float s, float t, T const src, U * dst) const; @@ -923,7 +923,7 @@ InterpolateCornerPatch(unsigned int const * cvs, // Interpolates the limit position of a parametric location on a patch template inline void -PatchTables::Interpolate(PatchHandle const & handle, float s, float t, +PatchTables::Limit(PatchHandle const & handle, float s, float t, T const src, U * dst) const { assert(dst); diff --git a/opensubdiv/far/stencilTablesFactory.cpp b/opensubdiv/far/stencilTablesFactory.cpp index 3d0b6f80..20542353 100644 --- a/opensubdiv/far/stencilTablesFactory.cpp +++ b/opensubdiv/far/stencilTablesFactory.cpp @@ -976,7 +976,7 @@ LimitStencilTablesFactory::Create(TopologyRefiner const & refiner, ProtoLimitStencil & dst = alloc.GetLimitStencils()[currentStencil]; - patchTables.Interpolate(*handle, s, t, *cvStencils, &dst); + patchTables.Limit(*handle, s, t, *cvStencils, &dst); ++numLimitStencils; } diff --git a/tutorials/far/CMakeLists.txt b/tutorials/far/CMakeLists.txt index 6577243c..c5d20bd0 100644 --- a/tutorials/far/CMakeLists.txt +++ b/tutorials/far/CMakeLists.txt @@ -29,6 +29,7 @@ set(TUTORIALS tutorial_3 tutorial_4 tutorial_5 + tutorial_6 ) foreach(tutorial ${TUTORIALS}) diff --git a/tutorials/far/tutorial_6/CMakeLists.txt b/tutorials/far/tutorial_6/CMakeLists.txt new file mode 100644 index 00000000..f2fa7860 --- /dev/null +++ b/tutorials/far/tutorial_6/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# 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. +# + +include_directories("${PROJECT_SOURCE_DIR}/opensubdiv") + +set(SOURCE_FILES + far_tutorial_6.cpp +) + +_add_executable(far_tutorial_6 + ${SOURCE_FILES} + $ + $ + $ +) + +install(TARGETS far_tutorial_6 DESTINATION "${CMAKE_BINDIR_BASE}/tutorials") + diff --git a/tutorials/far/tutorial_6/far_tutorial_6.cpp b/tutorials/far/tutorial_6/far_tutorial_6.cpp new file mode 100644 index 00000000..25708db5 --- /dev/null +++ b/tutorials/far/tutorial_6/far_tutorial_6.cpp @@ -0,0 +1,263 @@ +// +// 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. +// + + +//------------------------------------------------------------------------------ +// Tutorial description: +// +// This tutorial shows how to interpolate surface limits at arbitrary +// parametric locations using feature adaptive Far::PatchTables. +// +// The evaluation of the limit surface at arbitrary locations requires the +// adaptive isolation of topological features. This process converts the +// input polygonal control cage into a collection of bi-cubic patches. +// +// We can then evaluate the patches are random parametric locations and +// obtain analytical positions and tangents on the limit surface. +// +// The results are dumped into a MEL script that draws 'streak' particle +// systems that show the tangent and bi-tangent at the random samples locations. +// + +#include +#include +#include + +#include +#include +#include +#include + +using namespace OpenSubdiv; + +// pyramid geometry from catmark_pyramid_crease0.h +static int const g_nverts = 5; +static float const g_verts[24] = { 0.0f, 0.0f, 2.0f, + 0.0f, -2.0f, 0.0f, + 2.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, + -2.0f, 0.0f, 0.0f, }; + + +static int const g_vertsperface[5] = { 3, 3, 3, 3, 4 }; + +static int const g_nfaces = 5; +static int const g_faceverts[16] = { 0, 1, 2, + 0, 2, 3, + 0, 3, 4, + 0, 4, 1, + 4, 3, 2, 1 }; + +static int const g_ncreases = 4; +static int const g_creaseverts[8] = { 4, 3, 3, 2, 2, 1, 1, 4 }; +static float const g_creaseweights[4] = { 3.0f, 3.0f, 3.0f, 3.0f }; + +// Creates a Far::TopologyRefiner from the pyramid shape above +static Far::TopologyRefiner * createTopologyRefiner(); + +//------------------------------------------------------------------------------ +// Vertex container implementation. +// +struct Vertex { + + // Minimal required interface ---------------------- + Vertex() { } + + void Clear( void * =0 ) { + point[0] = point[1] = point[2] = 0.0f; + } + + void AddWithWeight(Vertex const & src, float weight) { + point[0] += weight * src.point[0]; + point[1] += weight * src.point[1]; + point[2] += weight * src.point[2]; + } + + void AddVaryingWithWeight(Vertex const &, float) { } + + float point[3]; +}; + +//------------------------------------------------------------------------------ +// Limit frame container implementation. +// +struct LimitFrame { + + void Clear( void * =0 ) { + point[0] = point[1] = point[2] = 0.0f; + deriv1[0] = deriv1[1] = deriv1[2] = 0.0f; + deriv2[0] = deriv2[1] = deriv2[2] = 0.0f; + } + + void AddWithWeight(Vertex const & src, + float weight, float d1Weight, float d2Weight) { + + point[0] += weight * src.point[0]; + point[1] += weight * src.point[1]; + point[2] += weight * src.point[2]; + + deriv1[0] += d1Weight * src.point[0]; + deriv1[1] += d1Weight * src.point[1]; + deriv1[2] += d1Weight * src.point[2]; + + deriv2[0] += d2Weight * src.point[0]; + deriv2[1] += d2Weight * src.point[1]; + deriv2[2] += d2Weight * src.point[2]; + } + + float point[3], + deriv1[3], + deriv2[3]; +}; + +//------------------------------------------------------------------------------ +int main(int, char **) { + + // Generate a FarTopologyRefiner (see far_tutorial_0 for details). + Far::TopologyRefiner * refiner = createTopologyRefiner(); + + // Adaptively refine the topology with an isolation level capped at 3 + // because the sharpest crease in the shape is 3.0f (in g_creaseweights[]) + int maxIsolation = 3; + refiner->RefineAdaptive(maxIsolation); + + + // Create a buffer to hold the position of the + std::vector verts(refiner->GetNumVerticesTotal()); + memcpy(&verts[0], g_verts, g_nverts*3*sizeof(float)); + + // Interpolate vertex primvar data : they are the control vertices + // of the limit patches (see far_tutorial_0 for details) + refiner->Interpolate(&verts[0], &verts[g_nverts]); + + + // Generate a set of Far::PatchTables that we will use to evaluate the + // surface limit + Far::PatchTables const * patchTables = + Far::PatchTablesFactory::Create(*refiner); + + // Create a Far::PatchMap to help locating patches in the table + Far::PatchMap patchmap(*patchTables); + + + // Generate random samples on each ptex face + int nsamples = 200, + nfaces = refiner->GetNumPtexFaces(); + + std::vector samples(nsamples * nfaces); + + srand( static_cast(2147483647) ); + + for (int face=0, count=0; faceLimit(*handle, s, t, &verts[0], &samples[count]); + } + } + + { // Visualization with Maya : print a MEL script that generates particles + // at the location of the limit vertices + + int nsamples = (int)samples.size(); + + printf("file -f -new;\n"); + + // Output particle positions for the tangent + printf("particle -n deriv1 "); + for (int sample=0; sample::Create(type, options, desc); + + return refiner; +}