mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-24 04:20:21 +00:00
Added evaluator, first .obj file reading and subdividing.
This commit is contained in:
parent
7dbf3d4198
commit
ecd726742f
@ -68,11 +68,12 @@
|
||||
#include <osd/mesh.h>
|
||||
#include <osd/vertex.h>
|
||||
|
||||
#include <osdutil/mesh.h>
|
||||
#include <osdutil/refiner.h>
|
||||
#include <osdutil/uniformEvaluator.h>
|
||||
#include <osdutil/topology.h>
|
||||
|
||||
#include "../common/stopwatch.h"
|
||||
#include "../../regression/common/shape_utils.h"
|
||||
|
||||
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
@ -86,70 +87,86 @@
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
typedef HbrMesh<OsdVertex> OsdHbrMesh;
|
||||
typedef HbrVertex<OsdVertex> OsdHbrVertex;
|
||||
typedef HbrFace<OsdVertex> OsdHbrFace;
|
||||
typedef HbrHalfedge<OsdVertex> OsdHbrHalfedge;
|
||||
static shape * readShape( char const * fname ) {
|
||||
|
||||
typedef FarMesh<OsdVertex> OsdFarMesh;
|
||||
typedef FarMeshFactory<OsdVertex> OsdFarMeshFactory;
|
||||
typedef FarSubdivisionTables<OsdVertex> OsdFarMeshSubdivision;
|
||||
FILE * handle = fopen( fname, "rt" );
|
||||
if (not handle) {
|
||||
printf("Could not open \"%s\" - aborting.\n", fname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fseek( handle, 0, SEEK_END );
|
||||
size_t size = ftell(handle);
|
||||
fseek( handle, 0, SEEK_SET );
|
||||
|
||||
char * shapeStr = new char[size+1];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void
|
||||
createOsdMesh(int level)
|
||||
if ( fread( shapeStr, size, 1, handle)!=1 ) {
|
||||
printf("Error reading \"%s\" - aborting.\n", fname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fclose(handle);
|
||||
|
||||
shapeStr[size]='\0';
|
||||
|
||||
return shape::parseShape( shapeStr, 1 );
|
||||
}
|
||||
|
||||
static bool
|
||||
shapeToTopology( const shape *input, PxOsdUtilSubdivTopology *output,
|
||||
std::string *errorMessage)
|
||||
{
|
||||
float points[] = { 0.000000f, -1.414214f, 1.000000f,
|
||||
1.414214f, 0.000000f, 1.000000f,
|
||||
-1.414214f, 0.000000f, 1.000000f,
|
||||
0.000000f, 1.414214f, 1.000000f,
|
||||
-1.414214f, 0.000000f, -1.000000f,
|
||||
0.000000f, 1.414214f, -1.000000f,
|
||||
0.000000f, -1.414214f, -1.000000f,
|
||||
1.414214f, 0.000000f, -1.000000f };
|
||||
|
||||
int nverts[] = { 4, 4, 4, 4, 4, 4};
|
||||
|
||||
int indices[] = { 0, 1, 3, 2,
|
||||
2, 3, 5, 4,
|
||||
4, 5, 7, 6,
|
||||
6, 7, 1, 0,
|
||||
1, 7, 5, 3,
|
||||
6, 0, 2, 4};
|
||||
int numVertices = input->getNverts();
|
||||
|
||||
output->numVertices = numVertices;
|
||||
output->maxLevels = 3; //arbitrary initial value
|
||||
output->nverts = input->nvertsPerFace;
|
||||
output->indices = input->faceverts;
|
||||
|
||||
// Scheme scheme = kCatmark;
|
||||
// XXX:gelder
|
||||
// Need to pull over uvs and tags for better test coverage
|
||||
|
||||
PxOsdUtilSubdivTopology t;
|
||||
t.name = "TestSubdiv";
|
||||
for (int i=0; i< (int)(sizeof(nverts)/sizeof(int)); ++i) {
|
||||
t.nverts.push_back(nverts[i]);
|
||||
}
|
||||
for (int i=0; i< (int)(sizeof(indices)/sizeof(int)); ++i) {
|
||||
t.indices.push_back(indices[i]);
|
||||
}
|
||||
t.numVertices = (int)sizeof(points)/(3*sizeof(float));
|
||||
t.maxLevels = 8;
|
||||
return output->IsValid(errorMessage);
|
||||
}
|
||||
|
||||
std::string errorMessage;
|
||||
PxOsdUtilRefiner refiner;
|
||||
|
||||
// Create refiner, passing "false" to adaptive so we'll get
|
||||
// uniform refinement
|
||||
if (not refiner.Initialize(t, false, &errorMessage)) {
|
||||
std::cout << "Refiner creation failed with " << errorMessage << std::endl;
|
||||
return;
|
||||
//------------------------------------------------------------------------------
|
||||
static bool
|
||||
createOsdMesh(char *inputFile, char *outputFile, std::string *errorMessage)
|
||||
{
|
||||
|
||||
shape *inputShape = readShape(inputFile);
|
||||
|
||||
PxOsdUtilSubdivTopology topology;
|
||||
if (not shapeToTopology(inputShape, &topology, errorMessage))
|
||||
return false;
|
||||
|
||||
PxOsdUtilUniformEvaluator uniformEvaluator;
|
||||
|
||||
// Create uniformEvaluator
|
||||
if (not uniformEvaluator.Initialize(topology, errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push the vertex data
|
||||
uniformEvaluator.SetCoarsePositions(inputShape->verts, errorMessage);
|
||||
|
||||
// Refine with eight threads
|
||||
if (not uniformEvaluator.Refine(8, errorMessage))
|
||||
return false;
|
||||
|
||||
std::vector<int> refinedQuads;
|
||||
if (not refiner.GetRefinedQuads(&refinedQuads, &errorMessage)) {
|
||||
if (not uniformEvaluator.GetRefinedQuads(&refinedQuads, errorMessage)) {
|
||||
std::cout << "GetRefinedQuads failed with " << errorMessage << std::endl;
|
||||
}
|
||||
|
||||
|
||||
float *refinedPositions = NULL;
|
||||
int numFloats = 0;
|
||||
if (not uniformEvaluator.GetRefinedPositions(&refinedPositions, &numFloats, errorMessage)) {
|
||||
std::cout << "GetRefinedPositions failed with " << errorMessage << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Quads = " << refinedQuads.size()/4 << std::endl;
|
||||
for (int i=0; i<(int)refinedQuads.size(); i+=4) {
|
||||
std::cout << "(" << refinedQuads[i] <<
|
||||
@ -159,42 +176,22 @@ createOsdMesh(int level)
|
||||
")\n";
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// Push the vertex data:
|
||||
std::vector<float> pointsVec;
|
||||
pointsVec.resize(sizeof(points));
|
||||
for (int i=0; i<(int)sizeof(points); ++i) {
|
||||
pointsVec[i] = points[i];
|
||||
std::cout << "Hot damn, it worked.\n";
|
||||
std::cout << "Positions = " << numFloats/3 << std::endl;
|
||||
for (int i=0; i<numFloats; i+=3) {
|
||||
std::cout << "(" << refinedPositions[i] <<
|
||||
", " << refinedPositions[i+1] <<
|
||||
"," << refinedPositions[i+2] << ")\n";
|
||||
}
|
||||
|
||||
|
||||
shape->SetCoarsePositions(pointsVec);
|
||||
|
||||
std::vector<float> refinedPositions;
|
||||
// if (not uniformEvaluator.WriteRefinedObj("foo.obj", errorMessage)) {
|
||||
// std::cout << errorMessage << std::endl;
|
||||
// }
|
||||
|
||||
|
||||
if (not (shape->Refine(2) and
|
||||
shape->GetPositions(&refinedPositions, &errorMessage) and
|
||||
shape->GetQuads(&refinedQuads, &errorMessage))) {
|
||||
std::cout << errorMessage << std::endl;
|
||||
} else {
|
||||
std::cout << "Hot damn, it worked.\n";
|
||||
std::cout << "Positions = " << refinedPositions.size()/3 << std::endl;
|
||||
for (int i=0; i<(int)refinedPositions.size(); i+=3) {
|
||||
std::cout << "(" << refinedPositions[i] <<
|
||||
", " << refinedPositions[i+1] <<
|
||||
"," << refinedPositions[i+2] << ")\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (not shape->WriteRefinedObj("foo.obj", &errorMessage)) {
|
||||
std::cout << errorMessage << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -207,11 +204,23 @@ callbackError(OpenSubdiv::OsdErrorType err, const char *message)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int main(int, char**) {
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
|
||||
if (argc < 3) {
|
||||
std::cout << "Usage: projectTest input.obj output\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "input is " << argv[1] << " and output is " << argv[2] <<std::endl;
|
||||
|
||||
|
||||
OsdSetErrorCallback(callbackError);
|
||||
|
||||
createOsdMesh(1);
|
||||
std::string errorMessage;
|
||||
|
||||
if (not createOsdMesh(argv[1], argv[2], &errorMessage)) {
|
||||
std::cout << "Failed with error: " << errorMessage << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,8 @@ set(PUBLIC_HEADER_FILES
|
||||
drawController.h
|
||||
mesh.h
|
||||
refiner.h
|
||||
topology.h
|
||||
topology.h
|
||||
uniformEvaluator.h
|
||||
)
|
||||
|
||||
add_library(osdutil
|
||||
@ -45,7 +46,9 @@ add_library(osdutil
|
||||
refiner.h
|
||||
refiner.cpp
|
||||
topology.h
|
||||
topology.cpp
|
||||
topology.cpp
|
||||
uniformEvaluator.h
|
||||
uniformEvaluator.cpp
|
||||
${INC_FILES}
|
||||
)
|
||||
|
||||
|
@ -107,7 +107,7 @@ PxOsdUtilRefiner::Initialize(
|
||||
// create the quad tables to include all levels by specifying
|
||||
// firstLevel as 1
|
||||
FarMeshFactory<OsdVertex> uniformMeshFactory(
|
||||
_mesh->GetHbrMesh(), t.maxLevels, false, /*firstLevel=*/1);
|
||||
_mesh->GetHbrMesh(), t.maxLevels, false);
|
||||
|
||||
_farMesh = uniformMeshFactory.Create();
|
||||
|
||||
|
@ -1,3 +1,26 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "topology.h"
|
||||
|
||||
#include <sstream>
|
||||
|
@ -1,3 +1,26 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef PX_OSD_UTIL_TOPOLOGY_H
|
||||
#define PX_OSD_UTIL_TOPOLOGY_H
|
||||
|
||||
|
319
opensubdiv/osdutil/uniformEvaluator.cpp
Normal file
319
opensubdiv/osdutil/uniformEvaluator.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "uniformEvaluator.h"
|
||||
|
||||
#define HBR_ADAPTIVE
|
||||
#include "../hbr/mesh.h"
|
||||
|
||||
#include "../osd/vertex.h"
|
||||
|
||||
#include <omp.h>
|
||||
|
||||
#include "../osd/ompComputeController.h"
|
||||
#include "../osd/cpuComputeController.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
PxOsdUtilUniformEvaluator::PxOsdUtilUniformEvaluator():
|
||||
_refiner(NULL),
|
||||
_ownsRefiner(false),
|
||||
_computeContext(NULL),
|
||||
_vertexBuffer(NULL),
|
||||
_vvBuffer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
PxOsdUtilUniformEvaluator::~PxOsdUtilUniformEvaluator()
|
||||
{
|
||||
if (_ownsRefiner and _refiner) {
|
||||
delete _refiner;
|
||||
}
|
||||
if (_computeContext)
|
||||
delete _computeContext;
|
||||
if (_vertexBuffer)
|
||||
delete _vertexBuffer;
|
||||
if (_vvBuffer)
|
||||
delete _vvBuffer;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PxOsdUtilUniformEvaluator::Initialize(
|
||||
const PxOsdUtilSubdivTopology &t,
|
||||
string *errorMessage)
|
||||
{
|
||||
|
||||
std::cout << "Initializing evaluator with topology\n";
|
||||
|
||||
// create and initialize a refiner, passing "false" for adaptive
|
||||
// to indicate we wish for uniform refinement
|
||||
PxOsdUtilRefiner *refiner = new PxOsdUtilRefiner();
|
||||
_ownsRefiner = true;
|
||||
|
||||
std::cout << "Created refiner\n";
|
||||
|
||||
if (not refiner->Initialize(t, false, errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Initialized refiner\n";
|
||||
|
||||
return Initialize(refiner, errorMessage);
|
||||
}
|
||||
|
||||
bool
|
||||
PxOsdUtilUniformEvaluator::Initialize(
|
||||
PxOsdUtilRefiner *refiner,
|
||||
string *errorMessage)
|
||||
{
|
||||
|
||||
std::cout << "Initializing evaluator with refiner\n";
|
||||
|
||||
if (refiner->GetAdaptive()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = "Uniform evaluator requires uniform refiner";
|
||||
std::cout << *errorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note we assume someone else keeps this pointer alive
|
||||
_refiner = refiner;
|
||||
_ownsRefiner = false;
|
||||
|
||||
const FarMesh<OsdVertex> *fmesh = _refiner->GetFarMesh();
|
||||
const HbrMesh<OsdVertex> *hmesh = _refiner->GetHbrMesh();
|
||||
const vector<string> &vvNames = _refiner->GetTopology().vvNames;
|
||||
|
||||
if (not (fmesh and hmesh)) {
|
||||
if (errorMessage)
|
||||
*errorMessage = "No valid uniform far/hbr mesh";
|
||||
std::cout << *errorMessage << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// No need to create a far mesh if no subdivision is required.
|
||||
if (_refiner->GetTopology().maxLevels == 0) {
|
||||
|
||||
// Three elements per unrefined point
|
||||
_vertexBuffer = OsdCpuVertexBuffer::Create(
|
||||
3, hmesh->GetNumVertices());
|
||||
|
||||
// zeros
|
||||
memset( _vertexBuffer->BindCpuBuffer(), 0,
|
||||
3 * hmesh->GetNumVertices() * sizeof(float));
|
||||
|
||||
if (vvNames.size()) {
|
||||
|
||||
// One element in the vertex buffer for each
|
||||
// named vertex varying attribute in the unrefined mesh
|
||||
_vvBuffer = OsdCpuVertexBuffer::Create(
|
||||
vvNames.size(), hmesh->GetNumVertices());
|
||||
|
||||
// zeros
|
||||
memset( _vvBuffer->BindCpuBuffer(), 0,
|
||||
vvNames.size() * hmesh->GetNumVertices() * sizeof(float));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_computeContext = OsdCpuComputeContext::Create(fmesh);
|
||||
|
||||
// Three elements per refined point
|
||||
_vertexBuffer = OsdCpuVertexBuffer::Create(
|
||||
3, fmesh->GetNumVertices());
|
||||
|
||||
// zeros
|
||||
memset( _vertexBuffer->BindCpuBuffer(), 0,
|
||||
3 * fmesh->GetNumVertices() * sizeof(float));
|
||||
|
||||
|
||||
if (vvNames.size()) {
|
||||
|
||||
// One element in the vertex buffer for each
|
||||
// named vertex varying attribute in the refined mesh
|
||||
_vvBuffer = OsdCpuVertexBuffer::Create(
|
||||
vvNames.size(), fmesh->GetNumVertices());
|
||||
|
||||
// zeros
|
||||
memset( _vvBuffer->BindCpuBuffer(), 0,
|
||||
vvNames.size() * fmesh->GetNumVertices() * sizeof(float));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PxOsdUtilUniformEvaluator::SetCoarsePositions(
|
||||
const vector<float>& coords, string *errorMessage )
|
||||
{
|
||||
const float* pFloats = &coords.front();
|
||||
int numFloats = (int) coords.size();
|
||||
|
||||
//XXX: should be >= num coarse vertices
|
||||
if (numFloats/3 >= _refiner->GetFarMesh()->GetNumVertices()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = "Indexing error in tesselator";
|
||||
std::cout << *errorMessage << "\n";
|
||||
} else {
|
||||
_vertexBuffer->UpdateData(pFloats, 0, numFloats / 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PxOsdUtilUniformEvaluator::SetCoarseVVData(
|
||||
const vector<float>& data, string *errorMessage
|
||||
)
|
||||
{
|
||||
if (!_vvBuffer) {
|
||||
if (!data.empty() and errorMessage)
|
||||
*errorMessage =
|
||||
"Mesh was not constructed with VV variables.";
|
||||
return;
|
||||
}
|
||||
|
||||
int numElements = _vvBuffer->GetNumElements();
|
||||
int numVertices = (int) data.size() / numElements;
|
||||
const float* pFloats = &data.front();
|
||||
_vvBuffer->UpdateData(pFloats, 0, numVertices);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PxOsdUtilUniformEvaluator::Refine(
|
||||
int numThreads, string *errorMessage)
|
||||
{
|
||||
const FarMesh<OsdVertex> *fmesh = _refiner->GetFarMesh();
|
||||
|
||||
if (numThreads > 1) {
|
||||
OsdOmpComputeController ompComputeController(numThreads);
|
||||
ompComputeController.Refine(_computeContext,
|
||||
fmesh->GetKernelBatches(),
|
||||
_vertexBuffer, _vvBuffer);
|
||||
} else {
|
||||
OsdCpuComputeController cpuComputeController;
|
||||
cpuComputeController.Refine(_computeContext,
|
||||
fmesh->GetKernelBatches(),
|
||||
_vertexBuffer, _vvBuffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PxOsdUtilUniformEvaluator::GetRefinedPositions(
|
||||
float **positions, int *numFloats,
|
||||
string *errorMessage) const
|
||||
{
|
||||
|
||||
if (not (positions and numFloats)) {
|
||||
if (errorMessage) {
|
||||
*errorMessage =
|
||||
"GetRefinedPositions: positions and/or numFloats was NULL";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_refiner->IsRefined()) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = "GetRefinedPositions: Mesh has not been refined.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int numRefinedVerts = _refiner->GetNumRefinedVertices();
|
||||
int firstVertexOffset = _refiner->GetFirstVertexOffset();
|
||||
|
||||
if (numRefinedVerts == 0) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = "GetRefinedPositions: not refined.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// The vertexBuffer has all subdivision levels, here we are skipping
|
||||
// past the vertices on lower subdivision levels and returning
|
||||
// a pointer to the start of the most refined level
|
||||
*positions = _vertexBuffer->BindCpuBuffer() + (3*firstVertexOffset);
|
||||
*numFloats = numRefinedVerts*3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PxOsdUtilUniformEvaluator::GetRefinedVVData(
|
||||
float **data, int *numFloats, int *numElementsRetVal,
|
||||
std::string *errorMessage ) const
|
||||
{
|
||||
|
||||
|
||||
if (not (data and numFloats)) {
|
||||
if (errorMessage) {
|
||||
*errorMessage =
|
||||
"GetRefinedVVData: data and/or numFloats was NULL";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_refiner->IsRefined()) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = "GetRefinedVVData: Mesh has not been refined.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int numRefinedVerts = _refiner->GetNumRefinedVertices();
|
||||
int firstVertexOffset = _refiner->GetFirstVertexOffset();
|
||||
|
||||
if (numRefinedVerts == 0) {
|
||||
if (errorMessage) {
|
||||
*errorMessage = "GetRefinedVVData: not refined.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int numElements = GetTopology().vvNames.size();
|
||||
if (numElementsRetVal)
|
||||
*numElementsRetVal = numElements;
|
||||
|
||||
// The vertexBuffer has all subdivision levels, here we are skipping
|
||||
// past the vertices on lower subdivision levels and returning
|
||||
// a pointer to the start of the most refined level
|
||||
*data =
|
||||
_vvBuffer->BindCpuBuffer() + (numElements * firstVertexOffset);
|
||||
*numFloats = numElements * numRefinedVerts;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
184
opensubdiv/osdutil/uniformEvaluator.h
Normal file
184
opensubdiv/osdutil/uniformEvaluator.h
Normal file
@ -0,0 +1,184 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef PXOSDUTIL_UNIFORM_EVALUATOR_H
|
||||
#define PXOSDUTIL_UNIFORM_EVALUATOR_H
|
||||
|
||||
#include "refiner.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define HBR_ADAPTIVE
|
||||
|
||||
#include "../osd/cpuVertexBuffer.h"
|
||||
#include "../osd/cpuComputeContext.h"
|
||||
#include "../far/mesh.h"
|
||||
|
||||
// This class takes a mesh that has undergone uniform refinement to
|
||||
// a fixed subdivision level, and creates required run time OpenSubdiv
|
||||
// data structures used to sample values on subdivision surfaces.
|
||||
//
|
||||
// An important note here is that refined positions and vertex varying
|
||||
// attributes are sampled at the n-th subdivision level, not at the
|
||||
// exact limit surface. Use PxOsdUtilAdaptiveEvaluator for true limits.
|
||||
//
|
||||
class PxOsdUtilUniformEvaluator {
|
||||
public:
|
||||
PxOsdUtilUniformEvaluator();
|
||||
|
||||
~PxOsdUtilUniformEvaluator();
|
||||
|
||||
// Initialize returns false on error. If errorMessage is non-NULL it'll
|
||||
// be populated upon error.
|
||||
//
|
||||
// If successful vertex buffers and compute contexts will have been
|
||||
// created and are ready to SetCoarse* methods, call Refine, and then
|
||||
// sample refined values with the Get* methods
|
||||
//
|
||||
// Note that calling this method assumes that the evaluator isn't
|
||||
// responsible for the refiner's lifetime, someone else needs to
|
||||
// hold onto the refiner pointer. This allows for lightweight sharing
|
||||
// of refiners among evaluators.
|
||||
//
|
||||
bool Initialize(
|
||||
PxOsdUtilRefiner* refiner,
|
||||
std::string *errorMessage = NULL);
|
||||
|
||||
bool Initialize(
|
||||
const PxOsdUtilSubdivTopology &topology,
|
||||
std::string *errorMessage = NULL);
|
||||
|
||||
// Set new coarse-mesh CV positions, need to call Refine
|
||||
// before calling Get* methods
|
||||
void SetCoarsePositions(
|
||||
const std::vector<float>& coords,
|
||||
std::string *errorMessage = NULL
|
||||
);
|
||||
|
||||
// Set new coarse-mesh vertex varying values, need to call Refine
|
||||
// before calling Get* methods
|
||||
void SetCoarseVVData(
|
||||
const std::vector<float>& data,
|
||||
std::string *errorMessage = NULL
|
||||
);
|
||||
|
||||
// Refine the coarse mesh, needed before calling GetPositions, GetQuads etc.
|
||||
// If numThreads is 1, use single cpu. If numThreads > 1 use Omp and set
|
||||
// number of omp threads.
|
||||
//
|
||||
bool Refine(int numThreads,
|
||||
std::string *errorMessage = NULL);
|
||||
|
||||
// Grab position results of calling Refine, return by reference a pointer
|
||||
// into _vertexBuffer memory with the refined points positions,
|
||||
// packed as 3 floats per point. This doesn't involve a copy, the
|
||||
// pointer will be valid as long as _vertexBuffer exists.
|
||||
//
|
||||
bool GetRefinedPositions(float **positions, int *numFloats,
|
||||
std::string *errorMessage = NULL) const;
|
||||
|
||||
// Grab vertex varying results of calling Refine, return by reference
|
||||
// a pointer into _vvBuffer memory with the refined data,
|
||||
// packed as (numElements) floats per point. This doesn't involve
|
||||
// a copy, the pointer will be valid as long as _vertexBuffer exists.
|
||||
//
|
||||
bool GetRefinedVVData(float **data, int *numFloats,
|
||||
int *numElements = NULL,
|
||||
std::string *errorMessage = NULL) const;
|
||||
|
||||
// Fetch the face varying attribute values on refined quads, call
|
||||
// through to the refiner but keep in evaluator API for
|
||||
// one-stop-service for user API
|
||||
void GetRefinedFVData(int subdivisionLevel,
|
||||
const std::vector<std::string>& names,
|
||||
std::vector<float>* fvdata) {
|
||||
_refiner->GetRefinedFVData(subdivisionLevel, names, fvdata);
|
||||
}
|
||||
|
||||
|
||||
// Fetch the topology of the post-refined mesh. The "quads" vector
|
||||
// will be filled with 4 ints per quad which index into a vector
|
||||
// of positions.
|
||||
//
|
||||
// Calls through to the refiner.
|
||||
//
|
||||
bool GetRefinedQuads(std::vector<int>* quads,
|
||||
std::string *errorMessage = NULL) const {
|
||||
return _refiner->GetRefinedQuads(quads, errorMessage);
|
||||
}
|
||||
|
||||
// Fetch the U/V coordinates of the refined quads in the U/V space
|
||||
// of their parent coarse face
|
||||
bool GetRefinedPtexUvs(std::vector<float>* subfaceUvs,
|
||||
std::vector<int>* ptexIndices,
|
||||
std::string *errorMessage = NULL) const {
|
||||
return _refiner->GetRefinedPtexUvs(subfaceUvs, ptexIndices, errorMessage);
|
||||
}
|
||||
|
||||
|
||||
// Write the refined quad mesh to given filename, return false on error
|
||||
// bool WriteRefinedObj( const std::string &filename,
|
||||
// std::string *errorMessage = NULL) const;
|
||||
|
||||
// Forward these calls through to the refiner, which may forward
|
||||
// to the mesh. Make these top level API calls on the evaluator
|
||||
// so clients can talk to a single API
|
||||
//
|
||||
const std::string &GetName() const { return _refiner->GetName();}
|
||||
|
||||
const OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex> *GetHbrMesh() {
|
||||
return _refiner->GetHbrMesh();
|
||||
}
|
||||
|
||||
const PxOsdUtilSubdivTopology &GetTopology() const {
|
||||
return _refiner->GetTopology();
|
||||
}
|
||||
|
||||
const OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex>* GetFarMesh() {
|
||||
return _refiner->GetFarMesh();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// A pointer to the shared refiner used. Note that this class may
|
||||
// own the refiner pointer (if _ownsRefiner is true), or it may
|
||||
// assume that someone else is responsible for managing that pointer
|
||||
// if _ownsRefiner is false.
|
||||
PxOsdUtilRefiner *_refiner;
|
||||
bool _ownsRefiner;
|
||||
|
||||
// responsible for performing uniform catmull/clark subdivision
|
||||
// on the incoming polygonal topology. This only stores topology and
|
||||
// face varying data and can be shared among threads. Doesn't store
|
||||
// per-vertex information being refined in different threads, those
|
||||
// are in vertex buffers that can't be shared.
|
||||
OpenSubdiv::OsdCpuComputeContext *_computeContext;
|
||||
OpenSubdiv::OsdCpuVertexBuffer *_vertexBuffer;
|
||||
OpenSubdiv::OsdCpuVertexBuffer *_vvBuffer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* PXOSDUTIL_UNIFORM_EVALUATOR_H */
|
Loading…
Reference in New Issue
Block a user