// // Copyright 2015 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 #include #include #include #include "sceneBase.h" using namespace OpenSubdiv; SceneBase::SceneBase(Options const &options) : _options(options), _indexBuffer(0), _patchParamTexture(0) { } SceneBase::~SceneBase() { if (_indexBuffer) glDeleteBuffers(1, &_indexBuffer); if (_patchParamTexture) glDeleteTextures(1, &_patchParamTexture); for (int i = 0; i < (int)_patchTables.size(); ++i) { delete _patchTables[i]; } } void SceneBase::AddTopology(Shape const *shape, int level, bool varying) { Far::PatchTables const * patchTable = NULL; int numVerts = createStencilTable(shape, level, varying, &patchTable); // centering rest position float pmin[3] = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; float pmax[3] = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; int nverts = shape->GetNumVertices(); for (int i = 0; i < nverts; ++i) { for (int j = 0; j < 3; ++j) { float v = shape->verts[i*3+j]; pmin[j] = std::min(v, pmin[j]); pmax[j] = std::max(v, pmax[j]); } } float center[3] = { (pmax[0]+pmin[0])*0.5f, (pmax[1]+pmin[1])*0.5f, pmin[2] }; float radius = sqrt((pmax[0]-pmin[0])*(pmax[0]-pmin[0]) + (pmax[1]-pmin[1])*(pmax[1]-pmin[1]) + (pmax[2]-pmin[2])*(pmax[2]-pmin[2])); std::vector restPosition(shape->verts); for (size_t i=0; i < restPosition.size()/3; ++i) { for (int j = 0; j < 3; ++j) { restPosition[i*3+j] = (shape->verts[i*3+j] - center[j])/radius; } } // store topology Topology topology; topology.numVerts = numVerts; topology.restPosition = restPosition; _topologies.push_back(topology); // store patch. // PatchTables is used later to be spliced into the index buffer. _patchTables.push_back(patchTable); } int SceneBase::createStencilTable(Shape const *shape, int level, bool varying, OpenSubdiv::Far::PatchTables const **patchTablesOut) { Far::TopologyRefiner * refiner = 0; { Sdc::SchemeType type = GetSdcType(*shape); Sdc::Options options = GetSdcOptions(*shape); refiner = Far::TopologyRefinerFactory::Create( *shape, Far::TopologyRefinerFactory::Options(type, options)); assert(refiner); } // Adaptive refinement currently supported only for catmull-clark scheme if (_options.adaptive) { Far::TopologyRefiner::AdaptiveOptions options(level); refiner->RefineAdaptive(options); } else { Far::TopologyRefiner::UniformOptions options(level); options.fullTopologyInLastLevel = true; refiner->RefineUniform(options); } Far::StencilTables const * vertexStencils=0, * varyingStencils=0; { Far::StencilTablesFactory::Options options; options.generateOffsets = true; options.generateIntermediateLevels = _options.adaptive; vertexStencils = Far::StencilTablesFactory::Create(*refiner, options); if (varying) { varyingStencils = Far::StencilTablesFactory::Create(*refiner, options); } assert(vertexStencils); } Far::PatchTables const * patchTables = NULL; { Far::PatchTablesFactory::Options poptions(level); if (_options.endCap == kEndCapBSplineBasis) { poptions.SetEndCapType( Far::PatchTablesFactory::Options::ENDCAP_BSPLINE_BASIS); } else { poptions.SetEndCapType( Far::PatchTablesFactory::Options::ENDCAP_GREGORY_BASIS); } patchTables = Far::PatchTablesFactory::Create(*refiner, poptions); } *patchTablesOut = patchTables; // append gregory vertices into stencils { if (Far::StencilTables const *vertexStencilsWithEndCap = Far::StencilTablesFactory::AppendEndCapStencilTables( *refiner, vertexStencils, patchTables->GetEndCapVertexStencilTables())) { delete vertexStencils; vertexStencils = vertexStencilsWithEndCap; } if (varyingStencils) { if (Far::StencilTables const *varyingStencilsWithEndCap = Far::StencilTablesFactory::AppendEndCapStencilTables( *refiner, varyingStencils, patchTables->GetEndCapVaryingStencilTables())) { delete varyingStencils; varyingStencils = varyingStencilsWithEndCap; } } } int numControlVertices = refiner->GetNumVertices(0); _stencilTableSize = createMeshRefiner(vertexStencils, varyingStencils, numControlVertices); // note: refiner takes ownerships of vertexStencils/ varyingStencils, patchTables delete refiner; return numControlVertices + vertexStencils->GetNumStencils(); } int SceneBase::AddObjects(int numObjects) { _objects.clear(); int numTopologies = (int)_topologies.size(); int vertsOffset = 0; for (int i = 0; i < numObjects; ++i) { Object obj; obj.topologyIndex = i % numTopologies; obj.vertsOffset = vertsOffset; _objects.push_back(obj); vertsOffset += _topologies[obj.topologyIndex].numVerts; } // invalidate batch for (int i = 0; i < (int)_batches.size(); ++i) { glDeleteBuffers(1, &_batches[i].dispatchBuffer); } _batches.clear(); return vertsOffset; } size_t SceneBase::CreateIndexBuffer() { if (_indexBuffer == 0) { glGenBuffers(1, &_indexBuffer); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); std::vector buffer; std::vector ppBuffer; int numTopologies = (int)_topologies.size(); for (int i = 0; i < numTopologies; ++i) { Far::PatchTables const *patchTables = _patchTables[i]; int nPatchArrays = patchTables->GetNumPatchArrays(); _topologies[i].patchArrays.clear(); // for each patchArray for (int j = 0; j < nPatchArrays; ++j) { SceneBase::PatchArray patchArray; patchArray.desc = patchTables->GetPatchArrayDescriptor(j); patchArray.numPatches = patchTables->GetNumPatches(j); patchArray.indexOffset = (int)buffer.size(); patchArray.primitiveIDOffset = (int)ppBuffer.size()/3; _topologies[i].patchArrays.push_back(patchArray); // indices Far::ConstIndexArray indices = patchTables->GetPatchArrayVertices(j); for (int k = 0; k < indices.size(); ++k) { buffer.push_back(indices[k]); } // patchParams Far::ConstPatchParamArray patchParams = patchTables->GetPatchParams(j); // XXX: needs sharpness interface for patcharray or put sharpness into patchParam. for (int k = 0; k < patchParams.size(); ++k) { float sharpness = 0.0; ppBuffer.push_back(patchParams[k].faceIndex); ppBuffer.push_back(patchParams[k].bitField.field); ppBuffer.push_back(*((unsigned int *)&sharpness)); } } #if 0 // XXX: we'll remove below APIs from Far::PatchTables. // use GetPatchParams(patchArray) instead as above. // patch param (all in one) Far::PatchParamTable const &patchParamTables = patchTables->GetPatchParamTable(); std::vector const &sharpnessIndexTable = patchTables->GetSharpnessIndexTable(); std::vector const &sharpnessValues = patchTables->GetSharpnessValues(); int npatches = (int)patchParamTables.size(); for (int i = 0; i < npatches; ++i) { float sharpness = 0.0; if (i < (int)sharpnessIndexTable.size()) { sharpness = sharpnessIndexTable[i] >= 0 ? sharpnessValues[sharpnessIndexTable[i]] : 0.0f; } ppBuffer.push_back(patchParamTables[i].faceIndex); ppBuffer.push_back(patchParamTables[i].bitField.field); ppBuffer.push_back(*((unsigned int *)&sharpness)); } #endif } glBufferData(GL_ELEMENT_ARRAY_BUFFER, (int)buffer.size()*sizeof(int), &buffer[0], GL_STATIC_DRAW); // patchParam is currently expected to be texture (it can be SSBO) GLuint texBuffer = 0; glGenBuffers(1, &texBuffer); glBindBuffer(GL_ARRAY_BUFFER, texBuffer); glBufferData(GL_ARRAY_BUFFER, ppBuffer.size()*sizeof(unsigned int), &ppBuffer[0], GL_STATIC_DRAW); if (_patchParamTexture == 0) { glGenTextures(1, &_patchParamTexture); } glBindTexture(GL_TEXTURE_BUFFER, _patchParamTexture); glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32I, texBuffer); glBindTexture(GL_TEXTURE_BUFFER, 0); glDeleteBuffers(1, &texBuffer); return buffer.size()*sizeof(int) + ppBuffer.size()*sizeof(int); } void SceneBase::buildBatches() { int numObjects = (int)_objects.size(); for (int i = 0; i < (int)_batches.size(); ++i) { glDeleteBuffers(1, &_batches[i].dispatchBuffer); } _batches.clear(); typedef std::map > StagingBatches; StagingBatches stagingBatches; for (int i = 0; i < numObjects; ++i) { // get patchArrays from topology SceneBase::PatchArrayVector const &patchArrays = _topologies[_objects[i].topologyIndex].patchArrays; // for each patchArray: for (int j = 0; j < (int)patchArrays.size(); ++j) { SceneBase::PatchArray const &patchArray = patchArrays[j]; // find batch for the descriptor std::vector &command = stagingBatches[patchArray.desc]; int nPatch = patchArray.numPatches; int baseVertex = GetVertsOffset(i); command.push_back(nPatch * patchArray.desc.GetNumControlVertices()); command.push_back(1); command.push_back(patchArray.indexOffset); command.push_back(baseVertex); command.push_back(0); command.push_back(patchArray.primitiveIDOffset); } } int stride = sizeof(int)*6; // not 5, since we interleave primitiveIDOffset for (StagingBatches::iterator it = stagingBatches.begin(); it != stagingBatches.end(); ++it) { Batch batch; glGenBuffers(1, &batch.dispatchBuffer); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch.dispatchBuffer); glBufferData(GL_DRAW_INDIRECT_BUFFER, it->second.size()*sizeof(int), &it->second[0], GL_STATIC_DRAW); batch.desc = it->first; batch.count = (int)it->second.size()/6; batch.stride = stride; _batches.push_back(batch); } glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); }