mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-30 07:10:07 +00:00
Add far_tutorial_6 showing how to interpolate primvar data on the surface
limit at arbitrary locations.
This commit is contained in:
parent
09789296d9
commit
f7b21b941c
BIN
documentation/images/far_tutorial_6.0.png
Normal file
BIN
documentation/images/far_tutorial_6.0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 KiB |
@ -55,6 +55,10 @@ or in your local ``<repository root>/turorials``.
|
|||||||
:width: 100px
|
:width: 100px
|
||||||
:target: images/far_tutorial_3.0.png
|
: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**
|
.. list-table:: **Far Tutorials**
|
||||||
:class: quickref
|
:class: quickref
|
||||||
:widths: 50 50
|
:widths: 50 50
|
||||||
@ -93,6 +97,11 @@ or in your local ``<repository root>/turorials``.
|
|||||||
FarStencilTables to interpolate 2 primvar data buffers: vertex positions and
|
FarStencilTables to interpolate 2 primvar data buffers: vertex positions and
|
||||||
vertex colors.
|
vertex colors.
|
||||||
|
|
|
|
||||||
|
| **Tutorial 6**
|
||||||
|
| This tutorial shows how to interpolate surface limits at arbitrary
|
||||||
|
parametric locations using feature adaptive Far::PatchTables.
|
||||||
|
| |far_tut_6|
|
||||||
|
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @param dst Destination primvar buffer (limit surface data)
|
/// @param dst Destination primvar buffer (limit surface data)
|
||||||
///
|
///
|
||||||
template <class T, class U> void Interpolate(PatchHandle const & handle,
|
template <class T, class U> void Limit(PatchHandle const & handle,
|
||||||
float s, float t, T const src, U * dst) const;
|
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
|
// Interpolates the limit position of a parametric location on a patch
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline void
|
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 {
|
T const src, U * dst) const {
|
||||||
|
|
||||||
assert(dst);
|
assert(dst);
|
||||||
|
@ -976,7 +976,7 @@ LimitStencilTablesFactory::Create(TopologyRefiner const & refiner,
|
|||||||
ProtoLimitStencil & dst =
|
ProtoLimitStencil & dst =
|
||||||
alloc.GetLimitStencils()[currentStencil];
|
alloc.GetLimitStencils()[currentStencil];
|
||||||
|
|
||||||
patchTables.Interpolate(*handle, s, t, *cvStencils, &dst);
|
patchTables.Limit(*handle, s, t, *cvStencils, &dst);
|
||||||
|
|
||||||
++numLimitStencils;
|
++numLimitStencils;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ set(TUTORIALS
|
|||||||
tutorial_3
|
tutorial_3
|
||||||
tutorial_4
|
tutorial_4
|
||||||
tutorial_5
|
tutorial_5
|
||||||
|
tutorial_6
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach(tutorial ${TUTORIALS})
|
foreach(tutorial ${TUTORIALS})
|
||||||
|
39
tutorials/far/tutorial_6/CMakeLists.txt
Normal file
39
tutorials/far/tutorial_6/CMakeLists.txt
Normal file
@ -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}
|
||||||
|
$<TARGET_OBJECTS:sdc_obj>
|
||||||
|
$<TARGET_OBJECTS:vtr_obj>
|
||||||
|
$<TARGET_OBJECTS:far_obj>
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS far_tutorial_6 DESTINATION "${CMAKE_BINDIR_BASE}/tutorials")
|
||||||
|
|
263
tutorials/far/tutorial_6/far_tutorial_6.cpp
Normal file
263
tutorials/far/tutorial_6/far_tutorial_6.cpp
Normal file
@ -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 <far/topologyRefinerFactory.h>
|
||||||
|
#include <far/patchTablesFactory.h>
|
||||||
|
#include <far/patchMap.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
|
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<Vertex> 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<LimitFrame> samples(nsamples * nfaces);
|
||||||
|
|
||||||
|
srand( static_cast<int>(2147483647) );
|
||||||
|
|
||||||
|
for (int face=0, count=0; face<nfaces; ++face) {
|
||||||
|
|
||||||
|
for (int sample=0; sample<nsamples; ++sample, ++count) {
|
||||||
|
|
||||||
|
float s = (float)rand()/(float)RAND_MAX,
|
||||||
|
t = (float)rand()/(float)RAND_MAX;
|
||||||
|
|
||||||
|
// Locate the patch corresponding to the face ptex idx and (s,t)
|
||||||
|
Far::PatchTables::PatchHandle const * handle =
|
||||||
|
patchmap.FindPatch(face, s, t);
|
||||||
|
assert(handle);
|
||||||
|
|
||||||
|
// Evaluate the limit frame
|
||||||
|
patchTables->Limit(*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<nsamples; ++sample) {
|
||||||
|
float const * pos = samples[sample].point;
|
||||||
|
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||||
|
}
|
||||||
|
printf(";\n");
|
||||||
|
// Set per-particle direction using the limit tangent (display as 'Streak')
|
||||||
|
printf("setAttr \"deriv1.particleRenderType\" 6;\n");
|
||||||
|
printf("setAttr \"deriv1.velocity\" -type \"vectorArray\" %d ",nsamples);
|
||||||
|
for (int sample=0; sample<nsamples; ++sample) {
|
||||||
|
float const * tan1 = samples[sample].deriv1;
|
||||||
|
printf("%f %f %f\n", tan1[0], tan1[1], tan1[2]);
|
||||||
|
}
|
||||||
|
printf(";\n");
|
||||||
|
|
||||||
|
// Output particle positions for the bi-tangent
|
||||||
|
printf("particle -n deriv2 ");
|
||||||
|
for (int sample=0; sample<nsamples; ++sample) {
|
||||||
|
float const * pos = samples[sample].point;
|
||||||
|
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||||
|
}
|
||||||
|
printf(";\n");
|
||||||
|
printf("setAttr \"deriv2.particleRenderType\" 6;\n");
|
||||||
|
printf("setAttr \"deriv2.velocity\" -type \"vectorArray\" %d ",nsamples);
|
||||||
|
for (int sample=0; sample<nsamples; ++sample) {
|
||||||
|
float const * tan2 = samples[sample].deriv2;
|
||||||
|
printf("%f %f %f\n", tan2[0], tan2[1], tan2[2]);
|
||||||
|
}
|
||||||
|
printf(";\n");
|
||||||
|
|
||||||
|
// Exercise to the reader : cross tangent & bi-tangent for limit
|
||||||
|
// surface normal...
|
||||||
|
|
||||||
|
// Force Maya DAG update to see the result in the viewport
|
||||||
|
printf("currentTime -edit `currentTime -q`;\n");
|
||||||
|
printf("select deriv1Shape deriv2Shape;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static Far::TopologyRefiner *
|
||||||
|
createTopologyRefiner() {
|
||||||
|
|
||||||
|
|
||||||
|
typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor;
|
||||||
|
|
||||||
|
Sdc::Type type = OpenSubdiv::Sdc::TYPE_CATMARK;
|
||||||
|
|
||||||
|
Sdc::Options options;
|
||||||
|
options.SetVVarBoundaryInterpolation(Sdc::Options::VVAR_BOUNDARY_EDGE_ONLY);
|
||||||
|
|
||||||
|
Descriptor desc;
|
||||||
|
desc.numVertices = g_nverts;
|
||||||
|
desc.numFaces = g_nfaces;
|
||||||
|
desc.vertsPerFace = g_vertsperface;
|
||||||
|
desc.vertIndices = g_faceverts;
|
||||||
|
desc.numCreases = g_ncreases;
|
||||||
|
desc.creaseVertexIndexPairs = g_creaseverts;
|
||||||
|
desc.creaseWeights = g_creaseweights;
|
||||||
|
|
||||||
|
// Instantiate a FarTopologyRefiner from the descriptor.
|
||||||
|
Far::TopologyRefiner * refiner =
|
||||||
|
Far::TopologyRefinerFactory<Descriptor>::Create(type, options, desc);
|
||||||
|
|
||||||
|
return refiner;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user