Add Chromium-only Blender WebEngine parity work
This commit is contained in:
51
blender-5.2.0/extern/opensubdiv-source/tutorials/far/CMakeLists.txt
vendored
Normal file
51
blender-5.2.0/extern/opensubdiv-source/tutorials/far/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
macro(osd_add_far_tutorial NAME)
|
||||
|
||||
osd_add_executable(${NAME} "tutorials/far"
|
||||
${ARGN}
|
||||
$<TARGET_OBJECTS:sdc_obj>
|
||||
$<TARGET_OBJECTS:vtr_obj>
|
||||
$<TARGET_OBJECTS:far_obj>
|
||||
)
|
||||
|
||||
install(TARGETS ${NAME} DESTINATION "${CMAKE_BINDIR_BASE}/tutorials")
|
||||
|
||||
endmacro()
|
||||
|
||||
|
||||
set(TUTORIALS
|
||||
tutorial_1_1
|
||||
tutorial_1_2
|
||||
tutorial_2_1
|
||||
tutorial_2_2
|
||||
tutorial_2_3
|
||||
tutorial_3_1
|
||||
tutorial_4_1
|
||||
tutorial_4_2
|
||||
tutorial_4_3
|
||||
tutorial_5_1
|
||||
tutorial_5_2
|
||||
tutorial_5_3
|
||||
)
|
||||
|
||||
foreach(tutorial ${TUTORIALS})
|
||||
|
||||
add_subdirectory("${tutorial}")
|
||||
|
||||
list(APPEND TUTORIAL_TARGETS "far_${tutorial}")
|
||||
|
||||
add_test(far_${tutorial} ${EXECUTABLE_OUTPUT_PATH}/far_${tutorial})
|
||||
|
||||
endforeach()
|
||||
|
||||
add_custom_target(far_tutorials DEPENDS ${TUTORIAL_TARGETS})
|
||||
|
||||
set_target_properties(far_tutorials
|
||||
PROPERTIES
|
||||
FOLDER "tutorials/far"
|
||||
)
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_1/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_1/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_1_1
|
||||
far_tutorial_1_1.cpp
|
||||
)
|
||||
173
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_1/far_tutorial_1_1.cpp
vendored
Normal file
173
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_1/far_tutorial_1_1.cpp
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial presents in a very succinct way the requisite steps to
|
||||
// instantiate and refine a mesh with Far from simple topological data.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex container implementation.
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_position[0] = src._position[0];
|
||||
_position[1] = src._position[1];
|
||||
_position[2] = src._position[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_position[0]=_position[1]=_position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_position[0]+=weight*src._position[0];
|
||||
_position[1]+=weight*src._position[1];
|
||||
_position[2]+=weight*src._position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
_position[0]=x;
|
||||
_position[1]=y;
|
||||
_position[2]=z;
|
||||
}
|
||||
|
||||
const float * GetPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
private:
|
||||
float _position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
static float g_verts[8][3] = {{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f }};
|
||||
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
// Populate a topology descriptor with our raw data
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor
|
||||
Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
int maxlevel = 2;
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
|
||||
// Allocate a buffer for vertex primvar data. The buffer length is set to
|
||||
// be the sum of all children vertices up to the highest level of refinement.
|
||||
std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
|
||||
Vertex * verts = &vbuffer[0];
|
||||
|
||||
|
||||
// Initialize coarse mesh positions
|
||||
int nCoarseVerts = g_nverts;
|
||||
for (int i=0; i<nCoarseVerts; ++i) {
|
||||
verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
}
|
||||
|
||||
|
||||
// Interpolate vertex primvar data
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
Vertex * src = verts;
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices();
|
||||
primvarRefiner.Interpolate(level, src, dst);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
|
||||
{ // Output OBJ of the highest level refined -----------
|
||||
|
||||
Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);
|
||||
|
||||
int nverts = refLastLevel.GetNumVertices();
|
||||
int nfaces = refLastLevel.GetNumFaces();
|
||||
|
||||
// Print vertex positions
|
||||
int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;
|
||||
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = verts[firstOfLastVerts + vert].GetPosition();
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
// Print faces
|
||||
for (int face = 0; face < nfaces; ++face) {
|
||||
|
||||
Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
|
||||
|
||||
// all refined Catmark faces should be quads
|
||||
assert(fverts.size()==4);
|
||||
|
||||
printf("f ");
|
||||
for (int vert=0; vert<fverts.size(); ++vert) {
|
||||
printf("%d ", fverts[vert]+1); // OBJ uses 1-based arrays...
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_2/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_2/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_1_2
|
||||
far_tutorial_1_2.cpp
|
||||
)
|
||||
278
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_2/far_tutorial_1_2.cpp
vendored
Normal file
278
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_1_2/far_tutorial_1_2.cpp
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
//
|
||||
// Copyright 2018 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial illustrates two different styles of defining classes for
|
||||
// interpolating primvar data with the template methods in Far. The most
|
||||
// common usage involves data of a fixed size, so the focus here is on an
|
||||
// alternative supporting variable length data.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
//
|
||||
// Vertex data containers for interpolation:
|
||||
// - Coord3 is fixed to support 3 floats
|
||||
// - Coord2 is fixed to support 2 floats
|
||||
// - CoordBuffer can support a specified number of floats
|
||||
//
|
||||
struct Coord3 {
|
||||
Coord3() { }
|
||||
Coord3(float x, float y, float z) { _xyz[0] = x, _xyz[1] = y, _xyz[2] = z; }
|
||||
|
||||
void Clear() { _xyz[0] = _xyz[1] = _xyz[2] = 0.0f; }
|
||||
|
||||
void AddWithWeight(Coord3 const & src, float weight) {
|
||||
_xyz[0] += weight * src._xyz[0];
|
||||
_xyz[1] += weight * src._xyz[1];
|
||||
_xyz[2] += weight * src._xyz[2];
|
||||
}
|
||||
|
||||
float const * Coords() const { return &_xyz[0]; }
|
||||
|
||||
private:
|
||||
float _xyz[3];
|
||||
};
|
||||
|
||||
struct Coord2 {
|
||||
Coord2() { }
|
||||
Coord2(float u, float v) { _uv[0] = u, _uv[1] = v; }
|
||||
|
||||
void Clear() { _uv[0] = _uv[1] = 0.0f; }
|
||||
|
||||
void AddWithWeight(Coord2 const & src, float weight) {
|
||||
_uv[0] += weight * src._uv[0];
|
||||
_uv[1] += weight * src._uv[1];
|
||||
}
|
||||
|
||||
float const * Coords() const { return &_uv[0]; }
|
||||
|
||||
private:
|
||||
float _uv[2];
|
||||
};
|
||||
|
||||
struct CoordBuffer {
|
||||
//
|
||||
// The head of an external buffer and stride is specified on construction:
|
||||
//
|
||||
CoordBuffer(float * data, int size) : _data(data), _size(size) { }
|
||||
CoordBuffer() : _data(0), _size(0) { }
|
||||
|
||||
void Clear() {
|
||||
for (int i = 0; i < _size; ++i) {
|
||||
_data[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void AddWithWeight(CoordBuffer const & src, float weight) {
|
||||
assert(src._size == _size);
|
||||
for (int i = 0; i < _size; ++i) {
|
||||
_data[i] += weight * src._data[i];
|
||||
}
|
||||
}
|
||||
|
||||
float const * Coords() const { return _data; }
|
||||
|
||||
//
|
||||
// Defining [] to return a location elsewhere in the buffer is the key
|
||||
// requirement to supporting interpolatible data of varying size
|
||||
//
|
||||
CoordBuffer operator[](int index) const {
|
||||
return CoordBuffer(_data + index * _size, _size);
|
||||
}
|
||||
|
||||
private:
|
||||
float * _data;
|
||||
int _size;
|
||||
};
|
||||
|
||||
//
|
||||
// Global cube geometry from catmark_cube.h
|
||||
//
|
||||
// Topology:
|
||||
static int g_nverts = 8;
|
||||
static int g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
// Primvar data:
|
||||
static float g_verts[8][3] = {{ 0.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, 0.0f, 1.0f },
|
||||
{ 0.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 1.0f },
|
||||
{ 0.0f, 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.0f },
|
||||
{ 1.0f, 0.0f, 0.0f }};
|
||||
|
||||
//
|
||||
// Creates Far::TopologyRefiner from raw geometry above (see tutorial_1_1 for
|
||||
// more details)
|
||||
//
|
||||
static Far::TopologyRefiner *
|
||||
createFarTopologyRefiner() {
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
return refiner;
|
||||
}
|
||||
|
||||
//
|
||||
// Overview of main():
|
||||
// - create a Far::TopologyRefiner and uniformly refine it
|
||||
// - allocate separate and combined data buffers for vertex positions and UVs
|
||||
// - populate all refined data buffers and compare results
|
||||
// - write the result in Obj format
|
||||
//
|
||||
// Disable warnings for exact floating point comparisons:
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning disable 1572
|
||||
#endif
|
||||
|
||||
int main(int, char **) {
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the global geometry:
|
||||
Far::TopologyRefiner * refiner = createFarTopologyRefiner();
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'
|
||||
int maxlevel = 2;
|
||||
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
// Allocate and populate data buffers for vertex primvar data -- positions and
|
||||
// UVs. We assign UV coordiantes by simply projecting/assigning XY values.
|
||||
// The position and UV buffers use their associated data types, while the
|
||||
// combined buffer uses 5 floats per vertex.
|
||||
//
|
||||
int numBaseVertices = g_nverts;
|
||||
int numTotalVertices = refiner->GetNumVerticesTotal();
|
||||
|
||||
std::vector<Coord3> posData(numTotalVertices);
|
||||
std::vector<Coord2> uvData(numTotalVertices);
|
||||
|
||||
int combinedStride = 3 + 2;
|
||||
std::vector<float> combinedData(numTotalVertices * combinedStride);
|
||||
|
||||
for (int i = 0; i < numBaseVertices; ++i) {
|
||||
posData[i] = Coord3(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
uvData[i] = Coord2(g_verts[i][0], g_verts[i][1]);
|
||||
|
||||
float * coordCombined = &combinedData[i * combinedStride];
|
||||
coordCombined[0] = g_verts[i][0];
|
||||
coordCombined[1] = g_verts[i][1];
|
||||
coordCombined[2] = g_verts[i][2];
|
||||
coordCombined[3] = g_verts[i][0];
|
||||
coordCombined[4] = g_verts[i][1];
|
||||
}
|
||||
|
||||
// Interpolate vertex primvar data
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
Coord3 * posSrc = &posData[0];
|
||||
Coord2 * uvSrc = & uvData[0];
|
||||
|
||||
CoordBuffer combinedSrc(&combinedData[0], combinedStride);
|
||||
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
int numLevelVerts = refiner->GetLevel(level-1).GetNumVertices();
|
||||
|
||||
Coord3 * posDst = posSrc + numLevelVerts;
|
||||
Coord2 * uvDst = uvSrc + numLevelVerts;
|
||||
|
||||
CoordBuffer combinedDst = combinedSrc[numLevelVerts];
|
||||
|
||||
primvarRefiner.Interpolate(level, posSrc, posDst);
|
||||
primvarRefiner.Interpolate(level, uvSrc, uvDst);
|
||||
primvarRefiner.Interpolate(level, combinedSrc, combinedDst);
|
||||
|
||||
posSrc = posDst;
|
||||
uvSrc = uvDst;
|
||||
combinedSrc = combinedDst;
|
||||
}
|
||||
|
||||
// Verify that the combined coords match the separate results:
|
||||
for (int i = numBaseVertices; i < numTotalVertices; ++i) {
|
||||
float const * posCoords = posData[i].Coords();
|
||||
float const * uvCoords = uvData[i].Coords();
|
||||
|
||||
float const * combCoords = &combinedData[combinedStride * i];
|
||||
|
||||
assert(combCoords[0] == posCoords[0]);
|
||||
assert(combCoords[1] == posCoords[1]);
|
||||
assert(combCoords[2] == posCoords[2]);
|
||||
assert(combCoords[3] == uvCoords[0]);
|
||||
assert(combCoords[4] == uvCoords[1]);
|
||||
}
|
||||
|
||||
//
|
||||
// Output OBJ of the highest level refined:
|
||||
//
|
||||
Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);
|
||||
|
||||
int firstOfLastVerts = numTotalVertices - refLastLevel.GetNumVertices();
|
||||
|
||||
// Print vertex positions
|
||||
printf("# Vertices:\n");
|
||||
for (int vert = firstOfLastVerts; vert < numTotalVertices; ++vert) {
|
||||
float const * pos = &combinedData[vert * combinedStride];
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
printf("# UV coordinates:\n");
|
||||
for (int vert = firstOfLastVerts; vert < numTotalVertices; ++vert) {
|
||||
float const * uv = &combinedData[vert * combinedStride] + 3;
|
||||
printf("vt %f %f\n", uv[0], uv[1]);
|
||||
}
|
||||
|
||||
// Print faces
|
||||
int numFaces = refLastLevel.GetNumFaces();
|
||||
|
||||
printf("# Faces:\n");
|
||||
for (int face = 0; face < numFaces; ++face) {
|
||||
Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
|
||||
|
||||
printf("f ");
|
||||
for (int fvert = 0; fvert < fverts.size(); ++fvert) {
|
||||
int objIndex = 1 + fverts[fvert]; // OBJ uses 1-based arrays...
|
||||
printf("%d/%d ", objIndex, objIndex);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_1/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_1/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_2_1
|
||||
far_tutorial_2_1.cpp
|
||||
)
|
||||
228
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_1/far_tutorial_2_1.cpp
vendored
Normal file
228
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_1/far_tutorial_2_1.cpp
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// Building on tutorial 0, this example shows how to instantiate a simple mesh,
|
||||
// refine it uniformly and then interpolate additional sets of primvar data.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex container implementation.
|
||||
//
|
||||
// We are adding a per-vertex color attribute to our primvar data. While they
|
||||
// are separate properties and exist in separate buffers (as when read from an
|
||||
// Alembic file) they are both of the form float[3] and so we can use the same
|
||||
// underlying type.
|
||||
//
|
||||
// While color and position may be the same, we'll make the color a "varying"
|
||||
// primvar, e.g. it is constrained to being linearly interpolated between
|
||||
// vertices, rather than smoothly like position and other vertex data.
|
||||
//
|
||||
struct Point3 {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Point3() { }
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_point[0]=_point[1]=_point[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Point3 const & src, float weight) {
|
||||
_point[0]+=weight*src._point[0];
|
||||
_point[1]+=weight*src._point[1];
|
||||
_point[2]+=weight*src._point[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPoint(float x, float y, float z) {
|
||||
_point[0]=x;
|
||||
_point[1]=y;
|
||||
_point[2]=z;
|
||||
}
|
||||
|
||||
const float * GetPoint() const {
|
||||
return _point;
|
||||
}
|
||||
|
||||
private:
|
||||
float _point[3];
|
||||
};
|
||||
|
||||
typedef Point3 VertexPosition;
|
||||
typedef Point3 VertexColor;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
static float g_verts[8][3] = {{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f }};
|
||||
|
||||
// Per-vertex RGB color data
|
||||
static float g_colors[8][3] = {{ 1.0f, 0.0f, 0.5f },
|
||||
{ 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f, 1.0f },
|
||||
{ 0.0f, 0.0f, 0.0f }};
|
||||
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
static Far::TopologyRefiner * createFarTopologyRefiner();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
int maxlevel = 5;
|
||||
|
||||
Far::TopologyRefiner * refiner = createFarTopologyRefiner();
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
// Allocate buffers for vertex primvar data.
|
||||
//
|
||||
// We assume we received the coarse data for the mesh in separate buffers
|
||||
// from some other source, e.g. an Alembic file. Meanwhile, we want buffers
|
||||
// for the last/finest subdivision level to persist. We have no interest
|
||||
// in the intermediate levels.
|
||||
//
|
||||
// Determine the sizes for our needs:
|
||||
int nCoarseVerts = g_nverts;
|
||||
int nFineVerts = refiner->GetLevel(maxlevel).GetNumVertices();
|
||||
int nTotalVerts = refiner->GetNumVerticesTotal();
|
||||
int nTempVerts = nTotalVerts - nCoarseVerts - nFineVerts;
|
||||
|
||||
// Allocate and initialize the primvar data for the original coarse vertices:
|
||||
std::vector<VertexPosition> coarsePosBuffer(nCoarseVerts);
|
||||
std::vector<VertexColor> coarseClrBuffer(nCoarseVerts);
|
||||
|
||||
for (int i = 0; i < nCoarseVerts; ++i) {
|
||||
coarsePosBuffer[i].SetPoint(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
coarseClrBuffer[i].SetPoint(g_colors[i][0], g_colors[i][1], g_colors[i][2]);
|
||||
}
|
||||
|
||||
// Allocate intermediate and final storage to be populated:
|
||||
std::vector<VertexPosition> tempPosBuffer(nTempVerts);
|
||||
std::vector<VertexPosition> finePosBuffer(nFineVerts);
|
||||
|
||||
std::vector<VertexColor> tempClrBuffer(nTempVerts);
|
||||
std::vector<VertexColor> fineClrBuffer(nFineVerts);
|
||||
|
||||
// Interpolate all primvar data -- separate buffers can be populated on
|
||||
// separate threads if desired:
|
||||
VertexPosition * srcPos = &coarsePosBuffer[0];
|
||||
VertexPosition * dstPos = &tempPosBuffer[0];
|
||||
|
||||
VertexColor * srcClr = &coarseClrBuffer[0];
|
||||
VertexColor * dstClr = &tempClrBuffer[0];
|
||||
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
for (int level = 1; level < maxlevel; ++level) {
|
||||
primvarRefiner.Interpolate( level, srcPos, dstPos);
|
||||
primvarRefiner.InterpolateVarying(level, srcClr, dstClr);
|
||||
|
||||
srcPos = dstPos, dstPos += refiner->GetLevel(level).GetNumVertices();
|
||||
srcClr = dstClr, dstClr += refiner->GetLevel(level).GetNumVertices();
|
||||
}
|
||||
|
||||
// Interpolate the last level into the separate buffers for our final data:
|
||||
primvarRefiner.Interpolate( maxlevel, srcPos, finePosBuffer);
|
||||
primvarRefiner.InterpolateVarying(maxlevel, srcClr, fineClrBuffer);
|
||||
|
||||
|
||||
{ // Visualization with Maya : print a MEL script that generates colored
|
||||
// particles at the location of the refined vertices (don't forget to
|
||||
// turn shading on in the viewport to see the colors)
|
||||
|
||||
int nverts = nFineVerts;
|
||||
|
||||
// Output particle positions
|
||||
printf("particle ");
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = finePosBuffer[vert].GetPoint();
|
||||
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
printf(";\n");
|
||||
|
||||
// Set particle point size (20 -- very large)
|
||||
printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n");
|
||||
|
||||
// Add per-particle color attribute ('rgbPP')
|
||||
printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n");
|
||||
|
||||
// Set per-particle color values from our primvar data
|
||||
printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts);
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * color = fineClrBuffer[vert].GetPoint();
|
||||
printf("%f %f %f\n", color[0], color[1], color[2]);
|
||||
}
|
||||
printf(";\n");
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Creates Far::TopologyRefiner from raw geometry
|
||||
//
|
||||
// see tutorial_1_1 for more details
|
||||
//
|
||||
static Far::TopologyRefiner *
|
||||
createFarTopologyRefiner() {
|
||||
|
||||
// Populate a topology descriptor with our raw data
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
return refiner;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_2/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_2/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_2_2
|
||||
far_tutorial_2_2.cpp
|
||||
)
|
||||
345
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_2/far_tutorial_2_2.cpp
vendored
Normal file
345
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_2/far_tutorial_2_2.cpp
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Face-varying implementation.
|
||||
//
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_position[0] = src._position[0];
|
||||
_position[1] = src._position[1];
|
||||
_position[2] = src._position[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_position[0]=_position[1]=_position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_position[0]+=weight*src._position[0];
|
||||
_position[1]+=weight*src._position[1];
|
||||
_position[2]+=weight*src._position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
_position[0]=x;
|
||||
_position[1]=y;
|
||||
_position[2]=z;
|
||||
}
|
||||
|
||||
const float * GetPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
private:
|
||||
float _position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Face-varying container implementation.
|
||||
//
|
||||
// We are using a uv texture layout as a 'face-varying' primitive variable
|
||||
// attribute. Because face-varying data is specified 'per-face-per-vertex',
|
||||
// we cannot use the same container that we use for 'vertex' or 'varying'
|
||||
// data. We specify a new container, which only carries (u,v) coordinates.
|
||||
// Similarly to our 'Vertex' container, we add a minimalistic interpolation
|
||||
// interface with a 'Clear()' and 'AddWithWeight()' methods.
|
||||
//
|
||||
struct FVarVertexUV {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
void Clear() {
|
||||
u=v=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(FVarVertexUV const & src, float weight) {
|
||||
u += weight * src.u;
|
||||
v += weight * src.v;
|
||||
}
|
||||
|
||||
// Basic 'uv' layout channel
|
||||
float u,v;
|
||||
};
|
||||
|
||||
struct FVarVertexColor {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
void Clear() {
|
||||
r=g=b=a=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(FVarVertexColor const & src, float weight) {
|
||||
r += weight * src.r;
|
||||
g += weight * src.g;
|
||||
b += weight * src.b;
|
||||
a += weight * src.a;
|
||||
}
|
||||
|
||||
// Basic 'color' layout channel
|
||||
float r,g,b,a;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
|
||||
|
||||
// 'vertex' primitive variable data & topology
|
||||
static float g_verts[8][3] = {{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f }};
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
// 'face-varying' primitive variable data & topology for UVs
|
||||
static float g_uvs[14][2] = {{ 0.375, 0.00 },
|
||||
{ 0.625, 0.00 },
|
||||
{ 0.375, 0.25 },
|
||||
{ 0.625, 0.25 },
|
||||
{ 0.375, 0.50 },
|
||||
{ 0.625, 0.50 },
|
||||
{ 0.375, 0.75 },
|
||||
{ 0.625, 0.75 },
|
||||
{ 0.375, 1.00 },
|
||||
{ 0.625, 1.00 },
|
||||
{ 0.875, 0.00 },
|
||||
{ 0.875, 0.25 },
|
||||
{ 0.125, 0.00 },
|
||||
{ 0.125, 0.25 }};
|
||||
|
||||
static int g_nuvs = 14;
|
||||
|
||||
static int g_uvIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 9, 8,
|
||||
1, 10, 11, 3,
|
||||
12, 0, 2, 13 };
|
||||
|
||||
// 'face-varying' primitive variable data & topology for color
|
||||
static float g_colors[24][4] = {{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0}};
|
||||
|
||||
static int g_ncolors = 24;
|
||||
|
||||
static int g_colorIndices[24] = { 0, 3, 9, 6,
|
||||
7, 10, 15, 12,
|
||||
13, 16, 21, 18,
|
||||
19, 22, 4, 1,
|
||||
5, 23, 17, 11,
|
||||
20, 2, 8, 14 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
int maxlevel = 3;
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE);
|
||||
|
||||
// Populate a topology descriptor with our raw data
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
int channelUV = 0;
|
||||
int channelColor = 1;
|
||||
|
||||
// Create a face-varying channel descriptor
|
||||
Descriptor::FVarChannel channels[2];
|
||||
channels[channelUV].numValues = g_nuvs;
|
||||
channels[channelUV].valueIndices = g_uvIndices;
|
||||
channels[channelColor].numValues = g_ncolors;
|
||||
channels[channelColor].valueIndices = g_colorIndices;
|
||||
|
||||
// Add the channel topology to the main descriptor
|
||||
desc.numFVarChannels = 2;
|
||||
desc.fvarChannels = channels;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'
|
||||
// note: fullTopologyInLastLevel must be true to work with face-varying data
|
||||
{
|
||||
Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
|
||||
refineOptions.fullTopologyInLastLevel = true;
|
||||
refiner->RefineUniform(refineOptions);
|
||||
}
|
||||
|
||||
// Allocate and initialize the 'vertex' primvar data (see tutorial 2 for
|
||||
// more details).
|
||||
std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
|
||||
Vertex * verts = &vbuffer[0];
|
||||
|
||||
for (int i=0; i<g_nverts; ++i) {
|
||||
verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
}
|
||||
|
||||
// Allocate and initialize the first channel of 'face-varying' primvar data (UVs)
|
||||
std::vector<FVarVertexUV> fvBufferUV(refiner->GetNumFVarValuesTotal(channelUV));
|
||||
FVarVertexUV * fvVertsUV = &fvBufferUV[0];
|
||||
for (int i=0; i<g_nuvs; ++i) {
|
||||
fvVertsUV[i].u = g_uvs[i][0];
|
||||
fvVertsUV[i].v = g_uvs[i][1];
|
||||
}
|
||||
|
||||
// Allocate & interpolate the 'face-varying' primvar data (colors)
|
||||
std::vector<FVarVertexColor> fvBufferColor(refiner->GetNumFVarValuesTotal(channelColor));
|
||||
FVarVertexColor * fvVertsColor = &fvBufferColor[0];
|
||||
for (int i=0; i<g_ncolors; ++i) {
|
||||
fvVertsColor[i].r = g_colors[i][0];
|
||||
fvVertsColor[i].g = g_colors[i][1];
|
||||
fvVertsColor[i].b = g_colors[i][2];
|
||||
fvVertsColor[i].a = g_colors[i][3];
|
||||
}
|
||||
|
||||
// Interpolate both vertex and face-varying primvar data
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
Vertex * srcVert = verts;
|
||||
FVarVertexUV * srcFVarUV = fvVertsUV;
|
||||
FVarVertexColor * srcFVarColor = fvVertsColor;
|
||||
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
Vertex * dstVert = srcVert + refiner->GetLevel(level-1).GetNumVertices();
|
||||
FVarVertexUV * dstFVarUV = srcFVarUV + refiner->GetLevel(level-1).GetNumFVarValues(channelUV);
|
||||
FVarVertexColor * dstFVarColor = srcFVarColor + refiner->GetLevel(level-1).GetNumFVarValues(channelColor);
|
||||
|
||||
primvarRefiner.Interpolate(level, srcVert, dstVert);
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcFVarUV, dstFVarUV, channelUV);
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcFVarColor, dstFVarColor, channelColor);
|
||||
|
||||
srcVert = dstVert;
|
||||
srcFVarUV = dstFVarUV;
|
||||
srcFVarColor = dstFVarColor;
|
||||
}
|
||||
|
||||
|
||||
{ // Output OBJ of the highest level refined -----------
|
||||
|
||||
Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);
|
||||
|
||||
int nverts = refLastLevel.GetNumVertices();
|
||||
int nuvs = refLastLevel.GetNumFVarValues(channelUV);
|
||||
int ncolors= refLastLevel.GetNumFVarValues(channelColor);
|
||||
int nfaces = refLastLevel.GetNumFaces();
|
||||
|
||||
// Print vertex positions
|
||||
int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;
|
||||
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = verts[firstOfLastVerts + vert].GetPosition();
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
// Print uvs
|
||||
int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channelUV) - nuvs;
|
||||
|
||||
for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
|
||||
FVarVertexUV const & uv = fvVertsUV[firstOfLastUvs + fvvert];
|
||||
printf("vt %f %f\n", uv.u, uv.v);
|
||||
}
|
||||
|
||||
// Print colors
|
||||
int firstOfLastColors = refiner->GetNumFVarValuesTotal(channelColor) - ncolors;
|
||||
|
||||
for (int fvvert = 0; fvvert < ncolors; ++fvvert) {
|
||||
FVarVertexColor const & c = fvVertsColor[firstOfLastColors + fvvert];
|
||||
printf("c %f %f %f %f\n", c.r, c.g, c.b, c.a);
|
||||
}
|
||||
|
||||
// Print faces
|
||||
for (int face = 0; face < nfaces; ++face) {
|
||||
|
||||
Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
|
||||
Far::ConstIndexArray fuvs = refLastLevel.GetFaceFVarValues(face, channelUV);
|
||||
|
||||
// all refined Catmark faces should be quads
|
||||
assert(fverts.size()==4 && fuvs.size()==4);
|
||||
|
||||
printf("f ");
|
||||
for (int vert=0; vert<fverts.size(); ++vert) {
|
||||
// OBJ uses 1-based arrays...
|
||||
printf("%d/%d ", fverts[vert]+1, fuvs[vert]+1);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_3/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_3/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_2_3
|
||||
far_tutorial_2_3.cpp
|
||||
)
|
||||
513
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_3/far_tutorial_2_3.cpp
vendored
Normal file
513
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_2_3/far_tutorial_2_3.cpp
vendored
Normal file
@@ -0,0 +1,513 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// NOTE: The following approaches are approximations to compute smooth normals,
|
||||
// for highest fidelity patches should be used for positions and normals,
|
||||
// which form the true limit surface.
|
||||
//
|
||||
// Building on tutorial 3, this example shows how to instantiate a simple mesh,
|
||||
// refine it uniformly, interpolate both 'vertex' and 'face-varying'
|
||||
// primvar data, and finally calculate approximated smooth normals.
|
||||
// The resulting interpolated data is output in 'obj' format.
|
||||
//
|
||||
// Currently, this tutorial supports 3 methods to approximate smooth normals:
|
||||
//
|
||||
// CrossTriangle : Calculates smooth normals (accumulating per vertex) using
|
||||
// 3 verts to generate 2 vectors. This approximation has
|
||||
// trouble when working with quads (which can be non-planar)
|
||||
// since it only takes into account half of each face.
|
||||
//
|
||||
// CrossQuad : Calculates smooth normals (accumulating per vertex)
|
||||
// but this time, instead of taking into account only 3 verts
|
||||
// it creates 2 vectors crossing the quad.
|
||||
// This approximation builds upon CrossTriangle but takes
|
||||
// into account the 4 verts of the face.
|
||||
//
|
||||
// Limit : Calculates the normals at the limit for each vert
|
||||
// at the last level of subdivision.
|
||||
// These are the true limit normals, however, in this example
|
||||
// they are used with verts that are not at the limit.
|
||||
// This can lead to new visual artifacts since the normals
|
||||
// and the positions don't match. Additionally, this approach
|
||||
// requires extra computation to calculate the limit normals.
|
||||
// For this reason, we strongly suggest using
|
||||
// limit positions with limit normals.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Math helpers.
|
||||
//
|
||||
//
|
||||
|
||||
// Returns the normalized version of the input vector
|
||||
inline void
|
||||
normalize(float *n) {
|
||||
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
|
||||
n[0] *= rn;
|
||||
n[1] *= rn;
|
||||
n[2] *= rn;
|
||||
}
|
||||
|
||||
// Returns the cross product of \p v1 and \p v2.
|
||||
void cross(float const *v1, float const *v2, float* vOut)
|
||||
{
|
||||
vOut[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
vOut[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
vOut[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Face-varying implementation.
|
||||
//
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
position[0] = src.position[0];
|
||||
position[1] = src.position[1];
|
||||
position[2] = src.position[2];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
position[0]=position[1]=position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
position[0]+=weight*src.position[0];
|
||||
position[1]+=weight*src.position[1];
|
||||
position[2]+=weight*src.position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
position[0]=x;
|
||||
position[1]=y;
|
||||
position[2]=z;
|
||||
}
|
||||
|
||||
const float * GetPosition() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
float position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Face-varying container implementation.
|
||||
//
|
||||
// We are using a uv texture layout as a 'face-varying' primtiive variable
|
||||
// attribute. Because face-varying data is specified 'per-face-per-vertex',
|
||||
// we cannot use the same container that we use for 'vertex' or 'varying'
|
||||
// data. We specify a new container, which only carries (u,v) coordinates.
|
||||
// Similarly to our 'Vertex' container, we add a minimaliztic interpolation
|
||||
// interface with a 'Clear()' and 'AddWithWeight()' methods.
|
||||
//
|
||||
struct FVarVertexUV {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
void Clear() {
|
||||
u=v=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(FVarVertexUV const & src, float weight) {
|
||||
u += weight * src.u;
|
||||
v += weight * src.v;
|
||||
}
|
||||
|
||||
// Basic 'uv' layout channel
|
||||
float u,v;
|
||||
};
|
||||
|
||||
struct FVarVertexColor {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
void Clear() {
|
||||
r=g=b=a=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(FVarVertexColor const & src, float weight) {
|
||||
r += weight * src.r;
|
||||
g += weight * src.g;
|
||||
b += weight * src.b;
|
||||
a += weight * src.a;
|
||||
}
|
||||
|
||||
// Basic 'color' layout channel
|
||||
float r,g,b,a;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
|
||||
// 'vertex' primitive variable data & topology
|
||||
static float g_verts[8][3] = {{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f }};
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
// 'face-varying' primitive variable data & topology for UVs
|
||||
static float g_uvs[14][2] = {{ 0.375, 0.00 },
|
||||
{ 0.625, 0.00 },
|
||||
{ 0.375, 0.25 },
|
||||
{ 0.625, 0.25 },
|
||||
{ 0.375, 0.50 },
|
||||
{ 0.625, 0.50 },
|
||||
{ 0.375, 0.75 },
|
||||
{ 0.625, 0.75 },
|
||||
{ 0.375, 1.00 },
|
||||
{ 0.625, 1.00 },
|
||||
{ 0.875, 0.00 },
|
||||
{ 0.875, 0.25 },
|
||||
{ 0.125, 0.00 },
|
||||
{ 0.125, 0.25 }};
|
||||
|
||||
static int g_nuvs = 14;
|
||||
|
||||
static int g_uvIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 9, 8,
|
||||
1, 10, 11, 3,
|
||||
12, 0, 2, 13 };
|
||||
|
||||
// 'face-varying' primitive variable data & topology for color
|
||||
static float g_colors[24][4] = {{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 0.0, 0.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.0, 1.0, 1.0, 1.0}};
|
||||
|
||||
static int g_ncolors = 24;
|
||||
|
||||
static int g_colorIndices[24] = { 0, 3, 9, 6,
|
||||
7, 10, 15, 12,
|
||||
13, 16, 21, 18,
|
||||
19, 22, 4, 1,
|
||||
5, 23, 17, 11,
|
||||
20, 2, 8, 14 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
// Approximation methods for smooth normal computations
|
||||
enum NormalApproximation
|
||||
{
|
||||
CrossTriangle,
|
||||
CrossQuad,
|
||||
Limit
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
const int maxlevel = 2;
|
||||
enum NormalApproximation normalApproximation = CrossTriangle;
|
||||
|
||||
// Parsing command line parameters to see if the user wants to use a
|
||||
// specific method to calculate normals
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
|
||||
if (strstr(argv[i], "-limit")) {
|
||||
normalApproximation = Limit;
|
||||
} else if (!strcmp(argv[i], "-crossquad")) {
|
||||
normalApproximation = CrossQuad;
|
||||
} else if (!strcmp(argv[i], "-crosstriangle")) {
|
||||
normalApproximation = CrossTriangle;
|
||||
} else {
|
||||
printf("Parameters : \n");
|
||||
printf(" -crosstriangle : use the cross product of vectors\n");
|
||||
printf(" generated from 3 verts (default).\n");
|
||||
printf(" -crossquad : use the cross product of vectors\n");
|
||||
printf(" generated from 4 verts.\n");
|
||||
printf(" -limit : use normals calculated from the limit.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE);
|
||||
|
||||
// Populate a topology descriptor with our raw data
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Create a face-varying channel descriptor
|
||||
const int numChannels = 2;
|
||||
const int channelUV = 0;
|
||||
const int channelColor = 1;
|
||||
Descriptor::FVarChannel channels[numChannels];
|
||||
channels[channelUV].numValues = g_nuvs;
|
||||
channels[channelUV].valueIndices = g_uvIndices;
|
||||
channels[channelColor].numValues = g_ncolors;
|
||||
channels[channelColor].valueIndices = g_colorIndices;
|
||||
|
||||
// Add the channel topology to the main descriptor
|
||||
desc.numFVarChannels = numChannels;
|
||||
desc.fvarChannels = channels;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
// Uniformly refine the topolgy up to 'maxlevel'
|
||||
// note: fullTopologyInLastLevel must be true to work with face-varying data
|
||||
{
|
||||
Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
|
||||
refineOptions.fullTopologyInLastLevel = true;
|
||||
refiner->RefineUniform(refineOptions);
|
||||
}
|
||||
|
||||
// Allocate and initialize the 'vertex' primvar data (see tutorial 2 for
|
||||
// more details).
|
||||
std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
|
||||
Vertex * verts = &vbuffer[0];
|
||||
for (int i=0; i<g_nverts; ++i) {
|
||||
verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
}
|
||||
|
||||
// Allocate & initialize the first channel of 'face-varying' primvars (UVs)
|
||||
std::vector<FVarVertexUV> fvBufferUV(refiner->GetNumFVarValuesTotal(channelUV));
|
||||
FVarVertexUV * fvVertsUV = &fvBufferUV[0];
|
||||
for (int i=0; i<g_nuvs; ++i) {
|
||||
fvVertsUV[i].u = g_uvs[i][0];
|
||||
fvVertsUV[i].v = g_uvs[i][1];
|
||||
}
|
||||
|
||||
// Allocate & interpolate the 'face-varying' primvar data (colors)
|
||||
std::vector<FVarVertexColor> fvBufferColor(refiner->GetNumFVarValuesTotal(channelColor));
|
||||
FVarVertexColor * fvVertsColor = &fvBufferColor[0];
|
||||
for (int i=0; i<g_ncolors; ++i) {
|
||||
fvVertsColor[i].r = g_colors[i][0];
|
||||
fvVertsColor[i].g = g_colors[i][1];
|
||||
fvVertsColor[i].b = g_colors[i][2];
|
||||
fvVertsColor[i].a = g_colors[i][3];
|
||||
}
|
||||
|
||||
// Interpolate both vertex and face-varying primvar data
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
Vertex * srcVert = verts;
|
||||
FVarVertexUV * srcFVarUV = fvVertsUV;
|
||||
FVarVertexColor * srcFVarColor = fvVertsColor;
|
||||
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
Vertex * dstVert = srcVert + refiner->GetLevel(level-1).GetNumVertices();
|
||||
FVarVertexUV * dstFVarUV = srcFVarUV + refiner->GetLevel(level-1).GetNumFVarValues(channelUV);
|
||||
FVarVertexColor * dstFVarColor = srcFVarColor + refiner->GetLevel(level-1).GetNumFVarValues(channelColor);
|
||||
|
||||
primvarRefiner.Interpolate(level, srcVert, dstVert);
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcFVarUV, dstFVarUV, channelUV);
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcFVarColor, dstFVarColor, channelColor);
|
||||
|
||||
srcVert = dstVert;
|
||||
srcFVarUV = dstFVarUV;
|
||||
srcFVarColor = dstFVarColor;
|
||||
}
|
||||
|
||||
// Approximate normals
|
||||
Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);
|
||||
int nverts = refLastLevel.GetNumVertices();
|
||||
int nfaces = refLastLevel.GetNumFaces();
|
||||
int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;
|
||||
|
||||
std::vector<Vertex> normals(nverts);
|
||||
|
||||
// Different ways to approximate smooth normals
|
||||
//
|
||||
// For details check the description at the beginning of the file
|
||||
if (normalApproximation == Limit) {
|
||||
|
||||
// Approximation using the normal at the limit with verts that are
|
||||
// not at the limit
|
||||
//
|
||||
// For details check the description at the beginning of the file
|
||||
|
||||
std::vector<Vertex> fineLimitPos(nverts);
|
||||
std::vector<Vertex> fineDu(nverts);
|
||||
std::vector<Vertex> fineDv(nverts);
|
||||
|
||||
primvarRefiner.Limit(&verts[firstOfLastVerts], fineLimitPos, fineDu, fineDv);
|
||||
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * du = fineDu[vert].GetPosition();
|
||||
float const * dv = fineDv[vert].GetPosition();
|
||||
|
||||
float norm[3];
|
||||
cross(du, dv, norm);
|
||||
normals[vert].SetPosition(norm[0], norm[1], norm[2]);
|
||||
}
|
||||
|
||||
} else if (normalApproximation == CrossQuad) {
|
||||
|
||||
// Approximate smooth normals by accumulating normal vectors computed as
|
||||
// the cross product of two vectors generated by the 4 verts that
|
||||
// form each quad
|
||||
//
|
||||
// For details check the description at the beginning of the file
|
||||
|
||||
for (int f = 0; f < nfaces; f++) {
|
||||
Far::ConstIndexArray faceVertices = refLastLevel.GetFaceVertices(f);
|
||||
|
||||
// We will use the first three verts to calculate a normal
|
||||
const float * v0 = verts[ firstOfLastVerts + faceVertices[0] ].GetPosition();
|
||||
const float * v1 = verts[ firstOfLastVerts + faceVertices[1] ].GetPosition();
|
||||
const float * v2 = verts[ firstOfLastVerts + faceVertices[2] ].GetPosition();
|
||||
const float * v3 = verts[ firstOfLastVerts + faceVertices[3] ].GetPosition();
|
||||
|
||||
// Calculate the cross product between the vectors formed by v1-v0 and
|
||||
// v2-v0, and then normalize the result
|
||||
float normalCalculated [] = {0.0,0.0,0.0};
|
||||
float a[3] = { v2[0]-v0[0], v2[1]-v0[1], v2[2]-v0[2] };
|
||||
float b[3] = { v3[0]-v1[0], v3[1]-v1[1], v3[2]-v1[2] };
|
||||
cross(a, b, normalCalculated);
|
||||
normalize(normalCalculated);
|
||||
|
||||
// Accumulate that normal on all verts that are part of that face
|
||||
for(int vInFace = 0; vInFace < faceVertices.size() ; vInFace++ ) {
|
||||
|
||||
int vertexIndex = faceVertices[vInFace];
|
||||
normals[vertexIndex].position[0] += normalCalculated[0];
|
||||
normals[vertexIndex].position[1] += normalCalculated[1];
|
||||
normals[vertexIndex].position[2] += normalCalculated[2];
|
||||
}
|
||||
}
|
||||
|
||||
} else if (normalApproximation == CrossTriangle) {
|
||||
|
||||
// Approximate smooth normals by accumulating normal vectors computed as
|
||||
// the cross product of two vectors generated by 3 verts of the quad
|
||||
//
|
||||
// For details check the description at the beginning of the file
|
||||
|
||||
for (int f = 0; f < nfaces; f++) {
|
||||
Far::ConstIndexArray faceVertices = refLastLevel.GetFaceVertices(f);
|
||||
|
||||
// We will use the first three verts to calculate a normal
|
||||
const float * v0 = verts[ firstOfLastVerts + faceVertices[0] ].GetPosition();
|
||||
const float * v1 = verts[ firstOfLastVerts + faceVertices[1] ].GetPosition();
|
||||
const float * v2 = verts[ firstOfLastVerts + faceVertices[2] ].GetPosition();
|
||||
|
||||
// Calculate the cross product between the vectors formed by v1-v0 and
|
||||
// v2-v0, and then normalize the result
|
||||
float normalCalculated [] = {0.0,0.0,0.0};
|
||||
float a[3] = { v1[0]-v0[0], v1[1]-v0[1], v1[2]-v0[2] };
|
||||
float b[3] = { v2[0]-v0[0], v2[1]-v0[1], v2[2]-v0[2] };
|
||||
cross(a, b, normalCalculated);
|
||||
normalize(normalCalculated);
|
||||
|
||||
// Accumulate that normal on all verts that are part of that face
|
||||
for(int vInFace = 0; vInFace < faceVertices.size() ; vInFace++ ) {
|
||||
|
||||
int vertexIndex = faceVertices[vInFace];
|
||||
normals[vertexIndex].position[0] += normalCalculated[0];
|
||||
normals[vertexIndex].position[1] += normalCalculated[1];
|
||||
normals[vertexIndex].position[2] += normalCalculated[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we just need to normalize the accumulated normals
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
normalize(&normals[vert].position[0]);
|
||||
}
|
||||
|
||||
{ // Output OBJ of the highest level refined -----------
|
||||
|
||||
// Print vertex positions
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = verts[firstOfLastVerts + vert].GetPosition();
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
// Print vertex normals
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = normals[vert].GetPosition();
|
||||
printf("vn %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
// Print uvs
|
||||
int nuvs = refLastLevel.GetNumFVarValues(channelUV);
|
||||
int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channelUV) - nuvs;
|
||||
for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
|
||||
FVarVertexUV const & uv = fvVertsUV[firstOfLastUvs + fvvert];
|
||||
printf("vt %f %f\n", uv.u, uv.v);
|
||||
}
|
||||
|
||||
// Print faces
|
||||
for (int face = 0; face < nfaces; ++face) {
|
||||
Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
|
||||
Far::ConstIndexArray fuvs = refLastLevel.GetFaceFVarValues(face, channelUV);
|
||||
|
||||
// all refined Catmark faces should be quads
|
||||
assert(fverts.size()==4 && fuvs.size()==4);
|
||||
|
||||
printf("f ");
|
||||
for (int vert=0; vert<fverts.size(); ++vert) {
|
||||
// OBJ uses 1-based arrays...
|
||||
printf("%d/%d/%d ", fverts[vert]+1, fuvs[vert]+1, fverts[vert]+1);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_3_1
|
||||
far_tutorial_3_1.cpp
|
||||
)
|
||||
479
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/far_tutorial_3_1.cpp
vendored
Normal file
479
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/far_tutorial_3_1.cpp
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to interface a high-level topology representation
|
||||
// with Far for better efficiency. In tutorial 0, we showed how to instantiate
|
||||
// topology from a simple face-vertex list. Here we will show how to take
|
||||
// advantage of more complex data structures.
|
||||
//
|
||||
// Many client applications that manipulate geometry use advanced data structures
|
||||
// such as half-edge, quad-edge or winged-edge in order to represent complex
|
||||
// topological relationships beyond the usual face-vertex lists. We can take
|
||||
// advantage of this information.
|
||||
//
|
||||
// Far provides an advanced interface that allows such a client application to
|
||||
// communicate advanced component relationships directly and avoid having Far
|
||||
// rebuilding them redundantly.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyRefinerFactory.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// For this tutorial, we provide the complete topological representation of a
|
||||
// simple pyramid. In our case, we store it as a simple sequence of integers,
|
||||
// with the understanding that client-code would provide a fully implemented
|
||||
// data-structure such as quad-edges or winged-edges.
|
||||
//
|
||||
// Pyramid geometry from catmark_pyramid.h - extended for this tutorial
|
||||
//
|
||||
static int g_nverts = 5,
|
||||
g_nedges = 8,
|
||||
g_nfaces = 5;
|
||||
|
||||
// vertex positions
|
||||
static float g_verts[5][3] = {{ 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}};
|
||||
|
||||
// number of vertices in each face
|
||||
static int g_facenverts[5] = { 3, 3, 3, 3, 4 };
|
||||
|
||||
// index of face vertices
|
||||
static int g_faceverts[16] = { 0, 1, 2,
|
||||
0, 2, 3,
|
||||
0, 3, 4,
|
||||
0, 4, 1,
|
||||
4, 3, 2, 1 };
|
||||
|
||||
// index of edge vertices (2 per edge)
|
||||
static int g_edgeverts[16] = { 0, 1,
|
||||
1, 2,
|
||||
2, 0,
|
||||
2, 3,
|
||||
3, 0,
|
||||
3, 4,
|
||||
4, 0,
|
||||
4, 1 };
|
||||
|
||||
|
||||
// index of face edges
|
||||
static int g_faceedges[16] = { 0, 1, 2,
|
||||
2, 3, 4,
|
||||
4, 5, 6,
|
||||
6, 7, 0,
|
||||
5, 3, 1, 7 };
|
||||
|
||||
// number of faces adjacent to each edge
|
||||
static int g_edgenfaces[8] = { 2, 2, 2, 2, 2, 2, 2, 2 };
|
||||
|
||||
// index of faces incident to a given edge
|
||||
static int g_edgefaces[16] = { 0, 3,
|
||||
0, 4,
|
||||
0, 1,
|
||||
1, 4,
|
||||
1, 2,
|
||||
2, 4,
|
||||
2, 3,
|
||||
3, 4 };
|
||||
|
||||
// number of faces incident to each vertex
|
||||
static int g_vertexnfaces[5] = { 4, 3, 3, 3, 3 };
|
||||
|
||||
// index of faces incident to each vertex
|
||||
static int g_vertexfaces[25] = { 0, 1, 2, 3,
|
||||
0, 3, 4,
|
||||
0, 4, 1,
|
||||
1, 4, 2,
|
||||
2, 4, 3 };
|
||||
|
||||
|
||||
// number of edges incident to each vertex
|
||||
static int g_vertexnedges[5] = { 4, 3, 3, 3, 3 };
|
||||
|
||||
// index of edges incident to each vertex
|
||||
static int g_vertexedges[25] = { 0, 2, 4, 6,
|
||||
1, 0, 7,
|
||||
2, 1, 3,
|
||||
4, 3, 5,
|
||||
6, 5, 7 };
|
||||
|
||||
// Edge crease sharpness
|
||||
static float g_edgeCreases[8] = { 0.0f,
|
||||
2.5f,
|
||||
0.0f,
|
||||
2.5f,
|
||||
0.0f,
|
||||
2.5f,
|
||||
0.0f,
|
||||
2.5f };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Because existing client-code may not provide an exact match for the
|
||||
// topological queries required by Far's interface, we can provide a converter
|
||||
// class. This can be particularly useful for instance if the client
|
||||
// data-structure requires additional relationships to be mapped. For instance,
|
||||
// half-edge representations do not store unique edge indices and it can be
|
||||
// difficult to traverse edges or faces adjacent to a given vertex.
|
||||
//
|
||||
// Using an intermediate wrapper class allows us to leverage existing
|
||||
// relationships information from a mesh, and generate the missing components
|
||||
// temporarily.
|
||||
//
|
||||
// For a practical example, you can look at the file 'hbr_to_vtr.h' in the same
|
||||
// tutorial directory. This example implements a 'OsdHbrConverter' class as a
|
||||
// way of interfacing PRman's half-edge representation to Far.
|
||||
//
|
||||
struct Converter {
|
||||
|
||||
public:
|
||||
|
||||
Sdc::SchemeType GetType() const {
|
||||
return Sdc::SCHEME_CATMARK;
|
||||
}
|
||||
|
||||
Sdc::Options GetOptions() const {
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
return options;
|
||||
}
|
||||
|
||||
int GetNumFaces() const { return g_nfaces; }
|
||||
|
||||
int GetNumEdges() const { return g_nedges; }
|
||||
|
||||
int GetNumVertices() const { return g_nverts; }
|
||||
|
||||
//
|
||||
// Face relationships
|
||||
//
|
||||
int GetNumFaceVerts(int face) const { return g_facenverts[face]; }
|
||||
|
||||
int const * GetFaceVerts(int face) const { return g_faceverts+getCompOffset(g_facenverts, face); }
|
||||
|
||||
int const * GetFaceEdges(int face) const { return g_faceedges+getCompOffset(g_facenverts, face); }
|
||||
|
||||
|
||||
//
|
||||
// Edge relationships
|
||||
//
|
||||
int const * GetEdgeVertices(int edge) const { return g_edgeverts+edge*2; }
|
||||
|
||||
int GetNumEdgeFaces(int edge) const { return g_edgenfaces[edge]; }
|
||||
|
||||
int const * GetEdgeFaces(int edge) const { return g_edgefaces+getCompOffset(g_edgenfaces, edge); }
|
||||
|
||||
//
|
||||
// Vertex relationships
|
||||
//
|
||||
int GetNumVertexEdges(int vert) const { return g_vertexnedges[vert]; }
|
||||
|
||||
int const * GetVertexEdges(int vert) const { return g_vertexedges+getCompOffset(g_vertexnedges, vert); }
|
||||
|
||||
int GetNumVertexFaces(int vert) const { return g_vertexnfaces[vert]; }
|
||||
|
||||
int const * GetVertexFaces(int vert) const { return g_vertexfaces+getCompOffset(g_vertexnfaces, vert); }
|
||||
|
||||
private:
|
||||
|
||||
int getCompOffset(int const * comps, int comp) const {
|
||||
int ofs=0;
|
||||
for (int i=0; i<comp; ++i) {
|
||||
ofs += comps[i];
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<Converter>::resizeComponentTopology(
|
||||
TopologyRefiner & refiner, Converter const & conv) {
|
||||
|
||||
// Faces and face-verts
|
||||
int nfaces = conv.GetNumFaces();
|
||||
setNumBaseFaces(refiner, nfaces);
|
||||
for (int face=0; face<nfaces; ++face) {
|
||||
|
||||
int nv = conv.GetNumFaceVerts(face);
|
||||
setNumBaseFaceVertices(refiner, face, nv);
|
||||
}
|
||||
|
||||
// Edges and edge-faces
|
||||
int nedges = conv.GetNumEdges();
|
||||
setNumBaseEdges(refiner, nedges);
|
||||
for (int edge=0; edge<nedges; ++edge) {
|
||||
|
||||
int nf = conv.GetNumEdgeFaces(edge);
|
||||
setNumBaseEdgeFaces(refiner, edge, nf);
|
||||
}
|
||||
|
||||
// Vertices and vert-faces and vert-edges
|
||||
int nverts = conv.GetNumVertices();
|
||||
setNumBaseVertices(refiner, nverts);
|
||||
for (int vert=0; vert<nverts; ++vert) {
|
||||
|
||||
int ne = conv.GetNumVertexEdges(vert),
|
||||
nf = conv.GetNumVertexFaces(vert);
|
||||
setNumBaseVertexEdges(refiner, vert, ne);
|
||||
setNumBaseVertexFaces(refiner, vert, nf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<Converter>::assignComponentTopology(
|
||||
TopologyRefiner & refiner, Converter const & conv) {
|
||||
|
||||
using Far::IndexArray;
|
||||
|
||||
{ // Face relations:
|
||||
int nfaces = conv.GetNumFaces();
|
||||
for (int face=0; face<nfaces; ++face) {
|
||||
|
||||
IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face);
|
||||
IndexArray dstFaceEdges = getBaseFaceEdges(refiner, face);
|
||||
|
||||
int const * faceverts = conv.GetFaceVerts(face);
|
||||
int const * faceedges = conv.GetFaceEdges(face);
|
||||
|
||||
for (int vert=0; vert<conv.GetNumFaceVerts(face); ++vert) {
|
||||
dstFaceVerts[vert] = faceverts[vert];
|
||||
dstFaceEdges[vert] = faceedges[vert];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Edge relations
|
||||
//
|
||||
// Note: if your representation is unable to provide edge relationships
|
||||
// (ex: half-edges), you can comment out this section and Far will
|
||||
// automatically generate the missing information.
|
||||
//
|
||||
int nedges = conv.GetNumEdges();
|
||||
for (int edge=0; edge<nedges; ++edge) {
|
||||
|
||||
// Edge-vertices:
|
||||
IndexArray dstEdgeVerts = getBaseEdgeVertices(refiner, edge);
|
||||
dstEdgeVerts[0] = conv.GetEdgeVertices(edge)[0];
|
||||
dstEdgeVerts[1] = conv.GetEdgeVertices(edge)[1];
|
||||
|
||||
// Edge-faces
|
||||
IndexArray dstEdgeFaces = getBaseEdgeFaces(refiner, edge);
|
||||
for (int face=0; face<conv.GetNumEdgeFaces(face); ++face) {
|
||||
dstEdgeFaces[face] = conv.GetEdgeFaces(edge)[face];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Vertex relations
|
||||
int nverts = conv.GetNumVertices();
|
||||
for (int vert=0; vert<nverts; ++vert) {
|
||||
|
||||
// Vert-Faces:
|
||||
IndexArray vertFaces = getBaseVertexFaces(refiner, vert);
|
||||
//LocalIndexArray vertInFaceIndices = getBaseVertexFaceLocalIndices(refiner, vert);
|
||||
for (int face=0; face<conv.GetNumVertexFaces(vert); ++face) {
|
||||
vertFaces[face] = conv.GetVertexFaces(vert)[face];
|
||||
}
|
||||
|
||||
// Vert-Edges:
|
||||
IndexArray vertEdges = getBaseVertexEdges(refiner, vert);
|
||||
//LocalIndexArray vertInEdgeIndices = getBaseVertexEdgeLocalIndices(refiner, vert);
|
||||
for (int edge=0; edge<conv.GetNumVertexEdges(vert); ++edge) {
|
||||
vertEdges[edge] = conv.GetVertexEdges(vert)[edge];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
populateBaseLocalIndices(refiner);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<Converter>::assignComponentTags(
|
||||
TopologyRefiner & refiner, Converter const & conv) {
|
||||
|
||||
// arbitrarily sharpen the 4 bottom edges of the pyramid to 2.5f
|
||||
for (int edge=0; edge<conv.GetNumEdges(); ++edge) {
|
||||
setBaseEdgeSharpness(refiner, edge, g_edgeCreases[edge]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
template <>
|
||||
void
|
||||
TopologyRefinerFactory<Converter>::reportInvalidTopology(
|
||||
TopologyError /* errCode */, char const * msg, Converter const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional topology validation error reporting:
|
||||
// This method is called whenever the factory encounters topology validation
|
||||
// errors. By default, nothing is reported
|
||||
//
|
||||
Warning(msg);
|
||||
}
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<Converter>::assignFaceVaryingTopology(
|
||||
TopologyRefiner & /* refiner */, Converter const & /* conv */) {
|
||||
|
||||
// Because of the way MSVC++ specializes templated functions, we had to
|
||||
// remove the default stubs in Far::TopologyRefinerFactory. In this
|
||||
// example, no face-varying data is being added, but we still need to
|
||||
// implement a template specialization or MSVC++ linker fails.
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Far
|
||||
|
||||
} // namespace OPENSUBDIV_VERSION
|
||||
} // namespace OpenSubdiv
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Vertex container implementation.
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_position[0] = src._position[0];
|
||||
_position[1] = src._position[1];
|
||||
_position[2] = src._position[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_position[0]=_position[1]=_position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_position[0]+=weight*src._position[0];
|
||||
_position[1]+=weight*src._position[1];
|
||||
_position[2]+=weight*src._position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
_position[0]=x;
|
||||
_position[1]=y;
|
||||
_position[2]=z;
|
||||
}
|
||||
|
||||
const float * GetPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
private:
|
||||
float _position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
Converter conv;
|
||||
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Converter>::Create(conv,
|
||||
Far::TopologyRefinerFactory<Converter>::Options(conv.GetType(), conv.GetOptions()));
|
||||
|
||||
|
||||
int maxlevel = 5;
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
|
||||
// Allocate a buffer for vertex primvar data. The buffer length is set to
|
||||
// be the sum of all children vertices up to the highest level of refinement.
|
||||
std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
|
||||
Vertex * verts = &vbuffer[0];
|
||||
|
||||
|
||||
// Initialize coarse mesh positions
|
||||
int nCoarseVerts = g_nverts;
|
||||
for (int i=0; i<nCoarseVerts; ++i) {
|
||||
verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
|
||||
}
|
||||
|
||||
|
||||
// Interpolate vertex primvar data
|
||||
Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
Vertex * src = verts;
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices();
|
||||
primvarRefiner.Interpolate(level, src, dst);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
|
||||
{ // Output OBJ of the highest level refined -----------
|
||||
|
||||
Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);
|
||||
|
||||
int nverts = refLastLevel.GetNumVertices();
|
||||
int nfaces = refLastLevel.GetNumFaces();
|
||||
|
||||
// Print vertex positions
|
||||
int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;
|
||||
|
||||
for (int vert = 0; vert < nverts; ++vert) {
|
||||
float const * pos = verts[firstOfLastVerts + vert].GetPosition();
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
// Print faces
|
||||
for (int face = 0; face < nfaces; ++face) {
|
||||
|
||||
Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
|
||||
|
||||
// all refined Catmark faces should be quads
|
||||
assert(fverts.size()==4);
|
||||
|
||||
printf("f ");
|
||||
for (int vert=0; vert<fverts.size(); ++vert) {
|
||||
printf("%d ", fverts[vert]+1); // OBJ uses 1-based arrays...
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
446
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/hbr_to_vtr.h
vendored
Normal file
446
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_3_1/hbr_to_vtr.h
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include <hbr/mesh.h>
|
||||
#include <hbr/bilinear.h>
|
||||
#include <hbr/loop.h>
|
||||
#include <hbr/catmark.h>
|
||||
#include <hbr/vertexEdit.h>
|
||||
#include <hbr/cornerEdit.h>
|
||||
#include <hbr/holeEdit.h>
|
||||
|
||||
#include <opensubdiv/far/topologyRefinerFactory.h>
|
||||
|
||||
#include <typeinfo>
|
||||
#include <cassert>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool
|
||||
compareType(std::type_info const & t1, std::type_info const & t2) {
|
||||
|
||||
if (t1==t2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// On some systems, distinct instances of \c type_info objects compare equal if
|
||||
// their name() functions return equivalent strings. On other systems, distinct
|
||||
// type_info objects never compare equal. The latter can cause problems in the
|
||||
// presence of plugins loaded without RTLD_GLOBAL, because typeid(T) returns
|
||||
// different \c type_info objects for the same T in the two plugins.
|
||||
for (char const * p1 = t1.name(), *p2 = t2.name(); *p1 == *p2; ++p1, ++p2)
|
||||
if (*p1 == '\0')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Translates subdivision options from Hbr to SdcOptions
|
||||
//
|
||||
template <class T>
|
||||
static OpenSubdiv::SdcType
|
||||
getSdcOptions( OpenSubdiv::HbrMesh<T> const & mesh, OpenSubdiv::SdcOptions * options) {
|
||||
|
||||
typedef OpenSubdiv::SdcOptions SdcOptions;
|
||||
|
||||
typedef OpenSubdiv::HbrMesh<T> HMesh;
|
||||
typedef OpenSubdiv::HbrSubdivision<T> HSubdiv;
|
||||
typedef OpenSubdiv::HbrCatmarkSubdivision<T> HCatmarkSubdiv;
|
||||
|
||||
OpenSubdiv::SdcType type;
|
||||
|
||||
SdcOptions::TriangleSubdivision tris=SdcOptions::TRI_SUB_NORMAL;
|
||||
|
||||
HSubdiv const * subdivision = mesh.GetSubdivision();
|
||||
|
||||
if (compareType(typeid(*subdivision), typeid(OpenSubdiv::HbrBilinearSubdivision<T>))) {
|
||||
type = OpenSubdiv::TYPE_BILINEAR;
|
||||
} else if (compareType(typeid(*subdivision), typeid(OpenSubdiv::HbrCatmarkSubdivision<T>))) {
|
||||
type = OpenSubdiv::TYPE_CATMARK;
|
||||
HCatmarkSubdiv const * catmarkSudiv = dynamic_cast<HCatmarkSubdiv const *>(subdivision);
|
||||
switch (catmarkSudiv->GetTriangleSubdivisionMethod()) {
|
||||
case HCatmarkSubdiv::k_Normal: tris=SdcOptions::TRI_SUB_NORMAL; break;
|
||||
case HCatmarkSubdiv::k_Old: tris=SdcOptions::TRI_SUB_OLD; break;
|
||||
case HCatmarkSubdiv::k_New: tris=SdcOptions::TRI_SUB_NEW; break;
|
||||
}
|
||||
} else if (compareType(typeid(*subdivision), typeid(OpenSubdiv::HbrLoopSubdivision<T>))) {
|
||||
type = OpenSubdiv::TYPE_LOOP;
|
||||
} else
|
||||
assert(0);
|
||||
|
||||
OpenSubdiv::SdcOptions::VtxBoundaryInterpolation vvbi;
|
||||
switch (mesh.GetInterpolateBoundaryMethod()) {
|
||||
case HMesh::k_InterpolateBoundaryNone: vvbi=SdcOptions::VTX_BOUNDARY_NONE; break;
|
||||
case HMesh::k_InterpolateBoundaryEdgeOnly: vvbi=SdcOptions::VTX_BOUNDARY_EDGE_ONLY; break;
|
||||
case HMesh::k_InterpolateBoundaryEdgeAndCorner: vvbi=SdcOptions::VTX_BOUNDARY_EDGE_AND_CORNER; break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
OpenSubdiv::SdcOptions::FVarBoundaryInterpolation fvbi;
|
||||
switch (mesh.GetInterpolateBoundaryMethod()) {
|
||||
case HMesh::k_InterpolateBoundaryNone: fvbi=SdcOptions::FVAR_BOUNDARY_BILINEAR; break;
|
||||
case HMesh::k_InterpolateBoundaryEdgeOnly: fvbi=SdcOptions::FVAR_BOUNDARY_EDGE_ONLY; break;
|
||||
case HMesh::k_InterpolateBoundaryEdgeAndCorner: fvbi=SdcOptions::FVAR_BOUNDARY_EDGE_AND_CORNER; break;
|
||||
case HMesh::k_InterpolateBoundaryAlwaysSharp: fvbi=SdcOptions::FVAR_BOUNDARY_ALWAYS_SHARP; break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
OpenSubdiv::SdcOptions::CreasingMethod creaseMethod;
|
||||
switch (subdivision->GetCreaseSubdivisionMethod()) {
|
||||
case HSubdiv::k_CreaseNormal: creaseMethod=OpenSubdiv::SdcOptions::CREASE_UNIFORM; break;
|
||||
case HSubdiv::k_CreaseChaikin: creaseMethod=OpenSubdiv::SdcOptions::CREASE_CHAIKIN; break;
|
||||
};
|
||||
|
||||
options->SetVtxBoundaryInterpolation(vvbi);
|
||||
options->SetFVarBoundaryInterpolation(fvbi);
|
||||
options->SetCreasingMethod(creaseMethod);
|
||||
options->SetTriangleSubdivision(tris);
|
||||
options->SetNonManifoldInterpolation(OpenSubdiv::SdcOptions::NON_MANIFOLD_NONE);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// The HbrConverter is used to specialize FarTopologyRefinerFactory for the Hbr rep.
|
||||
//
|
||||
// Hbr is a half-edge topo rep, which by definition does not index edges
|
||||
// uniquely. To remedy the problem, the converter uses a std::map to connect
|
||||
// Hbr's half-edge pointers to unique indices.
|
||||
//
|
||||
// This remapping code is provided as an example of efficient implementation of
|
||||
// the translation from an arbitrary topo rep to Vtr.
|
||||
//
|
||||
// Even though Vtr is capable of re-generating edge and vertex relationships on
|
||||
// its own, this requires costly work that may be redundant if these relationships
|
||||
// can be translated from the host rep.
|
||||
//
|
||||
template <class T> class HbrConverter {
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
HbrConverter(OpenSubdiv::HbrMesh<T> const & hmesh) : _hmesh(hmesh) {
|
||||
|
||||
_nfaces = _hmesh.GetNumFaces();
|
||||
_nverts = _hmesh.GetNumVertices();
|
||||
_type = getSdcOptions<OpenSubdiv::OsdVertex>(_hmesh, &_options);
|
||||
}
|
||||
|
||||
// Returns the type of mesh (Bilinear, Catmark, Loop)
|
||||
OpenSubdiv::SdcType const & GetType() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
// Returns subdivision options
|
||||
OpenSubdiv::SdcOptions const & GetOptions() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
// The HbrMesh being converted
|
||||
OpenSubdiv::HbrMesh<T> const & GetHbrMesh() const {
|
||||
return _hmesh;
|
||||
}
|
||||
|
||||
// Number of faces in the mesh (cached for efficiency)
|
||||
int GetNumFaces() const {
|
||||
return _nfaces;
|
||||
}
|
||||
|
||||
// Number of vertices in the mesh (cached for efficiency)
|
||||
int GetNumVertices() const {
|
||||
return _nverts;
|
||||
}
|
||||
|
||||
// Number of edges in the mesh
|
||||
int GetNumEdges() const {
|
||||
return (int)_edgeset.size();
|
||||
}
|
||||
|
||||
// Returns a pointer to the Hbr halfege of index 'idx'
|
||||
OpenSubdiv::HbrHalfedge<T> const * GetEdge(int idx) const {
|
||||
return _edgeids[idx];
|
||||
}
|
||||
|
||||
typedef std::map<OpenSubdiv::HbrHalfedge<T> const *, int> EdgeMap;
|
||||
|
||||
// A map of unique edges between vertices
|
||||
EdgeMap & GetEdges() {
|
||||
return _edgeset;
|
||||
}
|
||||
|
||||
// Must be called after the edge map has been populated
|
||||
void FinishEdgeMap() const {
|
||||
// Fudge const-ness because resizeComponentTopology() passes the converter
|
||||
// as a const. The alternative is to add an iteration loop over Hbr before,
|
||||
// which would waste time.
|
||||
EdgeVec * edges = const_cast<EdgeVec *>(&_edgeids);
|
||||
edges->resize(_edgeset.size());
|
||||
for (typename EdgeMap::const_iterator it=_edgeset.begin(); it!=_edgeset.end(); ++it) {
|
||||
(*edges)[it->second] = it->first;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a unique edge index for a given half-edge
|
||||
int GetEdgeIndex(OpenSubdiv::HbrHalfedge<T> const * e) const {
|
||||
assert(e);
|
||||
typename EdgeMap::const_iterator it = _edgeset.find(e);
|
||||
if (it==_edgeset.end()) {
|
||||
assert(e->GetOpposite());
|
||||
it = _edgeset.find(e->GetOpposite());
|
||||
}
|
||||
assert(it!=_edgeset.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Returns the edgeVertIndex for a given Hbr halfedge 'e' and vertex 'v'
|
||||
int GetEdgeVertIndex(OpenSubdiv::HbrHalfedge<T> const * e, OpenSubdiv::HbrVertex<T> const * v) const {
|
||||
assert(e && v);
|
||||
if (_edgeset.find(e)==_edgeset.end()) {
|
||||
e = e->GetOpposite();
|
||||
assert(e);
|
||||
}
|
||||
return (v==e->GetOrgVertex() ? 0:1);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef std::vector<OpenSubdiv::HbrHalfedge<T> const *> EdgeVec;
|
||||
|
||||
OpenSubdiv::SdcType _type;
|
||||
OpenSubdiv::SdcOptions _options;
|
||||
|
||||
OpenSubdiv::HbrMesh<T> const & _hmesh;
|
||||
|
||||
int _nfaces,
|
||||
_nverts;
|
||||
|
||||
EdgeMap _edgeset;
|
||||
EdgeVec _edgeids;
|
||||
};
|
||||
|
||||
typedef HbrConverter<OpenSubdiv::OsdVertex> OsdHbrConverter;
|
||||
|
||||
typedef OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex> OsdHbrMesh;
|
||||
typedef OpenSubdiv::HbrSubdivision<OpenSubdiv::OsdVertex> OsdHbrSubdivision;
|
||||
typedef OpenSubdiv::HbrVertex<OpenSubdiv::OsdVertex> OsdHbrVertex;
|
||||
typedef OpenSubdiv::HbrFace<OpenSubdiv::OsdVertex> OsdHbrFace;
|
||||
typedef OpenSubdiv::HbrHalfedge<OpenSubdiv::OsdVertex> OsdHbrHalfedge;
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <>
|
||||
void
|
||||
FarTopologyRefinerFactory<OsdHbrConverter>::resizeComponentTopology(
|
||||
FarTopologyRefiner & refiner, OsdHbrConverter const & conv) {
|
||||
|
||||
OsdHbrMesh const & hmesh = conv.GetHbrMesh();
|
||||
|
||||
int nfaces = hmesh.GetNumFaces(),
|
||||
nverts = hmesh.GetNumVertices();
|
||||
|
||||
OsdHbrConverter::EdgeMap & edges = const_cast<OsdHbrConverter &>(conv).GetEdges();
|
||||
assert(edges.size()==0);
|
||||
|
||||
// Faces and face-verts
|
||||
setNumBaseFaces(refiner, nfaces);
|
||||
for (int i=0; i<nfaces; ++i) {
|
||||
|
||||
OsdHbrFace const * f = hmesh.GetFace(i);
|
||||
|
||||
int nv = f->GetNumVertices();
|
||||
assert(nv==4); // temporary until n-gons are supported
|
||||
|
||||
setNumBaseFaceVertices(refiner, i, nv);
|
||||
|
||||
for (int j=0; j<nv; ++j) {
|
||||
|
||||
// index Hbr edge pointers in the map
|
||||
OsdHbrHalfedge const * e = f->GetEdge(j);
|
||||
if (e->IsBoundary() || (e->GetRightFace()->GetID()>f->GetID())) {
|
||||
int id = (int)edges.size();
|
||||
edges[e] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conv.FinishEdgeMap();
|
||||
|
||||
// Edges and edge-faces
|
||||
setNumBaseEdges(refiner, (int)edges.size());
|
||||
for (int i=0; i!=conv.GetNumEdges(); ++i) {
|
||||
OsdHbrHalfedge const * e = conv.GetEdge(i);
|
||||
setNumBaseEdgeFaces(refiner, i, e->GetRightFace() ? 2 : 1);
|
||||
}
|
||||
|
||||
// Vertices and vert-faces and vert-edges
|
||||
setNumBaseVertices(refiner, nverts);
|
||||
for (int i=0; i<nverts; ++i) {
|
||||
|
||||
OsdHbrVertex * v = hmesh.GetVertex(i);
|
||||
|
||||
class GatherOperator : public OpenSubdiv::HbrHalfedgeOperator<OpenSubdiv::OsdVertex> {
|
||||
|
||||
OsdHbrVertex const * _v;
|
||||
public:
|
||||
int vertEdgeCount,
|
||||
vertFaceCount;
|
||||
|
||||
GatherOperator(OsdHbrVertex const * v) : _v(v), vertEdgeCount(0), vertFaceCount(0) { }
|
||||
|
||||
virtual void operator() (OsdHbrHalfedge &e) {
|
||||
if (e.GetOrgVertex()==_v && e.GetFace())
|
||||
++vertFaceCount;
|
||||
++vertEdgeCount;
|
||||
}
|
||||
};
|
||||
|
||||
GatherOperator op(v);
|
||||
v->ApplyOperatorSurroundingEdges(op);
|
||||
|
||||
setNumBaseVertexEdges(refiner, i, op.vertEdgeCount);
|
||||
setNumBaseVertexFaces(refiner, i, op.vertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
FarTopologyRefinerFactory<OsdHbrConverter>::assignComponentTopology(
|
||||
FarTopologyRefiner & refiner, OsdHbrConverter const & conv) {
|
||||
|
||||
typedef FarTopologyRefiner::Index Index;
|
||||
typedef FarTopologyRefiner::IndexArray IndexArray;
|
||||
typedef FarTopologyRefiner::LocalIndex LocalIndex;
|
||||
|
||||
OsdHbrMesh const & hmesh = conv.GetHbrMesh();
|
||||
|
||||
OsdHbrConverter::EdgeMap & edges = const_cast<OsdHbrConverter &>(conv).GetEdges();
|
||||
|
||||
{ // Face relations:
|
||||
int nfaces = getNumBaseFaces(refiner);
|
||||
for (int i=0; i < nfaces; ++i) {
|
||||
|
||||
IndexArray dstFaceVerts = getBaseFaceVertices(refiner, i);
|
||||
IndexArray dstFaceEdges = getBaseFaceEdges(refiner, i);
|
||||
|
||||
OsdHbrFace * f = hmesh.GetFace(i);
|
||||
|
||||
for (int j = 0; j < dstFaceVerts.size(); ++j) {
|
||||
|
||||
dstFaceVerts[j] = (int)f->GetVertex(j)->GetID();
|
||||
dstFaceEdges[j] = conv.GetEdgeIndex(f->GetEdge(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Edge relations
|
||||
for (OsdHbrConverter::EdgeMap::const_iterator it=edges.begin(); it!=edges.end(); ++it) {
|
||||
|
||||
OsdHbrHalfedge const * e = it->first;
|
||||
int eidx = it->second;
|
||||
|
||||
// Edge-vertices:
|
||||
IndexArray dstEdgeVerts = getBaseEdgeVertices(refiner, eidx);
|
||||
dstEdgeVerts[0] = e->GetOrgVertex()->GetID();
|
||||
dstEdgeVerts[1] = e->GetDestVertex()->GetID();
|
||||
|
||||
// Edge-faces
|
||||
IndexArray dstEdgeFaces = getBaseEdgeFaces(refiner, eidx);
|
||||
dstEdgeFaces[0] = e->GetLeftFace()->GetID();
|
||||
// half-edges only have 2 faces incident to an edge (no non-manifold)
|
||||
if (e->GetRightFace()) {
|
||||
dstEdgeFaces[1] = e->GetRightFace()->GetID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Vert relations
|
||||
for (int i=0; i<getNumBaseVertices(refiner); ++i) {
|
||||
|
||||
OsdHbrVertex const * v = hmesh.GetVertex(i);
|
||||
|
||||
// The Hbr operator gathers the indices of the faces and edges incident
|
||||
// to a vertex and populates the refiner topological relationships.
|
||||
class GatherOperator : public OpenSubdiv::HbrHalfedgeOperator<OpenSubdiv::OsdVertex> {
|
||||
|
||||
OsdHbrConverter const & _conv;
|
||||
OsdHbrVertex const * _v;
|
||||
|
||||
Index * _dstVertFaces,
|
||||
* _dstVertEdges;
|
||||
|
||||
LocalIndex * _dstVertInFaceIndices,
|
||||
* _dstVertInEdgeIndices;
|
||||
public:
|
||||
|
||||
GatherOperator(FarTopologyRefiner & refiner, OsdHbrConverter const & conv,
|
||||
OsdHbrVertex const * v, int idx) : _conv(conv), _v(v) {
|
||||
|
||||
_dstVertFaces = getBaseVertexFaces(refiner, idx).begin(),
|
||||
_dstVertEdges = getBaseVertexEdges(refiner, idx).begin();
|
||||
|
||||
_dstVertInFaceIndices = getBaseVertexFaceLocalIndices(refiner, idx).begin(),
|
||||
_dstVertInEdgeIndices = getBaseVertexEdgeLocalIndices(refiner, idx).begin();
|
||||
}
|
||||
|
||||
virtual void operator() (OsdHbrHalfedge &e) {
|
||||
|
||||
OsdHbrFace * f=e.GetFace();
|
||||
if (f && (e.GetOrgVertex()==_v)) {
|
||||
*_dstVertFaces++ = f->GetID();
|
||||
for (int j=0; j<f->GetNumVertices(); ++j) {
|
||||
if (f->GetVertex(j)==_v) {
|
||||
*_dstVertInFaceIndices++ = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*_dstVertEdges++ = _conv.GetEdgeIndex(&e);
|
||||
*_dstVertInEdgeIndices++ = _conv.GetEdgeVertIndex(&e, _v);
|
||||
}
|
||||
};
|
||||
|
||||
GatherOperator op(refiner, conv, v, i);
|
||||
v->ApplyOperatorSurroundingEdges(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
FarTopologyRefinerFactory<OsdHbrConverter>::assignComponentTags(
|
||||
FarTopologyRefiner & refiner, OsdHbrConverter const & conv) {
|
||||
|
||||
OsdHbrMesh const & hmesh = conv.GetHbrMesh();
|
||||
|
||||
OsdHbrConverter::EdgeMap & edges = const_cast<OsdHbrConverter &>(conv).GetEdges();
|
||||
|
||||
// Initialize edge sharpness
|
||||
for (OsdHbrConverter::EdgeMap::const_iterator it=edges.begin(); it!=edges.end(); ++it) {
|
||||
|
||||
OsdHbrHalfedge const * e = it->first;
|
||||
|
||||
float sharpness = e->GetSharpness();
|
||||
if (e->GetOpposite()) {
|
||||
sharpness = std::max(sharpness, e->GetOpposite()->GetSharpness());
|
||||
|
||||
}
|
||||
setBaseEdgeSharpness(refiner, it->second, sharpness);
|
||||
}
|
||||
|
||||
// Initialize vertex sharpness
|
||||
for (int i=0; i<getNumBaseVertices(refiner); ++i) {
|
||||
setBaseVertexSharpness(refiner, i, hmesh.GetVertex(i)->GetSharpness());
|
||||
}
|
||||
|
||||
// XXXX Initialize h-edits
|
||||
}
|
||||
|
||||
} // namespace OPENSUBDIV_VERSION
|
||||
} // namespace OpenSubdiv
|
||||
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_1/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_1/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_4_1
|
||||
far_tutorial_4_1.cpp
|
||||
)
|
||||
168
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_1/far_tutorial_4_1.cpp
vendored
Normal file
168
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_1/far_tutorial_4_1.cpp
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to create and manipulate Far::StencilTable. We use
|
||||
// the factorized stencils to interpolate vertex primvar data buffers.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/stencilTable.h>
|
||||
#include <opensubdiv/far/stencilTableFactory.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex container implementation.
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_position[0] = src._position[0];
|
||||
_position[1] = src._position[1];
|
||||
_position[2] = src._position[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_position[0]=_position[1]=_position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_position[0]+=weight*src._position[0];
|
||||
_position[1]+=weight*src._position[1];
|
||||
_position[2]+=weight*src._position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
_position[0]=x;
|
||||
_position[1]=y;
|
||||
_position[2]=z;
|
||||
}
|
||||
|
||||
float const * GetPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
private:
|
||||
float _position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
|
||||
static float g_verts[24] = {-0.5f, -0.5f, 0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f };
|
||||
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
static Far::TopologyRefiner * createTopologyRefiner();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
// Generate a Far::TopologyRefiner (see tutorial_1_1 for details).
|
||||
Far::TopologyRefiner * refiner = createTopologyRefiner();
|
||||
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'.
|
||||
int maxlevel = 3;
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
|
||||
// Use the Far::StencilTable factory to create discrete stencil table
|
||||
// note: we only want stencils for the highest refinement level.
|
||||
Far::StencilTableFactory::Options options;
|
||||
options.generateIntermediateLevels=false;
|
||||
options.generateOffsets=true;
|
||||
|
||||
Far::StencilTable const * stencilTable =
|
||||
Far::StencilTableFactory::Create(*refiner, options);
|
||||
|
||||
// Allocate vertex primvar buffer (1 stencil for each vertex)
|
||||
int nstencils = stencilTable->GetNumStencils();
|
||||
std::vector<Vertex> vertexBuffer(nstencils);
|
||||
|
||||
|
||||
// Quick & dirty re-cast of the primvar data from our cube
|
||||
// (this is where you would drive shape deformations every frame)
|
||||
Vertex * controlValues = reinterpret_cast<Vertex *>(g_verts);
|
||||
|
||||
{ // This section would be applied every frame after control vertices have
|
||||
// been moved.
|
||||
|
||||
// Apply stencils on the control vertex data to update the primvar data
|
||||
// of the refined vertices.
|
||||
stencilTable->UpdateValues(controlValues, &vertexBuffer[0]);
|
||||
}
|
||||
|
||||
{ // Visualization with Maya : print a MEL script that generates particles
|
||||
// at the location of the refined vertices
|
||||
|
||||
printf("particle ");
|
||||
for (int i=0; i<(int)vertexBuffer.size(); ++i) {
|
||||
float const * pos = vertexBuffer[i].GetPosition();
|
||||
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
printf("-c 1;\n");
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
delete stencilTable;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static Far::TopologyRefiner *
|
||||
createTopologyRefiner() {
|
||||
|
||||
// Populate a topology descriptor with our raw data.
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
return Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_2/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_2/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_4_2
|
||||
far_tutorial_4_2.cpp
|
||||
)
|
||||
222
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_2/far_tutorial_4_2.cpp
vendored
Normal file
222
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_2/far_tutorial_4_2.cpp
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to create and manipulate both 'vertex' and 'varying'
|
||||
// Far::StencilTable to interpolate 2 primvar data buffers: vertex positions and
|
||||
// vertex colors.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/stencilTable.h>
|
||||
#include <opensubdiv/far/stencilTableFactory.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex container implementation.
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_data[0] = src._data[0];
|
||||
_data[1] = src._data[1];
|
||||
_data[2] = src._data[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_data[0]=_data[1]=_data[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_data[0]+=weight*src._data[0];
|
||||
_data[1]+=weight*src._data[1];
|
||||
_data[2]+=weight*src._data[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
float const * GetData() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
private:
|
||||
float _data[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
|
||||
static float g_verts[24] = {-0.5f, -0.5f, 0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f };
|
||||
|
||||
// Per-vertex RGB color data
|
||||
static float g_colors[24] = { 1.0f, 0.0f, 0.5f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f,
|
||||
1.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 0.0f };
|
||||
|
||||
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
static Far::TopologyRefiner * createTopologyRefiner();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
// Generate a Far::TopologyRefiner (see tutorial_1_1 for details).
|
||||
Far::TopologyRefiner * refiner = createTopologyRefiner();
|
||||
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'.
|
||||
int maxlevel = 4;
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
int nverts = refiner->GetLevel(maxlevel).GetNumVertices();
|
||||
|
||||
// Use the Far::StencilTable factory to create discrete stencil table
|
||||
Far::StencilTableFactory::Options options;
|
||||
options.generateIntermediateLevels=false; // only the highest refinement level.
|
||||
options.generateOffsets=true;
|
||||
|
||||
//
|
||||
// Vertex primvar data
|
||||
//
|
||||
|
||||
// Create stencils table for 'vertex' interpolation
|
||||
options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VERTEX;
|
||||
|
||||
Far::StencilTable const * vertexStencils =
|
||||
Far::StencilTableFactory::Create(*refiner, options);
|
||||
assert(nverts==vertexStencils->GetNumStencils());
|
||||
|
||||
// Allocate vertex primvar buffer (1 stencil for each vertex)
|
||||
std::vector<Vertex> vertexBuffer(vertexStencils->GetNumStencils());
|
||||
|
||||
// Use the cube vertex positions as 'vertex' primvar data
|
||||
Vertex * vertexCVs = reinterpret_cast<Vertex *>(g_verts);
|
||||
|
||||
//
|
||||
// Varying primvar data
|
||||
//
|
||||
|
||||
// Create stencils table for 'varying' interpolation
|
||||
options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VARYING;
|
||||
|
||||
Far::StencilTable const * varyingStencils =
|
||||
Far::StencilTableFactory::Create(*refiner, options);
|
||||
assert(nverts==varyingStencils->GetNumStencils());
|
||||
|
||||
// Allocate varying primvar buffer (1 stencil for each vertex)
|
||||
std::vector<Vertex> varyingBuffer(varyingStencils->GetNumStencils());
|
||||
|
||||
// Use per-vertex array of RGB colors as 'varying' primvar data
|
||||
Vertex * varyingCVs = reinterpret_cast<Vertex *>(g_colors);
|
||||
|
||||
delete refiner;
|
||||
|
||||
//
|
||||
// Apply stencils (in frame loop)
|
||||
//
|
||||
|
||||
{ // This section would be applied every frame after control vertices have
|
||||
// been moved.
|
||||
|
||||
// Apply stencils on the control vertex data to update the primvar data
|
||||
// of the refined vertices.
|
||||
|
||||
vertexStencils->UpdateValues(vertexCVs, &vertexBuffer[0]);
|
||||
|
||||
varyingStencils->UpdateValues(varyingCVs, &varyingBuffer[0]);
|
||||
}
|
||||
|
||||
{ // Visualization with Maya : print a MEL script that generates particles
|
||||
// at the location of the refined vertices
|
||||
|
||||
printf("particle ");
|
||||
for (int vert=0; vert<(int)nverts; ++vert) {
|
||||
float const * pos = vertexBuffer[vert].GetData();
|
||||
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
printf("-c 1;\n");
|
||||
|
||||
// Set particle point size (20 -- very large)
|
||||
printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n");
|
||||
|
||||
// Add per-particle color attribute ('rgbPP')
|
||||
printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n");
|
||||
|
||||
// Set per-particle color values from our 'varying' primvar data
|
||||
printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts);
|
||||
for (int vert=0; vert<nverts; ++vert) {
|
||||
float const * color = varyingBuffer[vert].GetData();
|
||||
printf("%f %f %f\n", color[0], color[1], color[2]);
|
||||
}
|
||||
printf(";\n");
|
||||
}
|
||||
|
||||
delete vertexStencils;
|
||||
delete varyingStencils;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static Far::TopologyRefiner *
|
||||
createTopologyRefiner() {
|
||||
|
||||
// Populate a topology descriptor with our raw data.
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
return refiner;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_3/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_3/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_4_3
|
||||
far_tutorial_4_3.cpp
|
||||
)
|
||||
222
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_3/far_tutorial_4_3.cpp
vendored
Normal file
222
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_4_3/far_tutorial_4_3.cpp
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to create and manipulate table of cascading stencils.
|
||||
//
|
||||
// We initialize a Far::TopologyRefiner with a cube and apply uniform
|
||||
// refinement. We then use a Far::StencilTableFactory to generate a stencil
|
||||
// table. We set the factory Options to not factorize intermediate levels,
|
||||
// thus giving a table of "cascading" stencils.
|
||||
//
|
||||
// We then apply the stencils to the vertex position primvar data, and insert
|
||||
// a hierarchical edit at level 1. This edit is smoothed by the application
|
||||
// of the subsequent stencil cascades.
|
||||
//
|
||||
// The results are dumped into an OBJ file that shows the intermediate levels
|
||||
// of refinement of the original cube.
|
||||
//
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/stencilTable.h>
|
||||
#include <opensubdiv/far/stencilTableFactory.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex container implementation.
|
||||
//
|
||||
struct Vertex {
|
||||
|
||||
// Minimal required interface ----------------------
|
||||
Vertex() { }
|
||||
|
||||
Vertex(Vertex const & src) {
|
||||
_position[0] = src._position[0];
|
||||
_position[1] = src._position[1];
|
||||
_position[2] = src._position[2];
|
||||
}
|
||||
|
||||
void Clear( void * =0 ) {
|
||||
_position[0]=_position[1]=_position[2]=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(Vertex const & src, float weight) {
|
||||
_position[0]+=weight*src._position[0];
|
||||
_position[1]+=weight*src._position[1];
|
||||
_position[2]+=weight*src._position[2];
|
||||
}
|
||||
|
||||
// Public interface ------------------------------------
|
||||
void SetPosition(float x, float y, float z) {
|
||||
_position[0]=x;
|
||||
_position[1]=y;
|
||||
_position[2]=z;
|
||||
}
|
||||
|
||||
float const * GetPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
float * GetPosition() {
|
||||
return _position;
|
||||
}
|
||||
|
||||
private:
|
||||
float _position[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cube geometry from catmark_cube.h
|
||||
|
||||
static float g_verts[24] = {-0.5f, -0.5f, 0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f };
|
||||
|
||||
static int g_nverts = 8,
|
||||
g_nfaces = 6;
|
||||
|
||||
static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };
|
||||
|
||||
static int g_vertIndices[24] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4 };
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
static Far::TopologyRefiner * createTopologyRefiner();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
// Generate a Far::TopologyRefiner (see tutorial_1_1 for details).
|
||||
Far::TopologyRefiner * refiner = createTopologyRefiner();
|
||||
|
||||
// Uniformly refine the topology up to 'maxlevel'.
|
||||
int maxlevel = 4;
|
||||
refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));
|
||||
|
||||
// Use the Far::StencilTable factory to create cascading stencil table
|
||||
// note: we want stencils for each refinement level
|
||||
// "cascade" mode is achieved by setting "factorizeIntermediateLevels"
|
||||
// to false
|
||||
Far::StencilTableFactory::Options options;
|
||||
options.generateIntermediateLevels=true;
|
||||
options.factorizeIntermediateLevels=false;
|
||||
options.generateOffsets=true;
|
||||
|
||||
Far::StencilTable const * stencilTable =
|
||||
Far::StencilTableFactory::Create(*refiner, options);
|
||||
|
||||
std::vector<Vertex> vertexBuffer(refiner->GetNumVerticesTotal()-g_nverts);
|
||||
|
||||
Vertex * destVerts = &vertexBuffer[0];
|
||||
|
||||
int start = 0, end = 0; // stencil batches for each level of subdivision
|
||||
for (int level=0; level<maxlevel; ++level) {
|
||||
|
||||
int nverts = refiner->GetLevel(level+1).GetNumVertices();
|
||||
|
||||
Vertex const * srcVerts = reinterpret_cast<Vertex *>(g_verts);
|
||||
if (level>0) {
|
||||
srcVerts = &vertexBuffer[start];
|
||||
}
|
||||
|
||||
start = end;
|
||||
end += nverts;
|
||||
|
||||
stencilTable->UpdateValues(srcVerts, destVerts, start, end);
|
||||
|
||||
// apply 2 hierarchical edits on level 1 vertices
|
||||
if (level==1) {
|
||||
float * pos = destVerts[start+5].GetPosition();
|
||||
pos[1] += 0.5f;
|
||||
|
||||
pos = destVerts[start+20].GetPosition();
|
||||
pos[0] += 0.25f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // Output OBJ of the highest level refined -----------
|
||||
|
||||
Vertex * verts = &vertexBuffer[0];
|
||||
|
||||
// Print vertex positions
|
||||
for (int level=1, firstvert=0; level<=maxlevel; ++level) {
|
||||
|
||||
Far::TopologyLevel const & refLevel = refiner->GetLevel(level);
|
||||
|
||||
printf("g level_%d\n", level);
|
||||
|
||||
int nverts = refLevel.GetNumVertices();
|
||||
for (int vert=0; vert<nverts; ++vert) {
|
||||
float const * pos = verts[vert].GetPosition();
|
||||
printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
|
||||
}
|
||||
verts += nverts;
|
||||
|
||||
// Print faces
|
||||
for (int face=0; face<refLevel.GetNumFaces(); ++face) {
|
||||
|
||||
Far::ConstIndexArray fverts = refLevel.GetFaceVertices(face);
|
||||
|
||||
// all refined Catmark faces should be quads
|
||||
assert(fverts.size()==4);
|
||||
|
||||
printf("f ");
|
||||
for (int vert=0; vert<fverts.size(); ++vert) {
|
||||
printf("%d ", fverts[vert]+firstvert+1); // OBJ uses 1-based arrays...
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
firstvert+=nverts;
|
||||
}
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
delete stencilTable;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static Far::TopologyRefiner *
|
||||
createTopologyRefiner() {
|
||||
|
||||
// Populate a topology descriptor with our raw data.
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_vertIndices;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
return Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_1/CMakeLists.txt
vendored
Normal file
10
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_1/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_5_1
|
||||
far_tutorial_5_1.cpp
|
||||
)
|
||||
321
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_1/far_tutorial_5_1.cpp
vendored
Normal file
321
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_1/far_tutorial_5_1.cpp
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/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 at 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 <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
#include <opensubdiv/far/patchTableFactory.h>
|
||||
#include <opensubdiv/far/patchMap.h>
|
||||
#include <opensubdiv/far/ptexIndices.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cfloat>
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
typedef double Real;
|
||||
|
||||
// pyramid geometry from catmark_pyramid_crease0.h
|
||||
static int const g_nverts = 5;
|
||||
static Real 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, Real weight) {
|
||||
point[0] += weight * src.point[0];
|
||||
point[1] += weight * src.point[1];
|
||||
point[2] += weight * src.point[2];
|
||||
}
|
||||
|
||||
Real point[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Limit frame container implementation -- this interface is not strictly
|
||||
// required but follows a similar pattern to Vertex.
|
||||
//
|
||||
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,
|
||||
Real weight, Real d1Weight, Real 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];
|
||||
}
|
||||
|
||||
Real point[3],
|
||||
deriv1[3],
|
||||
deriv2[3];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char **) {
|
||||
|
||||
// Generate a Far::TopologyRefiner (see tutorial_1_1 for details).
|
||||
Far::TopologyRefiner * refiner = createTopologyRefiner();
|
||||
|
||||
// Patches are constructed from adaptively refined faces, but the processes
|
||||
// of constructing the PatchTable and of applying adaptive refinement have
|
||||
// historically been separate. Adaptive refinement is applied purely to
|
||||
// satisfy the needs of the desired PatchTable, so options associated with
|
||||
// adaptive refinement should be derived from those specified for the
|
||||
// PatchTable. This is not a strict requirement, but it will avoid
|
||||
// problems arising from specifying/coordinating the two independently
|
||||
// (especially when dealing with face-varying patches).
|
||||
|
||||
// Initialize options for the PatchTable:
|
||||
//
|
||||
// Choose patches adaptively refined to level 3 since the sharpest crease
|
||||
// in the shape is 3.0f (in g_creaseweights[]), and include the inf-sharp
|
||||
// crease option just to illustrate the need to syncronize options.
|
||||
//
|
||||
int maxPatchLevel = 3;
|
||||
|
||||
Far::PatchTableFactory::Options patchOptions(maxPatchLevel);
|
||||
patchOptions.SetPatchPrecision<Real>();
|
||||
patchOptions.useInfSharpPatch = true;
|
||||
patchOptions.generateVaryingTables = false;
|
||||
patchOptions.endCapType =
|
||||
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
|
||||
|
||||
// Initialize corresonding options for adaptive refinement:
|
||||
Far::TopologyRefiner::AdaptiveOptions adaptiveOptions(maxPatchLevel);
|
||||
|
||||
bool assignAdaptiveOptionsExplicitly = false;
|
||||
if (assignAdaptiveOptionsExplicitly) {
|
||||
adaptiveOptions.useInfSharpPatch = true;
|
||||
} else {
|
||||
// Be sure patch options were intialized with the desired max level
|
||||
adaptiveOptions = patchOptions.GetRefineAdaptiveOptions();
|
||||
}
|
||||
assert(adaptiveOptions.useInfSharpPatch == patchOptions.useInfSharpPatch);
|
||||
|
||||
// Apply adaptive refinement and construct the associated PatchTable to
|
||||
// evaluate the limit surface:
|
||||
refiner->RefineAdaptive(adaptiveOptions);
|
||||
|
||||
Far::PatchTable const * patchTable =
|
||||
Far::PatchTableFactory::Create(*refiner, patchOptions);
|
||||
|
||||
// Compute the total number of points we need to evaluate the PatchTable.
|
||||
// Approximations at irregular or extraordinary features require the use
|
||||
// of additional points associated with the patches that are referred to
|
||||
// as "local points" (i.e. local to the PatchTable).
|
||||
int nRefinerVertices = refiner->GetNumVerticesTotal();
|
||||
int nLocalPoints = patchTable->GetNumLocalPoints();
|
||||
|
||||
// Create a buffer to hold the position of the refined verts and
|
||||
// local points, then copy the coarse positions at the beginning.
|
||||
std::vector<Vertex> verts(nRefinerVertices + nLocalPoints);
|
||||
std::memcpy(&verts[0], g_verts, g_nverts*3*sizeof(Real));
|
||||
|
||||
// Adaptive refinement may result in fewer levels than the max specified.
|
||||
int nRefinedLevels = refiner->GetNumLevels();
|
||||
|
||||
// Interpolate vertex primvar data : they are the control vertices
|
||||
// of the limit patches (see tutorial_1_1 for details)
|
||||
Far::PrimvarRefinerReal<Real> primvarRefiner(*refiner);
|
||||
|
||||
Vertex * src = &verts[0];
|
||||
for (int level = 1; level < nRefinedLevels; ++level) {
|
||||
Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices();
|
||||
primvarRefiner.Interpolate(level, src, dst);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
// Evaluate local points from interpolated vertex primvars.
|
||||
if (nLocalPoints) {
|
||||
patchTable->GetLocalPointStencilTable<Real>()->UpdateValues(
|
||||
&verts[0], &verts[nRefinerVertices]);
|
||||
}
|
||||
|
||||
// Create a Far::PatchMap to help locating patches in the table
|
||||
Far::PatchMap patchmap(*patchTable);
|
||||
|
||||
// Create a Far::PtexIndices to help find indices of ptex faces.
|
||||
Far::PtexIndices ptexIndices(*refiner);
|
||||
|
||||
// Generate random samples on each ptex face
|
||||
int nsamplesPerFace = 200,
|
||||
nfaces = ptexIndices.GetNumFaces();
|
||||
|
||||
std::vector<LimitFrame> samples(nsamplesPerFace * nfaces);
|
||||
|
||||
srand( static_cast<int>(2147483647) );
|
||||
|
||||
Real pWeights[20], dsWeights[20], dtWeights[20];
|
||||
|
||||
for (int face=0, count=0; face<nfaces; ++face) {
|
||||
|
||||
for (int sample=0; sample<nsamplesPerFace; ++sample, ++count) {
|
||||
|
||||
Real s = (Real)rand()/(Real)RAND_MAX,
|
||||
t = (Real)rand()/(Real)RAND_MAX;
|
||||
|
||||
// Locate the patch corresponding to the face ptex idx and (s,t)
|
||||
Far::PatchTable::PatchHandle const * handle =
|
||||
patchmap.FindPatch(face, s, t);
|
||||
assert(handle);
|
||||
|
||||
// Evaluate the patch weights, identify the CVs and compute the limit frame:
|
||||
patchTable->EvaluateBasis(*handle, s, t, pWeights, dsWeights, dtWeights);
|
||||
|
||||
Far::ConstIndexArray cvs = patchTable->GetPatchVertices(*handle);
|
||||
|
||||
LimitFrame & dst = samples[count];
|
||||
dst.Clear();
|
||||
for (int cv=0; cv < cvs.size(); ++cv) {
|
||||
dst.AddWithWeight(verts[cvs[cv]], pWeights[cv], dsWeights[cv], dtWeights[cv]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{ // 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) {
|
||||
Real 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) {
|
||||
Real 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) {
|
||||
Real 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) {
|
||||
Real 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");
|
||||
}
|
||||
|
||||
delete refiner;
|
||||
delete patchTable;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static Far::TopologyRefiner *
|
||||
createTopologyRefiner() {
|
||||
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = g_nverts;
|
||||
desc.numFaces = g_nfaces;
|
||||
desc.numVertsPerFace = g_vertsperface;
|
||||
desc.vertIndicesPerFace = g_faceverts;
|
||||
desc.numCreases = g_ncreases;
|
||||
desc.creaseVertexIndexPairs = g_creaseverts;
|
||||
desc.creaseWeights = g_creaseweights;
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
|
||||
|
||||
return refiner;
|
||||
}
|
||||
11
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_2/CMakeLists.txt
vendored
Normal file
11
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_2/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright 2018 DreamWorks Animation LLC.
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_5_2
|
||||
far_tutorial_5_2.cpp
|
||||
$<TARGET_OBJECTS:regression_common_obj>
|
||||
)
|
||||
643
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_2/far_tutorial_5_2.cpp
vendored
Normal file
643
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_2/far_tutorial_5_2.cpp
vendored
Normal file
@@ -0,0 +1,643 @@
|
||||
//
|
||||
// Copyright 2018 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to manage the limit surface of a potentially
|
||||
// large mesh by creating groups of patches for selected faces of the
|
||||
// mesh. Familiarity with construction and evaluation of a PatchTable
|
||||
// is assumed (see tutorial_5_1).
|
||||
//
|
||||
// When the patches for a mesh do not need to be retained for further
|
||||
// use, e.g. when simply computing points for a tessellation, the time
|
||||
// and space required to construct a single large PatchTable can be
|
||||
// considerable. By constructing, evaluating and discarding smaller
|
||||
// PatchTables for subsets of the mesh, the high transient memory cost
|
||||
// can be avoided when computed serially. When computed in parallel,
|
||||
// there may be little memory savings, but the construction time can
|
||||
// then be distributed.
|
||||
//
|
||||
// This tutorial creates simple geometry (currently a lattice of cubes)
|
||||
// that can be expanded in complexity with a simple multiplier. The
|
||||
// collection of faces are then divided into a specified number of groups
|
||||
// from which patches will be constructed and evaluated. A simple
|
||||
// tessellation (a triangle fan around the midpoint of each face) is then
|
||||
// written in Obj format to the standard output.
|
||||
//
|
||||
|
||||
#include "../../../regression/common/arg_utils.h"
|
||||
#include "../../../regression/common/far_utils.h"
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
#include <opensubdiv/far/patchTableFactory.h>
|
||||
#include <opensubdiv/far/patchMap.h>
|
||||
#include <opensubdiv/far/ptexIndices.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
using Far::Index;
|
||||
|
||||
|
||||
//
|
||||
// Global utilities in this namespace are not relevant to the tutorial.
|
||||
// They simply serve to construct some default geometry to be processed
|
||||
// in the form of a TopologyRefiner and vector of vertex positions.
|
||||
//
|
||||
namespace {
|
||||
//
|
||||
// Simple structs for (x,y,z) position and a 3-tuple for the set
|
||||
// of vertices of a triangle:
|
||||
//
|
||||
struct Pos {
|
||||
Pos() { }
|
||||
Pos(float x, float y, float z) { p[0] = x, p[1] = y, p[2] = z; }
|
||||
|
||||
Pos operator+(Pos const & op) const {
|
||||
return Pos(p[0] + op.p[0], p[1] + op.p[1], p[2] + op.p[2]);
|
||||
}
|
||||
|
||||
// Clear() and AddWithWeight() required for interpolation:
|
||||
void Clear( void * =0 ) { p[0] = p[1] = p[2] = 0.0f; }
|
||||
|
||||
void AddWithWeight(Pos const & src, float weight) {
|
||||
p[0] += weight * src.p[0];
|
||||
p[1] += weight * src.p[1];
|
||||
p[2] += weight * src.p[2];
|
||||
}
|
||||
|
||||
float p[3];
|
||||
};
|
||||
typedef std::vector<Pos> PosVector;
|
||||
|
||||
struct Tri {
|
||||
Tri() { }
|
||||
Tri(int a, int b, int c) { v[0] = a, v[1] = b, v[2] = c; }
|
||||
|
||||
int v[3];
|
||||
};
|
||||
typedef std::vector<Tri> TriVector;
|
||||
|
||||
|
||||
//
|
||||
// Functions to populate the topology and geometry arrays with simple
|
||||
// shapes that we can multiply to increase complexity:
|
||||
//
|
||||
void
|
||||
appendDefaultPrimitive(Pos const & origin,
|
||||
std::vector<int> & vertsPerFace,
|
||||
std::vector<Index> & faceVerts,
|
||||
std::vector<Pos> & positionsPerVert) {
|
||||
|
||||
// Local topology and position of a cube centered at origin:
|
||||
static float const cubePositions[8][3] = { { -0.5f, -0.5f, -0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f } };
|
||||
|
||||
static int const cubeFaceVerts[6][4] = { { 0, 3, 2, 1 },
|
||||
{ 4, 5, 6, 7 },
|
||||
{ 0, 4, 7, 3 },
|
||||
{ 1, 2, 6, 5 },
|
||||
{ 0, 1, 5, 4 },
|
||||
{ 3, 7, 6, 2 } };
|
||||
|
||||
// Identify the next vertex before appending vertex positions:
|
||||
int baseVertex = (int) positionsPerVert.size();
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
float const * p = cubePositions[i];
|
||||
positionsPerVert.push_back(origin + Pos(p[0], p[1], p[2]));
|
||||
}
|
||||
|
||||
// Append number of verts-per-face and face-vertices for each face:
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
vertsPerFace.push_back(4);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
faceVerts.push_back(baseVertex + cubeFaceVerts[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
createDefaultGeometry(int multiplier,
|
||||
std::vector<int> & vertsPerFace,
|
||||
std::vector<Index> & faceVerts,
|
||||
std::vector<Pos> & positionsPerVert) {
|
||||
|
||||
// Default primitive is currently a cube:
|
||||
int const vertsPerPrimitive = 8;
|
||||
int const facesPerPrimitive = 6;
|
||||
int const faceVertsPerPrimitive = 24;
|
||||
|
||||
int nPrimitives = multiplier * multiplier * multiplier;
|
||||
|
||||
positionsPerVert.reserve(nPrimitives * vertsPerPrimitive);
|
||||
vertsPerFace.reserve(nPrimitives * facesPerPrimitive);
|
||||
faceVerts.reserve(nPrimitives * faceVertsPerPrimitive);
|
||||
|
||||
for (int x = 0; x < multiplier; ++x) {
|
||||
for (int y = 0; y < multiplier; ++y) {
|
||||
for (int z = 0; z < multiplier; ++z) {
|
||||
appendDefaultPrimitive(
|
||||
Pos((float)x * 2.0f, (float)y * 2.0f, (float)z * 2.0f),
|
||||
vertsPerFace, faceVerts, positionsPerVert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create a TopologyRefiner from default geometry created above:
|
||||
//
|
||||
Far::TopologyRefiner *
|
||||
createTopologyRefinerDefault(int multiplier,
|
||||
PosVector & posVector) {
|
||||
|
||||
std::vector<int> topVertsPerFace;
|
||||
std::vector<Index> topFaceVerts;
|
||||
|
||||
createDefaultGeometry(
|
||||
multiplier, topVertsPerFace, topFaceVerts, posVector);
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(
|
||||
Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = (int) posVector.size();
|
||||
desc.numFaces = (int) topVertsPerFace.size();
|
||||
desc.numVertsPerFace = &topVertsPerFace[0];
|
||||
desc.vertIndicesPerFace = &topFaceVerts[0];
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(
|
||||
type, options));
|
||||
|
||||
if (refiner == 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
bool dumpDefaultGeometryToObj = false;
|
||||
if (dumpDefaultGeometryToObj) {
|
||||
int nVerts = (int) posVector.size();
|
||||
for (int i = 0; i < nVerts; ++i) {
|
||||
float const * p = posVector[i].p;
|
||||
printf("v %f %f %f\n", p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
int const * fVerts = &topFaceVerts[0];
|
||||
int nFaces = (int) topVertsPerFace.size();
|
||||
for (int i = 0; i < nFaces; ++i) {
|
||||
printf("f");
|
||||
for (int j = 0; j < topVertsPerFace[i]; ++j) {
|
||||
printf(" %d", 1 + *fVerts++);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
return refiner;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a TopologyRefiner from a specified Obj file:
|
||||
// geometry created internally:
|
||||
//
|
||||
Far::TopologyRefiner *
|
||||
createTopologyRefinerFromObj(std::string const & objFileName,
|
||||
Sdc::SchemeType schemeType,
|
||||
PosVector & posVector) {
|
||||
|
||||
const char * filename = objFileName.c_str();
|
||||
const Shape * shape = 0;
|
||||
|
||||
std::ifstream ifs(filename);
|
||||
if (ifs) {
|
||||
std::stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
std::string shapeString = ss.str();
|
||||
|
||||
shape = Shape::parseObj(shapeString.c_str(),
|
||||
ConvertSdcTypeToShapeScheme(schemeType), false);
|
||||
if (shape == 0) {
|
||||
fprintf(stderr, "Error: Cannot create Shape "
|
||||
"from .obj file '%s'\n", filename);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error: Cannot open .obj file '%s'\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sdc::SchemeType sdcType = GetSdcType(*shape);
|
||||
Sdc::Options sdcOptions = GetSdcOptions(*shape);
|
||||
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Shape>::Create(*shape,
|
||||
Far::TopologyRefinerFactory<Shape>::Options(
|
||||
sdcType, sdcOptions));
|
||||
if (refiner == 0) {
|
||||
fprintf(stderr, "Error: Unable to construct TopologyRefiner "
|
||||
"from .obj file '%s'\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numVertices = refiner->GetNumVerticesTotal();
|
||||
posVector.resize(numVertices);
|
||||
std::memcpy(&posVector[0].p[0], &shape->verts[0],
|
||||
numVertices * 3 * sizeof(float));
|
||||
|
||||
delete shape;
|
||||
return refiner;
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
|
||||
//
|
||||
// The PatchGroup bundles objects used to create and evaluate a sparse set
|
||||
// of patches. Its construction creates a PatchTable and all other objects
|
||||
// necessary to evaluate patches associated with the specified subset of
|
||||
// faces provided. A simple method to tessellate a specified face is
|
||||
// provided.
|
||||
//
|
||||
// Note that, since the data buffers for the base level and refined levels
|
||||
// are separate (we want to avoid copying primvar data for the base level
|
||||
// of a potentially large mesh), that patch evaluation needs to account
|
||||
// for the separation when combining control points.
|
||||
//
|
||||
struct PatchGroup {
|
||||
PatchGroup(Far::PatchTableFactory::Options patchOptions,
|
||||
Far::TopologyRefiner const & baseRefinerArg,
|
||||
Far::PtexIndices const & basePtexIndicesArg,
|
||||
std::vector<Pos> const & basePositionsArg,
|
||||
std::vector<Index> const & baseFacesArg);
|
||||
~PatchGroup();
|
||||
|
||||
void TessellateBaseFace(int face, PosVector & tessPoints,
|
||||
TriVector & tessTris) const;
|
||||
|
||||
// Const reference members:
|
||||
Far::TopologyRefiner const & baseRefiner;
|
||||
Far::PtexIndices const & basePtexIndices;
|
||||
std::vector<Pos> const & basePositions;
|
||||
std::vector<Index> const & baseFaces;
|
||||
|
||||
// Members constructed to evaluate patches:
|
||||
Far::PatchTable * patchTable;
|
||||
Far::PatchMap * patchMap;
|
||||
int patchFaceSize;
|
||||
std::vector<Pos> localPositions;
|
||||
};
|
||||
|
||||
PatchGroup::PatchGroup(Far::PatchTableFactory::Options patchOptions,
|
||||
Far::TopologyRefiner const & baseRefinerArg,
|
||||
Far::PtexIndices const & basePtexIndicesArg,
|
||||
std::vector<Pos> const & basePositionsArg,
|
||||
std::vector<Index> const & baseFacesArg) :
|
||||
baseRefiner(baseRefinerArg),
|
||||
basePtexIndices(basePtexIndicesArg),
|
||||
basePositions(basePositionsArg),
|
||||
baseFaces(baseFacesArg) {
|
||||
|
||||
// Create a local refiner (sharing the base level), apply adaptive
|
||||
// refinement to the given subset of base faces, and construct a patch
|
||||
// table (and its associated map) for the same set of faces:
|
||||
//
|
||||
Far::ConstIndexArray groupFaces(&baseFaces[0], (int)baseFaces.size());
|
||||
|
||||
Far::TopologyRefiner *localRefiner =
|
||||
Far::TopologyRefinerFactory<Far::TopologyDescriptor>::Create(
|
||||
baseRefiner);
|
||||
|
||||
localRefiner->RefineAdaptive(
|
||||
patchOptions.GetRefineAdaptiveOptions(), groupFaces);
|
||||
|
||||
patchTable = Far::PatchTableFactory::Create(*localRefiner, patchOptions,
|
||||
groupFaces);
|
||||
|
||||
patchMap = new Far::PatchMap(*patchTable);
|
||||
|
||||
patchFaceSize =
|
||||
Sdc::SchemeTypeTraits::GetRegularFaceSize(baseRefiner.GetSchemeType());
|
||||
|
||||
// Compute the number of refined and local points needed to evaluate the
|
||||
// patches, allocate and interpolate. This varies from tutorial_5_1 in
|
||||
// that the primvar buffer for the base vertices is separate from the
|
||||
// refined vertices and local patch points (which must also be accounted
|
||||
// for when evaluating the patches).
|
||||
//
|
||||
int nBaseVertices = localRefiner->GetLevel(0).GetNumVertices();
|
||||
int nRefinedVertices = localRefiner->GetNumVerticesTotal() - nBaseVertices;
|
||||
int nLocalPoints = patchTable->GetNumLocalPoints();
|
||||
|
||||
localPositions.resize(nRefinedVertices + nLocalPoints);
|
||||
|
||||
if (nRefinedVertices) {
|
||||
Far::PrimvarRefiner primvarRefiner(*localRefiner);
|
||||
|
||||
Pos const * src = &basePositions[0];
|
||||
Pos * dst = &localPositions[0];
|
||||
for (int level = 1; level < localRefiner->GetNumLevels(); ++level) {
|
||||
primvarRefiner.Interpolate(level, src, dst);
|
||||
src = dst;
|
||||
dst += localRefiner->GetLevel(level).GetNumVertices();
|
||||
}
|
||||
}
|
||||
if (nLocalPoints) {
|
||||
patchTable->GetLocalPointStencilTable()->UpdateValues(
|
||||
&basePositions[0], nBaseVertices, &localPositions[0],
|
||||
&localPositions[nRefinedVertices]);
|
||||
}
|
||||
|
||||
delete localRefiner;
|
||||
}
|
||||
|
||||
PatchGroup::~PatchGroup() {
|
||||
delete patchTable;
|
||||
delete patchMap;
|
||||
}
|
||||
|
||||
void
|
||||
PatchGroup::TessellateBaseFace(int face, PosVector & tessPoints,
|
||||
TriVector & tessTris) const {
|
||||
|
||||
// Tesselate the face with points at the midpoint of the face and at
|
||||
// each corner, and triangles connecting the midpoint to each edge.
|
||||
// Irregular faces require an aribrary number of corners points, but
|
||||
// all are at the origin of the child face of the irregular base face:
|
||||
//
|
||||
float const quadPoints[5][2] = { { 0.5f, 0.5f },
|
||||
{ 0.0f, 0.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 0.0f, 1.0f } };
|
||||
|
||||
float const triPoints[4][2] = { { 0.5f, 0.5f },
|
||||
{ 0.0f, 0.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 1.0f } };
|
||||
|
||||
float const irregPoints[4][2] = { { 1.0f, 1.0f },
|
||||
{ 0.0f, 0.0f } };
|
||||
|
||||
// Determine the topology of the given base face and the resulting
|
||||
// tessellation points and faces to generate:
|
||||
//
|
||||
int baseFace = baseFaces[face];
|
||||
int faceSize = baseRefiner.GetLevel(0).GetFaceVertices(baseFace).size();
|
||||
|
||||
bool faceIsIrregular = (faceSize != patchFaceSize);
|
||||
|
||||
int nTessPoints = faceSize + 1;
|
||||
int nTessFaces = faceSize;
|
||||
|
||||
tessPoints.resize(nTessPoints);
|
||||
tessTris.resize(nTessFaces);
|
||||
|
||||
// Compute the mid and corner points -- remember that for an irregular
|
||||
// face, we must reference the individual ptex faces for each corner:
|
||||
//
|
||||
int ptexFace = basePtexIndices.GetFaceId(baseFace);
|
||||
|
||||
int numBaseVerts = (int) basePositions.size();
|
||||
|
||||
for (int i = 0; i < nTessPoints; ++i) {
|
||||
// Choose the (s,t) coordinate from the fixed tessellation:
|
||||
float const * st = faceIsIrregular ? irregPoints[i != 0]
|
||||
: ((faceSize == 4) ? quadPoints[i] : triPoints[i]);
|
||||
|
||||
// Locate the patch corresponding to the face ptex idx and (s,t)
|
||||
// and evaluate:
|
||||
int patchFace = ptexFace;
|
||||
if (faceIsIrregular && (i > 0)) {
|
||||
patchFace += i - 1;
|
||||
}
|
||||
Far::PatchTable::PatchHandle const * handle =
|
||||
patchMap->FindPatch(patchFace, st[0], st[1]);
|
||||
assert(handle);
|
||||
|
||||
float pWeights[20];
|
||||
patchTable->EvaluateBasis(*handle, st[0], st[1], pWeights);
|
||||
|
||||
// Identify the patch cvs and combine with the evaluated weights --
|
||||
// remember to distinguish cvs in the base level:
|
||||
Far::ConstIndexArray cvIndices = patchTable->GetPatchVertices(*handle);
|
||||
|
||||
Pos & pos = tessPoints[i];
|
||||
pos.Clear();
|
||||
for (int cv = 0; cv < cvIndices.size(); ++cv) {
|
||||
int cvIndex = cvIndices[cv];
|
||||
if (cvIndex < numBaseVerts) {
|
||||
pos.AddWithWeight(basePositions[cvIndex],
|
||||
pWeights[cv]);
|
||||
} else {
|
||||
pos.AddWithWeight(localPositions[cvIndex - numBaseVerts],
|
||||
pWeights[cv]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign triangles connecting the midpoint of the base face to the
|
||||
// points computed at the ends of each of its edges:
|
||||
//
|
||||
for (int i = 0; i < nTessFaces; ++i) {
|
||||
tessTris[i] = Tri(0, 1 + i, 1 + ((i + 1) % faceSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Command line arguments parsed to provide run-time options:
|
||||
//
|
||||
class Args {
|
||||
public:
|
||||
std::string inputObjFile;
|
||||
Sdc::SchemeType schemeType;
|
||||
int geoMultiplier;
|
||||
int maxPatchDepth;
|
||||
int numPatchGroups;
|
||||
bool noTessFlag;
|
||||
bool noOutputFlag;
|
||||
|
||||
public:
|
||||
Args(int argc, char ** argv) :
|
||||
inputObjFile(),
|
||||
schemeType(Sdc::SCHEME_CATMARK),
|
||||
geoMultiplier(10),
|
||||
maxPatchDepth(3),
|
||||
numPatchGroups(10),
|
||||
noTessFlag(false),
|
||||
noOutputFlag(false) {
|
||||
|
||||
// Parse and assign standard arguments and Obj files:
|
||||
ArgOptions args;
|
||||
args.Parse(argc, argv);
|
||||
|
||||
maxPatchDepth = args.GetLevel();
|
||||
schemeType = ConvertShapeSchemeToSdcType(args.GetDefaultScheme());
|
||||
|
||||
const std::vector<const char *> objFiles = args.GetObjFiles();
|
||||
if (!objFiles.empty()) {
|
||||
for (size_t i = 1; i < objFiles.size(); ++i) {
|
||||
fprintf(stderr,
|
||||
"Warning: .obj file '%s' ignored\n", objFiles[i]);
|
||||
}
|
||||
inputObjFile = std::string(objFiles[0]);
|
||||
}
|
||||
|
||||
// Parse remaining arguments specific to this example:
|
||||
const std::vector<const char *> &rargs = args.GetRemainingArgs();
|
||||
for (size_t i = 0; i < rargs.size(); ++i) {
|
||||
if (!strcmp(rargs[i], "-groups")) {
|
||||
if (++i < rargs.size()) numPatchGroups = atoi(rargs[i]);
|
||||
} else if (!strcmp(rargs[i], "-mult")) {
|
||||
if (++i < rargs.size()) geoMultiplier = atoi(rargs[i]);
|
||||
} else if (!strcmp(rargs[i], "-notess")) {
|
||||
noTessFlag = true;
|
||||
} else if (!strcmp(rargs[i], "-nooutput")) {
|
||||
noOutputFlag = true;
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Argument '%s' ignored\n", rargs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Args() { }
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Load command line arguments and geometry, then divide the mesh into groups
|
||||
// of faces from which to create and tessellate patches:
|
||||
//
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
|
||||
Args args(argc, argv);
|
||||
|
||||
//
|
||||
// Create or load the base geometry (command line arguments allow a
|
||||
// .obj file to be specified). In addition to the TopologyRefiner
|
||||
// and set of positions for the base vertices, a set of PtexIndices is
|
||||
// also required to evaluate patches, so build it here once for use
|
||||
// elsewhere:
|
||||
//
|
||||
std::vector<Pos> basePositions;
|
||||
|
||||
Far::TopologyRefiner * baseRefinerPtr = args.inputObjFile.empty() ?
|
||||
createTopologyRefinerDefault(args.geoMultiplier, basePositions) :
|
||||
createTopologyRefinerFromObj(args.inputObjFile, args.schemeType,
|
||||
basePositions);
|
||||
assert(baseRefinerPtr);
|
||||
Far::TopologyRefiner & baseRefiner = *baseRefinerPtr;
|
||||
|
||||
Far::PtexIndices basePtexIndices(baseRefiner);
|
||||
|
||||
//
|
||||
// Determine the sizes of the patch groups specified -- there will be
|
||||
// two sizes that differ by one to account for unequal division:
|
||||
//
|
||||
int numBaseFaces = baseRefiner.GetNumFacesTotal();
|
||||
|
||||
int numPatchGroups = args.numPatchGroups;
|
||||
if (numPatchGroups > numBaseFaces) {
|
||||
numPatchGroups = numBaseFaces;
|
||||
} else if (numPatchGroups < 1) {
|
||||
numPatchGroups = 1;
|
||||
}
|
||||
int lesserGroupSize = numBaseFaces / numPatchGroups;
|
||||
int numLargerGroups = numBaseFaces - (numPatchGroups * lesserGroupSize);
|
||||
|
||||
//
|
||||
// Define the options used to construct the patches for each group.
|
||||
// Unless suppressed, a tessellation in Obj format will also be printed
|
||||
// to standard output, so keep track of the vertex indices.
|
||||
//
|
||||
Far::PatchTableFactory::Options patchOptions(args.maxPatchDepth);
|
||||
patchOptions.generateVaryingTables = false;
|
||||
patchOptions.shareEndCapPatchPoints = false;
|
||||
patchOptions.endCapType =
|
||||
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
|
||||
|
||||
int objVertCount = 0;
|
||||
|
||||
PosVector tessPoints;
|
||||
TriVector tessFaces;
|
||||
|
||||
for (int i = 0; i < numPatchGroups; ++i) {
|
||||
|
||||
//
|
||||
// Initialize a vector with a group of base faces from which to
|
||||
// create and evaluate patches:
|
||||
//
|
||||
Index minFace = i * lesserGroupSize + std::min(i, numLargerGroups);
|
||||
Index maxFace = minFace + lesserGroupSize + (i < numLargerGroups);
|
||||
|
||||
std::vector<Far::Index> baseFaces(maxFace - minFace);
|
||||
for (int face = minFace; face < maxFace; ++face) {
|
||||
baseFaces[face - minFace] = face;
|
||||
}
|
||||
|
||||
//
|
||||
// Declare a PatchGroup and tessellate its base faces -- generating
|
||||
// vertices and faces in Obj format to standard output:
|
||||
//
|
||||
PatchGroup patchGroup(patchOptions,
|
||||
baseRefiner, basePtexIndices, basePositions, baseFaces);
|
||||
|
||||
if (args.noTessFlag) continue;
|
||||
|
||||
if (!args.noOutputFlag) {
|
||||
printf("g patchGroup_%d\n", i);
|
||||
}
|
||||
|
||||
for (int j = 0; j < (int) baseFaces.size(); ++j) {
|
||||
patchGroup.TessellateBaseFace(j, tessPoints, tessFaces);
|
||||
|
||||
if (!args.noOutputFlag) {
|
||||
int nVerts = (int) tessPoints.size();
|
||||
for (int k = 0; k < nVerts; ++k) {
|
||||
float const * p = tessPoints[k].p;
|
||||
printf("v %f %f %f\n", p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
int nTris = (int) tessFaces.size();
|
||||
int vBase = 1 + objVertCount;
|
||||
for (int k = 0; k < nTris; ++k) {
|
||||
int const * v = tessFaces[k].v;
|
||||
printf("f %d %d %d\n",
|
||||
vBase + v[0], vBase + v[1], vBase + v[2]);
|
||||
}
|
||||
objVertCount += nVerts;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete baseRefinerPtr;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
11
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_3/CMakeLists.txt
vendored
Normal file
11
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_3/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright 2020 DreamWorks Animation LLC.
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
osd_add_far_tutorial(
|
||||
far_tutorial_5_3
|
||||
far_tutorial_5_3.cpp
|
||||
$<TARGET_OBJECTS:regression_common_obj>
|
||||
)
|
||||
562
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_3/far_tutorial_5_3.cpp
vendored
Normal file
562
blender-5.2.0/extern/opensubdiv-source/tutorials/far/tutorial_5_3/far_tutorial_5_3.cpp
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
//
|
||||
// Copyright 2020 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tutorial description:
|
||||
//
|
||||
// This tutorial shows how to use a Far::LimitStenciTable to repeatedly
|
||||
// and efficiently evaluate a set of points (and optionally derivatives)
|
||||
// on the limit surface.
|
||||
//
|
||||
// A LimitStencilTable derives from StencilTable but is specialized to
|
||||
// factor the evaluation of limit positions and derivatives into stencils.
|
||||
// This allows a set of limit properties to be efficiently recomputed in
|
||||
// response to changes to the vertices of the base mesh. Constructing
|
||||
// the different kinds of StencilTables can have a high cost, so whether
|
||||
// that cost is worth it will depend on your usage (e.g. if points are
|
||||
// only computed once, using stencil tables is typically not worth the
|
||||
// added cost).
|
||||
//
|
||||
// Any points on the limit surface can be identified for evaluation. In
|
||||
// this example we create a crude tessellation similar to tutorial_5_2.
|
||||
// The midpoint of each face and points near the corners of the face are
|
||||
// evaluated and a triangle fan connects them.
|
||||
//
|
||||
|
||||
#include "../../../regression/common/arg_utils.h"
|
||||
#include "../../../regression/common/far_utils.h"
|
||||
|
||||
#include <opensubdiv/far/topologyDescriptor.h>
|
||||
#include <opensubdiv/far/patchTableFactory.h>
|
||||
#include <opensubdiv/far/stencilTableFactory.h>
|
||||
#include <opensubdiv/far/ptexIndices.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
using Far::Index;
|
||||
|
||||
|
||||
//
|
||||
// Global utilities in this namespace are not relevant to the tutorial.
|
||||
// They simply serve to construct some default geometry to be processed
|
||||
// in the form of a TopologyRefiner and vector of vertex positions.
|
||||
//
|
||||
namespace {
|
||||
//
|
||||
// Simple structs for (x,y,z) position and a 3-tuple for the set
|
||||
// of vertices of a triangle:
|
||||
//
|
||||
struct Pos {
|
||||
Pos() { }
|
||||
Pos(float x, float y, float z) { p[0] = x, p[1] = y, p[2] = z; }
|
||||
|
||||
Pos operator+(Pos const & op) const {
|
||||
return Pos(p[0] + op.p[0], p[1] + op.p[1], p[2] + op.p[2]);
|
||||
}
|
||||
|
||||
// Clear() and AddWithWeight() required for interpolation:
|
||||
void Clear( void * =0 ) { p[0] = p[1] = p[2] = 0.0f; }
|
||||
|
||||
void AddWithWeight(Pos const & src, float weight) {
|
||||
p[0] += weight * src.p[0];
|
||||
p[1] += weight * src.p[1];
|
||||
p[2] += weight * src.p[2];
|
||||
}
|
||||
|
||||
float p[3];
|
||||
};
|
||||
typedef std::vector<Pos> PosVector;
|
||||
|
||||
struct Tri {
|
||||
Tri() { }
|
||||
Tri(int a, int b, int c) { v[0] = a, v[1] = b, v[2] = c; }
|
||||
|
||||
int v[3];
|
||||
};
|
||||
typedef std::vector<Tri> TriVector;
|
||||
|
||||
|
||||
//
|
||||
// Functions to populate the topology and geometry arrays a simple
|
||||
// shape whose positions may be transformed:
|
||||
//
|
||||
void
|
||||
createCube(std::vector<int> & vertsPerFace,
|
||||
std::vector<Index> & faceVertsPerFace,
|
||||
std::vector<Pos> & positionsPerVert) {
|
||||
|
||||
// Local topology and position of a cube centered at origin:
|
||||
static float const cubePositions[8][3] = { { -0.5f, -0.5f, -0.5f },
|
||||
{ -0.5f, 0.5f, -0.5f },
|
||||
{ -0.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, -0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, -0.5f },
|
||||
{ 0.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, -0.5f, 0.5f } };
|
||||
|
||||
static int const cubeFaceVerts[6][4] = { { 0, 3, 2, 1 },
|
||||
{ 4, 5, 6, 7 },
|
||||
{ 0, 4, 7, 3 },
|
||||
{ 1, 2, 6, 5 },
|
||||
{ 0, 1, 5, 4 },
|
||||
{ 3, 7, 6, 2 } };
|
||||
|
||||
// Initialize verts-per-face and face-vertices for each face:
|
||||
vertsPerFace.resize(6);
|
||||
faceVertsPerFace.resize(24);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
vertsPerFace[i] = 4;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
faceVertsPerFace[i*4+j] = cubeFaceVerts[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize vertex positions:
|
||||
positionsPerVert.resize(8);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
float const * p = cubePositions[i];
|
||||
positionsPerVert[i] = Pos(p[0], p[1], p[2]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Create a TopologyRefiner from default geometry created above:
|
||||
//
|
||||
Far::TopologyRefiner *
|
||||
createTopologyRefinerDefault(PosVector & posVector) {
|
||||
|
||||
std::vector<int> topVertsPerFace;
|
||||
std::vector<Index> topFaceVerts;
|
||||
|
||||
createCube(topVertsPerFace, topFaceVerts, posVector);
|
||||
|
||||
typedef Far::TopologyDescriptor Descriptor;
|
||||
|
||||
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(
|
||||
Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
|
||||
|
||||
Descriptor desc;
|
||||
desc.numVertices = (int) posVector.size();
|
||||
desc.numFaces = (int) topVertsPerFace.size();
|
||||
desc.numVertsPerFace = &topVertsPerFace[0];
|
||||
desc.vertIndicesPerFace = &topFaceVerts[0];
|
||||
|
||||
// Instantiate a Far::TopologyRefiner from the descriptor.
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
|
||||
Far::TopologyRefinerFactory<Descriptor>::Options(type,options));
|
||||
assert(refiner);
|
||||
return refiner;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a TopologyRefiner from a specified Obj file:
|
||||
// geometry created internally:
|
||||
//
|
||||
Far::TopologyRefiner *
|
||||
createTopologyRefinerFromObj(std::string const & objFileName,
|
||||
Sdc::SchemeType schemeType,
|
||||
PosVector & posVector) {
|
||||
|
||||
const char * filename = objFileName.c_str();
|
||||
const Shape * shape = 0;
|
||||
|
||||
std::ifstream ifs(filename);
|
||||
if (ifs) {
|
||||
std::stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
std::string shapeString = ss.str();
|
||||
|
||||
shape = Shape::parseObj(shapeString.c_str(),
|
||||
ConvertSdcTypeToShapeScheme(schemeType), false);
|
||||
if (shape == 0) {
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create Shape from .obj file '%s'\n",
|
||||
filename);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error: Cannot open .obj file '%s'\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sdc::SchemeType sdcType = GetSdcType(*shape);
|
||||
Sdc::Options sdcOptions = GetSdcOptions(*shape);
|
||||
|
||||
Far::TopologyRefiner * refiner =
|
||||
Far::TopologyRefinerFactory<Shape>::Create(*shape,
|
||||
Far::TopologyRefinerFactory<Shape>::Options(
|
||||
sdcType, sdcOptions));
|
||||
if (refiner == 0) {
|
||||
fprintf(stderr, "Error: Unable to construct TopologyRefiner "
|
||||
"from .obj file '%s'\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numVertices = refiner->GetNumVerticesTotal();
|
||||
posVector.resize(numVertices);
|
||||
std::memcpy(&posVector[0].p[0], &shape->verts[0],
|
||||
numVertices * 3 * sizeof(float));
|
||||
|
||||
delete shape;
|
||||
return refiner;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Simple function to export an Obj file for the limit points -- which
|
||||
// provides a simple tessllation similar to tutorial_5_2.
|
||||
//
|
||||
int writeToObj(
|
||||
Far::TopologyLevel const & baseLevel,
|
||||
std::vector<Pos> const & vertexPositions,
|
||||
int nextObjVertexIndex) {
|
||||
|
||||
for (size_t i = 0; i < vertexPositions.size(); ++i) {
|
||||
float const * p = vertexPositions[i].p;
|
||||
printf("v %f %f %f\n", p[0], p[1], p[2]);
|
||||
}
|
||||
|
||||
//
|
||||
// Connect the sequences of limit points (center followed by corners)
|
||||
// into triangle fans for each base face:
|
||||
//
|
||||
for (int i = 0; i < baseLevel.GetNumFaces(); ++i) {
|
||||
int faceSize = baseLevel.GetFaceVertices(i).size();
|
||||
|
||||
int vCenter = nextObjVertexIndex + 1;
|
||||
int vCorner = vCenter + 1;
|
||||
for (int k = 0; k < faceSize; ++k) {
|
||||
printf("f %d %d %d\n",
|
||||
vCenter, vCorner + k, vCorner + ((k + 1) % faceSize));
|
||||
}
|
||||
nextObjVertexIndex += faceSize + 1;
|
||||
}
|
||||
return nextObjVertexIndex;
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
|
||||
//
|
||||
// Command line arguments parsed to provide run-time options:
|
||||
//
|
||||
class Args {
|
||||
public:
|
||||
std::string inputObjFile;
|
||||
Sdc::SchemeType schemeType;
|
||||
int maxPatchDepth;
|
||||
int numPoses;
|
||||
Pos poseOffset;
|
||||
bool deriv1Flag;
|
||||
bool noPatchesFlag;
|
||||
bool noOutputFlag;
|
||||
|
||||
public:
|
||||
Args(int argc, char ** argv) :
|
||||
inputObjFile(),
|
||||
schemeType(Sdc::SCHEME_CATMARK),
|
||||
maxPatchDepth(3),
|
||||
numPoses(0),
|
||||
poseOffset(1.0f, 0.0f, 0.0f),
|
||||
deriv1Flag(false),
|
||||
noPatchesFlag(false),
|
||||
noOutputFlag(false) {
|
||||
|
||||
// Parse and assign standard arguments and Obj files:
|
||||
ArgOptions args;
|
||||
args.Parse(argc, argv);
|
||||
|
||||
maxPatchDepth = args.GetLevel();
|
||||
schemeType = ConvertShapeSchemeToSdcType(args.GetDefaultScheme());
|
||||
|
||||
const std::vector<const char *> objFiles = args.GetObjFiles();
|
||||
if (!objFiles.empty()) {
|
||||
for (size_t i = 1; i < objFiles.size(); ++i) {
|
||||
fprintf(stderr,
|
||||
"Warning: .obj file '%s' ignored\n", objFiles[i]);
|
||||
}
|
||||
inputObjFile = std::string(objFiles[0]);
|
||||
}
|
||||
|
||||
// Parse remaining arguments specific to this example:
|
||||
const std::vector<const char *> &rargs = args.GetRemainingArgs();
|
||||
for (size_t i = 0; i < rargs.size(); ++i) {
|
||||
if (!strcmp(rargs[i], "-d1")) {
|
||||
deriv1Flag = true;
|
||||
} else if (!strcmp(rargs[i], "-nopatches")) {
|
||||
noPatchesFlag = true;
|
||||
} else if (!strcmp(rargs[i], "-poses")) {
|
||||
if (++i < rargs.size()) numPoses = atoi(rargs[i]);
|
||||
} else if (!strcmp(rargs[i], "-offset")) {
|
||||
if (++i < rargs.size()) poseOffset.p[0] = (float)atof(rargs[i]);
|
||||
if (++i < rargs.size()) poseOffset.p[1] = (float)atof(rargs[i]);
|
||||
if (++i < rargs.size()) poseOffset.p[2] = (float)atof(rargs[i]);
|
||||
} else if (!strcmp(rargs[i], "-nooutput")) {
|
||||
noOutputFlag = true;
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Argument '%s' ignored\n", rargs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Args() { }
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Assemble the set of locations for the limit points. The resulting
|
||||
// vector of LocationArrays can contain arbitrary locations on the limit
|
||||
// surface -- with multiple locations for the same patch grouped into a
|
||||
// single array.
|
||||
//
|
||||
// In this case, for each base face, coordinates for the center and its
|
||||
// corners are specified -- from which we will construct a triangle fan
|
||||
// providing a crude tessellation (similar to tutorial_5_2).
|
||||
//
|
||||
typedef Far::LimitStencilTableFactory::LocationArray LocationArray;
|
||||
|
||||
int assembleLimitPointLocations(Far::TopologyRefiner const & refiner,
|
||||
std::vector<LocationArray> & locations) {
|
||||
//
|
||||
// Coordinates for the center of the face and its corners (slightly
|
||||
// inset). Unlike most of the public interface for patches, the
|
||||
// LocationArray refers to parameteric coordinates as (s,t), so that
|
||||
// convention will be followed here.
|
||||
//
|
||||
// Note that the (s,t) coordinates in a LocationArray are referred to
|
||||
// by reference. The memory holding these (s,t) values must persist
|
||||
// while the LimitStencilTable is constructed -- the arrays here are
|
||||
// declared as static for that purpose.
|
||||
//
|
||||
static float const quadSCoords[5] = { 0.5f, 0.05f, 0.95f, 0.95f, 0.05f };
|
||||
static float const quadTCoords[5] = { 0.5f, 0.05f, 0.05f, 0.95f, 0.95f };
|
||||
|
||||
static float const triSCoords[4] = { 0.33f, 0.05f, 0.95f, 0.05f };
|
||||
static float const triTCoords[4] = { 0.33f, 0.05f, 0.00f, 0.95f };
|
||||
|
||||
static float const irregSCoords[2] = { 1.0f, 0.05f };
|
||||
static float const irregTCoords[2] = { 1.0f, 0.05f };
|
||||
|
||||
//
|
||||
// Since these are references to patches to be evaluated, we require
|
||||
// use of the Ptex indices to identify the top-most parameterized
|
||||
// patch, which is essential to dealing with non-quad faces (in the
|
||||
// case of Catmark).
|
||||
//
|
||||
Far::TopologyLevel const & baseLevel = refiner.GetLevel(0);
|
||||
|
||||
Far::PtexIndices basePtexIndices(refiner);
|
||||
|
||||
int regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(
|
||||
refiner.GetSchemeType());
|
||||
|
||||
|
||||
//
|
||||
// For each base face, simply refer to the (s,t) arrays for regular quad
|
||||
// and triangular patches with a single LocationArray. Otherwise, for
|
||||
// irregular faces, the corners of the face come from different patches
|
||||
// and so must be referenced in separate LocationArrays.
|
||||
//
|
||||
locations.clear();
|
||||
|
||||
int numLimitPoints = 0;
|
||||
for (int i = 0; i < baseLevel.GetNumFaces(); ++i) {
|
||||
int baseFaceSize = baseLevel.GetFaceVertices(i).size();
|
||||
int basePtexId = basePtexIndices.GetFaceId(i);
|
||||
|
||||
bool faceIsRegular = (baseFaceSize == regFaceSize);
|
||||
if (faceIsRegular) {
|
||||
// All coordinates are on the same top-level patch:
|
||||
LocationArray loc;
|
||||
loc.ptexIdx = basePtexId;
|
||||
loc.numLocations = baseFaceSize + 1;
|
||||
if (baseFaceSize == 4) {
|
||||
loc.s = quadSCoords;
|
||||
loc.t = quadTCoords;
|
||||
} else {
|
||||
loc.s = triSCoords;
|
||||
loc.t = triTCoords;
|
||||
}
|
||||
locations.push_back(loc);
|
||||
} else {
|
||||
// Center coordinate is on the first sub-patch while those on
|
||||
// near the corners are on each successive sub-patch:
|
||||
LocationArray loc;
|
||||
loc.numLocations = 1;
|
||||
for (int j = 0; j <= baseFaceSize; ++j) {
|
||||
bool isPerimeter = (j > 0);
|
||||
loc.ptexIdx = basePtexId + (isPerimeter ? (j-1) : 0);
|
||||
loc.s = &irregSCoords[isPerimeter];
|
||||
loc.t = &irregTCoords[isPerimeter];
|
||||
|
||||
locations.push_back(loc);
|
||||
}
|
||||
}
|
||||
numLimitPoints += baseFaceSize + 1;
|
||||
}
|
||||
return numLimitPoints;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load command line arguments and geometry, build the LimitStencilTable
|
||||
// for a set of points on the limit surface and compute those points for
|
||||
// several orientations of the mesh:
|
||||
//
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
|
||||
Args args(argc, argv);
|
||||
|
||||
//
|
||||
// Create or load the base geometry (command line arguments allow a
|
||||
// .obj file to be specified), providing a TopologyRefiner and a set
|
||||
// of base vertex positions to work with:
|
||||
//
|
||||
std::vector<Pos> basePositions;
|
||||
|
||||
Far::TopologyRefiner * refinerPtr = args.inputObjFile.empty() ?
|
||||
createTopologyRefinerDefault(basePositions) :
|
||||
createTopologyRefinerFromObj(args.inputObjFile, args.schemeType,
|
||||
basePositions);
|
||||
assert(refinerPtr);
|
||||
Far::TopologyRefiner & refiner = *refinerPtr;
|
||||
|
||||
Far::TopologyLevel const & baseLevel = refiner.GetLevel(0);
|
||||
|
||||
//
|
||||
// Use of LimitStencilTable requires either explicit or implicit use
|
||||
// of a PatchTable. A PatchTable is not required to construct a
|
||||
// LimitStencilTable -- one will be constructed internally for use
|
||||
// and discarded -- but explicit construction is recommended to control
|
||||
// the many legacy options for PatchTable, rather than relying on
|
||||
// internal defaults. Adaptive refinement is required in both cases
|
||||
// to indicate the accuracy of the patches.
|
||||
//
|
||||
// Note that if a TopologyRefiner and PatchTable are not used for
|
||||
// any other purpose than computing the limit points, that specifying
|
||||
// the subset of faces containing those limit points in the adaptive
|
||||
// refinement and PatchTable construction can avoid unnecessary
|
||||
// overhead.
|
||||
//
|
||||
Far::PatchTable * patchTablePtr = 0;
|
||||
|
||||
if (args.noPatchesFlag) {
|
||||
refiner.RefineAdaptive(
|
||||
Far::TopologyRefiner::AdaptiveOptions(args.maxPatchDepth));
|
||||
} else {
|
||||
Far::PatchTableFactory::Options patchOptions(args.maxPatchDepth);
|
||||
patchOptions.useInfSharpPatch = true;
|
||||
patchOptions.generateLegacySharpCornerPatches = false;
|
||||
patchOptions.generateVaryingTables = false;
|
||||
patchOptions.generateFVarTables = false;
|
||||
patchOptions.endCapType =
|
||||
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
|
||||
|
||||
refiner.RefineAdaptive(patchOptions.GetRefineAdaptiveOptions());
|
||||
|
||||
patchTablePtr = Far::PatchTableFactory::Create(refiner, patchOptions);
|
||||
assert(patchTablePtr);
|
||||
}
|
||||
|
||||
//
|
||||
// Assemble the set of locations for the limit points. For each base
|
||||
// face, coordinates for the center and its corners are specified --
|
||||
// from which we will construct a triangle fan providing a crude
|
||||
// tessellation (similar to tutorial_5_2).
|
||||
//
|
||||
std::vector<LocationArray> locations;
|
||||
|
||||
int numLimitPoints = assembleLimitPointLocations(refiner, locations);
|
||||
|
||||
//
|
||||
// Construct a LimitStencilTable from the refiner, patch table (optional)
|
||||
// and the collection of limit point locations. Stencils can optionally
|
||||
// be created for computing dervatives -- the default is to compute 1st
|
||||
// derivative stencils, so be sure to disable that if not necessary:
|
||||
//
|
||||
Far::LimitStencilTableFactory::Options limitOptions;
|
||||
limitOptions.generate1stDerivatives = args.deriv1Flag;
|
||||
|
||||
Far::LimitStencilTable const * limitStencilTablePtr =
|
||||
Far::LimitStencilTableFactory::Create(refiner, locations,
|
||||
0, // optional StencilTable for the refined points
|
||||
patchTablePtr, // optional PatchTable
|
||||
limitOptions);
|
||||
assert(limitStencilTablePtr);
|
||||
Far::LimitStencilTable const & limitStencilTable = *limitStencilTablePtr;
|
||||
|
||||
//
|
||||
// Apply the constructed LimitStencilTable to compute limit positions
|
||||
// from the base level vertex positions. This is trivial if computing
|
||||
// all positions in one invokation. The UpdateValues method (and those
|
||||
// for derivatives) are overloaded to optionally accept a subrange of
|
||||
// indices to distribute the computation:
|
||||
//
|
||||
std::vector<Pos> limitPositions(numLimitPoints);
|
||||
|
||||
limitStencilTable.UpdateValues(basePositions, limitPositions);
|
||||
|
||||
// Call with the optional subrange:
|
||||
limitStencilTable.UpdateValues(basePositions, limitPositions,
|
||||
0, numLimitPoints / 2);
|
||||
limitStencilTable.UpdateValues(basePositions, limitPositions,
|
||||
(numLimitPoints / 2) + 1, numLimitPoints);
|
||||
|
||||
// Write vertices and faces in Obj format for the original limit points:
|
||||
int objVertCount = 0;
|
||||
|
||||
if (!args.noOutputFlag) {
|
||||
printf("g base_mesh\n");
|
||||
objVertCount = writeToObj(baseLevel, limitPositions, objVertCount);
|
||||
}
|
||||
|
||||
//
|
||||
// Recompute the limit points and output faces for different "poses" of
|
||||
// the original mesh -- in this case simply translated. Also optionally
|
||||
// compute 1st derivatives (though they are not used here):
|
||||
//
|
||||
std::vector<Pos> posePositions(basePositions);
|
||||
|
||||
std::vector<Pos> limitDu(args.deriv1Flag ? numLimitPoints : 0);
|
||||
std::vector<Pos> limitDv(args.deriv1Flag ? numLimitPoints : 0);
|
||||
|
||||
for (int i = 0; i < args.numPoses; ++i) {
|
||||
// Trivially transform the base vertex positions and re-compute:
|
||||
for (size_t j = 0; j < basePositions.size(); ++j) {
|
||||
posePositions[j] = posePositions[j] + args.poseOffset;
|
||||
}
|
||||
|
||||
limitStencilTable.UpdateValues(posePositions, limitPositions);
|
||||
if (args.deriv1Flag) {
|
||||
limitStencilTable.UpdateDerivs(posePositions, limitDu, limitDv);
|
||||
}
|
||||
|
||||
if (!args.noOutputFlag) {
|
||||
printf("\ng pose_%d\n", i);
|
||||
objVertCount = writeToObj(baseLevel, limitPositions, objVertCount);
|
||||
}
|
||||
}
|
||||
delete refinerPtr;
|
||||
delete patchTablePtr;
|
||||
delete limitStencilTablePtr;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user