mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-26 13:30: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
|
||||
: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 ``<repository root>/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 ``<repository root>/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|
|
||||
|
|
||||
|
||||
----
|
||||
|
||||
|
@ -480,7 +480,7 @@ public:
|
||||
///
|
||||
/// @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;
|
||||
|
||||
|
||||
@ -923,7 +923,7 @@ InterpolateCornerPatch(unsigned int const * cvs,
|
||||
// Interpolates the limit position of a parametric location on a patch
|
||||
template <class T, class U>
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ set(TUTORIALS
|
||||
tutorial_3
|
||||
tutorial_4
|
||||
tutorial_5
|
||||
tutorial_6
|
||||
)
|
||||
|
||||
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