bool GusdBoundsCache::_ComputeBound( const UsdPrim &prim, UsdTimeCode time, const TfTokenVector &includedPurposes, ComputeFunc boundFunc, UT_BoundingBox &bounds ) { if( !prim.IsValid() ) return false; TfToken stageId( prim.GetStage()->GetRootLayer()->GetRealPath() ); MapType::accessor accessor; if( !m_map.find( accessor, Key( stageId, includedPurposes ))) { m_map.insert( accessor, Key( stageId, includedPurposes ) ); accessor->second = new Item( time, includedPurposes ); } std::lock_guard<std::mutex> lock(accessor->second->lock); UsdGeomBBoxCache& cache = accessor->second->bboxCache; cache.SetTime( time ); // boundFunc is either ComputeWorldBound or ComputeLocalBound GfBBox3d primBBox = (cache.*boundFunc)(prim); if( !primBBox.GetRange().IsEmpty() ) { const GfRange3d rng = primBBox.ComputeAlignedRange(); bounds = UT_BoundingBox( rng.GetMin()[0], rng.GetMin()[1], rng.GetMin()[2], rng.GetMax()[0], rng.GetMax()[1], rng.GetMax()[2]); return true; } return false; }
VtVec3fArray UsdGeomModelAPI::ComputeExtentsHint( UsdGeomBBoxCache& bboxCache) const { static const TfTokenVector &purposeTokens = UsdGeomImageable::GetOrderedPurposeTokens(); VtVec3fArray extents(purposeTokens.size() * 2); size_t lastNonEmptyBbox = std::numeric_limits<size_t>::max(); // We should be able execute this loop in parallel since the // bounding box computation can be multi-threaded. However, most // conversion processes are run on the farm and are limited to one // CPU, so there may not be a huge benefit from doing this. Also, // we expect purpose 'default' to be the most common purpose value // and in some cases the only purpose value. Computing bounds for // the rest of the purpose values should be very fast. for(size_t bboxType = purposeTokens.size(); bboxType-- != 0; ) { // Set the gprim purpose that we are interested in computing the // bbox for. This doesn't cause the cache to be blown. bboxCache.SetIncludedPurposes( std::vector<TfToken>(1, purposeTokens[bboxType])); GfBBox3d bbox = bboxCache. ComputeUntransformedBound(GetPrim()); const GfRange3d range = bbox.ComputeAlignedBox(); if (!range.IsEmpty() && lastNonEmptyBbox == std::numeric_limits<size_t>::max()) lastNonEmptyBbox = bboxType; const GfVec3d &min = range.GetMin(); const GfVec3d &max = range.GetMax(); size_t index = bboxType * 2; extents[index] = GfVec3f(min[0], min[1], min[2]); extents[index + 1] = GfVec3f(max[0], max[1], max[2]); } // If all the extents are empty. Author a single empty range. if (lastNonEmptyBbox == std::numeric_limits<size_t>::max()) lastNonEmptyBbox = 0; // Shrink the array to only include non-empty bounds. // If all the bounds are empty, we still need to author one empty // bound. extents.resize(2 * (lastNonEmptyBbox + 1)); return extents; }
bool UsdGeomCylinder::ComputeExtent(double height, double radius, const TfToken& axis, const GfMatrix4d& transform, VtVec3fArray* extent) { // Create Sized Extent extent->resize(2); GfVec3f max; if (!_ComputeExtentMax(height, radius, axis, &max)) { return false; } GfBBox3d bbox = GfBBox3d(GfRange3d(-max, max), transform); GfRange3d range = bbox.ComputeAlignedRange(); (*extent)[0] = GfVec3f(range.GetMin()); (*extent)[1] = GfVec3f(range.GetMax()); return true; }
bool UsdGeomPointInstancer::ComputeExtentAtTime( VtVec3fArray* extent, const UsdTimeCode time, const UsdTimeCode baseTime) const { if (!extent) { TF_WARN("%s -- null container passed to ComputeExtentAtTime()", GetPrim().GetPath().GetText()); return false; } VtIntArray protoIndices; if (!GetProtoIndicesAttr().Get(&protoIndices, time)) { TF_WARN("%s -- no prototype indices", GetPrim().GetPath().GetText()); return false; } const std::vector<bool> mask = ComputeMaskAtTime(time); if (!mask.empty() && mask.size() != protoIndices.size()) { TF_WARN("%s -- mask.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), mask.size(), protoIndices.size()); return false; } const UsdRelationship prototypes = GetPrototypesRel(); SdfPathVector protoPaths; if (!prototypes.GetTargets(&protoPaths) || protoPaths.empty()) { TF_WARN("%s -- no prototypes", GetPrim().GetPath().GetText()); return false; } // verify that all the protoIndices are in bounds. TF_FOR_ALL(iter, protoIndices) { const int protoIndex = *iter; if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size()) { TF_WARN("%s -- invalid prototype index: %d. Should be in [0, %zu)", GetPrim().GetPath().GetText(), protoIndex, protoPaths.size()); return false; } } // Note that we do NOT apply any masking when computing the instance // transforms. This is so that for a particular instance we can determine // both its transform and its prototype. Otherwise, the instanceTransforms // array would have masked instances culled out and we would lose the // mapping to the prototypes. // Masked instances will be culled before being applied to the extent below. VtMatrix4dArray instanceTransforms; if (!ComputeInstanceTransformsAtTime(&instanceTransforms, time, baseTime, IncludeProtoXform, IgnoreMask)) { TF_WARN("%s -- could not compute instance transforms", GetPrim().GetPath().GetText()); return false; } UsdStageWeakPtr stage = GetPrim().GetStage(); const TfTokenVector purposes { UsdGeomTokens->default_, UsdGeomTokens->proxy, UsdGeomTokens->render }; UsdGeomBBoxCache bboxCache(time, purposes); bboxCache.SetTime(time); GfRange3d extentRange; for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) { if (!mask.empty() && !mask[instanceId]) { continue; } const int protoIndex = protoIndices[instanceId]; const SdfPath& protoPath = protoPaths[protoIndex]; const UsdPrim& protoPrim = stage->GetPrimAtPath(protoPath); // Get the prototype bounding box. GfBBox3d thisBounds = bboxCache.ComputeUntransformedBound(protoPrim); // Apply the instance transform. thisBounds.Transform(instanceTransforms[instanceId]); extentRange.UnionWith(thisBounds.ComputeAlignedRange()); } const GfVec3d extentMin = extentRange.GetMin(); const GfVec3d extentMax = extentRange.GetMax(); *extent = VtVec3fArray(2); (*extent)[0] = GfVec3f(extentMin[0], extentMin[1], extentMin[2]); (*extent)[1] = GfVec3f(extentMax[0], extentMax[1], extentMax[2]); return true; }
void My_TestGLDrawing::InitTest() { std::cout << "My_TestGLDrawing::InitTest()\n"; _stage = UsdStage::Open(GetStageFilePath()); SdfPathVector excludedPaths; if (UsdImagingGLEngine::IsHydraEnabled()) { std::cout << "Using HD Renderer.\n"; _engine.reset(new UsdImagingGLEngine( _stage->GetPseudoRoot().GetPath(), excludedPaths)); if (!_GetRenderer().IsEmpty()) { if (!_engine->SetRendererPlugin(_GetRenderer())) { std::cerr << "Couldn't set renderer plugin: " << _GetRenderer().GetText() << std::endl; exit(-1); } else { std::cout << "Renderer plugin: " << _GetRenderer().GetText() << std::endl; } } } else{ std::cout << "Using Reference Renderer.\n"; _engine.reset( new UsdImagingGLEngine(_stage->GetPseudoRoot().GetPath(), excludedPaths)); } std::cout << glGetString(GL_VENDOR) << "\n"; std::cout << glGetString(GL_RENDERER) << "\n"; std::cout << glGetString(GL_VERSION) << "\n"; if (_ShouldFrameAll()) { TfTokenVector purposes; purposes.push_back(UsdGeomTokens->default_); purposes.push_back(UsdGeomTokens->proxy); // Extent hints are sometimes authored as an optimization to avoid // computing bounds, they are particularly useful for some tests where // there is no bound on the first frame. bool useExtentHints = true; UsdGeomBBoxCache bboxCache(UsdTimeCode::Default(), purposes, useExtentHints); GfBBox3d bbox = bboxCache.ComputeWorldBound(_stage->GetPseudoRoot()); GfRange3d world = bbox.ComputeAlignedRange(); GfVec3d worldCenter = (world.GetMin() + world.GetMax()) / 2.0; double worldSize = world.GetSize().GetLength(); std::cerr << "worldCenter: " << worldCenter << "\n"; std::cerr << "worldSize: " << worldSize << "\n"; if (UsdGeomGetStageUpAxis(_stage) == UsdGeomTokens->z) { // transpose y and z centering translation _translate[0] = -worldCenter[0]; _translate[1] = -worldCenter[2]; _translate[2] = -worldCenter[1] - worldSize; } else { _translate[0] = -worldCenter[0]; _translate[1] = -worldCenter[1]; _translate[2] = -worldCenter[2] - worldSize; } } else { _translate[0] = GetTranslate()[0]; _translate[1] = GetTranslate()[1]; _translate[2] = GetTranslate()[2]; } if(IsEnabledTestLighting()) { if(UsdImagingGLEngine::IsHydraEnabled()) { // set same parameter as GlfSimpleLightingContext::SetStateFromOpenGL // OpenGL defaults _lightingContext = GlfSimpleLightingContext::New(); GlfSimpleLight light; if (IsEnabledCameraLight()) { light.SetPosition(GfVec4f(_translate[0], _translate[2], _translate[1], 0)); } else { light.SetPosition(GfVec4f(0, -.5, .5, 0)); } light.SetDiffuse(GfVec4f(1,1,1,1)); light.SetAmbient(GfVec4f(0,0,0,1)); light.SetSpecular(GfVec4f(1,1,1,1)); GlfSimpleLightVector lights; lights.push_back(light); _lightingContext->SetLights(lights); GlfSimpleMaterial material; material.SetAmbient(GfVec4f(0.2, 0.2, 0.2, 1.0)); material.SetDiffuse(GfVec4f(0.8, 0.8, 0.8, 1.0)); material.SetSpecular(GfVec4f(0,0,0,1)); material.SetShininess(0.0001f); _lightingContext->SetMaterial(material); _lightingContext->SetSceneAmbient(GfVec4f(0.2,0.2,0.2,1.0)); } else { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); if (IsEnabledCameraLight()) { float position[4] = {_translate[0], _translate[2], _translate[1], 0}; glLightfv(GL_LIGHT0, GL_POSITION, position); } else { float position[4] = {0,-.5,.5,0}; glLightfv(GL_LIGHT0, GL_POSITION, position); } } } }