def test_IntersectionViewVolume(self): # a viewProjMat corresponding to a persp cam looking down the Y axis, # aimed at the origin. viewMat = Gf.Matrix4d(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -20, 1.0) projMat = Gf.Matrix4d(4.241894005673533, 0.0, 0.0, 0.0, 0.0, 4.2418940586972074, 0.0, 0.0, 0.0, 0.0, -1, -1.0, 0.0, 0.0, -20, 0.0) viewProjMat = viewMat * projMat # a typical box entirely in the view b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) ) self.assertTrue(Gf.Frustum.IntersectsViewVolume(b,viewProjMat)) # a typical box entirely out of the view b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 100, 0, 0 ), Gf.Vec3d( 101, 1, 1 ) ) ) self.assertFalse(Gf.Frustum.IntersectsViewVolume(b,viewProjMat)) # a large box entirely enclosing the view b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( -1e9, -1e9, -1e9 ), Gf.Vec3d( 1e9, 1e9, 1e9 ) ) ) self.assertTrue(Gf.Frustum.IntersectsViewVolume(b,viewProjMat))
def test_EmptyFrustumIntersection(self): self.assertFalse(Gf.Frustum().Intersects(Gf.BBox3d())) self.assertTrue(Gf.Frustum().Intersects(Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1,-1,-1), Gf.Vec3d(1,1,1))))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,0,-1))) self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0))) self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(1,1,1), Gf.Vec3d(0,0,1))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(-1,-1,-1), Gf.Vec3d(0,0,1))) self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0, 100, -100), \ Gf.Vec3d(-100,-100,100), \ Gf.Vec3d(100,-100,100))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0, 10, 100), \ Gf.Vec3d(-100,-10,-10), \ Gf.Vec3d(100,-10,-10))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0, 1, 1), \ Gf.Vec3d(50,0,-50), \ Gf.Vec3d(-50,0,-50))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(-1,-1,-1), Gf.Vec3d(0,0,1))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,-1))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(-100,0,-1), Gf.Vec3d(100,0,-1))) self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,100,-1), Gf.Vec3d(0,-100,-1))) self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(-100,0,1), Gf.Vec3d(100,0,-1))) self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,1)))
def test_Constructors(self): # no arg self.assertIsInstance( Gf.BBox3d(), Gf.BBox3d ) # copy constructor self.assertIsInstance( Gf.BBox3d( Gf.BBox3d() ), Gf.BBox3d ) # construct from range. self.assertIsInstance( Gf.BBox3d( Gf.Range3d() ), Gf.BBox3d ) # construct from range and matrix. self.assertIsInstance( Gf.BBox3d( Gf.Range3d(), Gf.Matrix4d() ), Gf.BBox3d )
def test_Operators(self): # equality r1 = Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) b1 = Gf.BBox3d( r1 ) b2 = Gf.BBox3d( r1 ) self.assertTrue(b1 == b2) # inequality r1 = Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) r2 = Gf.Range3d( Gf.Vec3d( 1, 1, 1 ), Gf.Vec3d( 2, 2, 2 ) ) b1 = Gf.BBox3d( r1 ) b2 = Gf.BBox3d( r2 ) self.assertTrue(b1 != b2) # string (just checks that it's not empty..) self.assertTrue(len(str(Gf.BBox3d())))
def TestPurposeWithInstancing(): """ Tests that purpose filtered bounding boxes work correctly with native instancing and inherited purpose. """ # Our test stages should all produce the exact same default and render # purpose bounding boxes even though they have different permutations of # instancing prims. defaultBBox = Gf.BBox3d( Gf.Range3d(Gf.Vec3d(-1.0, -1.0, -1.0), Gf.Vec3d(1.0, 1.0, 11.0))) renderBBox = Gf.BBox3d( Gf.Range3d(Gf.Vec3d(-11.0, -1.0, -16.0), Gf.Vec3d(1.0, 1.0, 11.0))) defaultCache = UsdGeom.BBoxCache(Usd.TimeCode.Default(), ['default']) renderCache = UsdGeom.BBoxCache(Usd.TimeCode.Default(), ['default', 'render']) # Stage with all instancing disabled. stage = Usd.Stage.Open("disableAllInstancing.usda") assert len(stage.GetMasters()) == 0 root = stage.GetPrimAtPath("/Root") assert defaultCache.ComputeWorldBound(root) == defaultBBox assert renderCache.ComputeWorldBound(root) == renderBBox # Stage with one set of instances. stage = Usd.Stage.Open("disableInnerInstancing.usda") assert len(stage.GetMasters()) == 1 root = stage.GetPrimAtPath("/Root") assert defaultCache.ComputeWorldBound(root) == defaultBBox assert renderCache.ComputeWorldBound(root) == renderBBox # Stage with one different set of instances. stage = Usd.Stage.Open("disableOuterInstancing.usda") assert len(stage.GetMasters()) == 1 root = stage.GetPrimAtPath("/Root") assert defaultCache.ComputeWorldBound(root) == defaultBBox assert renderCache.ComputeWorldBound(root) == renderBBox # Stage with both sets of instances which are nested. stage = Usd.Stage.Open("nestedInstanceTest.usda") assert len(stage.GetMasters()) == 2 root = stage.GetPrimAtPath("/Root") assert defaultCache.ComputeWorldBound(root) == defaultBBox assert renderCache.ComputeWorldBound(root) == renderBBox
def _VerifyExtentAndBBox(light, expectedExtent): self.assertEqual( UsdGeom.Boundable.ComputeExtentFromPlugins(light, time), expectedExtent) self.assertEqual( light.ComputeLocalBound(time, "default"), Gf.BBox3d( Gf.Range3d(Gf.Vec3d(expectedExtent[0]), Gf.Vec3d(expectedExtent[1])), Gf.Matrix4d(1.0)))
def test_IntersectOrientedBox(self): # Rotate (1,0,0) to (1,1,1), and translate by (3,3,3) xform = Gf.Matrix4d(Gf.Rotation(Gf.Vec3d(1,0,0), Gf.Vec3d(1,1,1,)), \ Gf.Vec3d(3,3,3)) box = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)), xform) r = Gf.Ray(Gf.Vec3d(0, 0, 0), Gf.Vec3d(1, 1, 1)) (hit, enterDist, exitDist) = r.Intersect(box) self.assertTrue(hit and Gf.IsClose(enterDist, 2.42264973081, 0.00001) \ and Gf.IsClose(exitDist, 3.57735026919, 0.00001))
def TestUsd4957(): """ Tests the case in which a prim has an xform directly on it and its bounding box relative to one of its ancestors is computed using ComputeRelativeBound(). """ s = Usd.Stage.Open("testUSD4957.usda") b = s.GetPrimAtPath("/A/B") c = s.GetPrimAtPath("/A/B/C") bc = UsdGeom.BBoxCache(Usd.TimeCode.Default(), ['default', 'render']) # Call the function being tested relativeBbox = bc.ComputeRelativeBound(c, b) # Compare the result with the bbox of C in its local space cExtent = UsdGeom.Boundable(c).GetExtentAttr().Get() cRange = Gf.Range3d(Gf.Vec3d(cExtent[0]), Gf.Vec3d(cExtent[1])) cLocalXform = UsdGeom.Xformable(c).GetLocalTransformation() cBbox = Gf.BBox3d(cRange, cLocalXform) AssertBBoxesClose(relativeBbox, cBbox, "ComputeRelativeBound produced a wrong bbox.")
def test_BBoxCache(self): """ Tests that a UsdGeomPointInstancer with multiple instances of multiple cube prototypes has the correct bboxes computed with UsdGeomBBoxCache. """ stage = Usd.Stage.CreateInMemory() world = UsdGeom.Xform.Define(stage, '/World') parent = UsdGeom.Xform.Define( stage, world.GetPath().AppendChild('parent')) instancer = UsdGeom.PointInstancer.Define( stage, parent.GetPath().AppendChild('MyPointInstancer')) prototypesPrim = self.stage.DefinePrim( instancer.GetPath().AppendChild('prototypes')) prototypesPrimPath = prototypesPrim.GetPath() # A unit cube at the origin. originCube = self._AddCubeModel( stage, prototypesPrimPath.AppendChild('OriginCube')) # A cube at the origin with a scale xformOp that makes it of length 5 # in each dimension. originScaledCube = self._AddCubeModel( stage, prototypesPrimPath.AppendChild('OriginScaledCube')) xformable = UsdGeom.Xformable(originScaledCube) xformable.AddScaleOp().Set(Gf.Vec3f(5.0)) # A unit cube with a translate xformOp. translatedCube = self._AddCubeModel( stage, prototypesPrimPath.AppendChild('TranslatedCube')) xformable = UsdGeom.Xformable(translatedCube) xformable.AddTranslateOp().Set(Gf.Vec3d(3.0, 6.0, 9.0)) # A unit cube with a rotateZ xformOp. rotatedCube = self._AddCubeModel( stage, prototypesPrimPath.AppendChild('RotatedCube')) xformable = UsdGeom.Xformable(rotatedCube) xformable.AddRotateZOp().Set(45.0) instancer.CreatePrototypesRel().SetTargets([ originCube.GetPath(), originScaledCube.GetPath(), translatedCube.GetPath(), rotatedCube.GetPath() ]) # Add transformations on the parent and the instancer itself. UsdGeom.Xformable(world).AddTranslateOp().Set((2,2,2)) UsdGeom.Xformable(parent).AddTranslateOp().Set((7,7,7)) UsdGeom.Xformable(instancer).AddTranslateOp().Set((11,11,11)) positions = [Gf.Vec3f(0,0,0)]*4 indices = range(4) self._SetTransformComponentsAndIndices( instancer, positions=positions, indices=indices) bboxCache = UsdGeom.BBoxCache( Usd.TimeCode.Default(), includedPurposes=[UsdGeom.Tokens.default_]) unitBox = Gf.Range3d((-0.5,)*3, (0.5,)*3) worldxf = Gf.Matrix4d().SetTranslate((2,)*3) parentxf = Gf.Matrix4d().SetTranslate((7,)*3) instancerxf = Gf.Matrix4d().SetTranslate((11,)*3) cubescale = Gf.Matrix4d().SetScale((5,)*3) cubexlat = Gf.Matrix4d().SetTranslate((3,6,9)) cuberot = Gf.Matrix4d().SetRotate(Gf.Rotation((0,0,1), 45)) cases = [ (0, Gf.Matrix4d()), # originCube (1, cubescale), # originScaledCube (2, cubexlat), # translatedCube (3, cuberot), # rotatedCube ] # scalar for iid, cubexf in cases: self.assertEqual( bboxCache.ComputePointInstanceWorldBound(instancer, iid), Gf.BBox3d(unitBox, cubexf*instancerxf*parentxf*worldxf)) self.assertEqual( bboxCache.ComputePointInstanceRelativeBound( instancer, iid, world.GetPrim()), Gf.BBox3d(unitBox, cubexf*instancerxf*parentxf)) self.assertEqual( bboxCache.ComputePointInstanceLocalBound(instancer, iid), Gf.BBox3d(unitBox, cubexf*instancerxf)) self.assertEqual( bboxCache.ComputePointInstanceUntransformedBound( instancer, iid), Gf.BBox3d(unitBox, cubexf)) # vectorized for i, wbox in enumerate(bboxCache.ComputePointInstanceWorldBounds( instancer, range(4))): self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]* instancerxf*parentxf*worldxf)) for i, wbox in enumerate(bboxCache.ComputePointInstanceRelativeBounds( instancer, range(4), world.GetPrim())): self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]* instancerxf*parentxf)) for i, wbox in enumerate(bboxCache.ComputePointInstanceLocalBounds( instancer, range(4))): self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]* instancerxf)) for i, wbox in enumerate( bboxCache.ComputePointInstanceUntransformedBounds( instancer, range(4))): self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]))
def test_LightExtentAndBBox(self): # Test extent and bbox computations for the boundable lights. time = Usd.TimeCode.Default() # Helper for computing the extent and bounding boxes for a light and # comparing against an expect extent pair. def _VerifyExtentAndBBox(light, expectedExtent): self.assertEqual( UsdGeom.Boundable.ComputeExtentFromPlugins(light, time), expectedExtent) self.assertEqual( light.ComputeLocalBound(time, "default"), Gf.BBox3d( Gf.Range3d( Gf.Vec3d(expectedExtent[0]), Gf.Vec3d(expectedExtent[1])), Gf.Matrix4d(1.0))) # Create a prim of each boundable light type. stage = Usd.Stage.CreateInMemory() rectLight = UsdLux.RectLight.Define(stage, "/RectLight") self.assertTrue(rectLight) diskLight = UsdLux.DiskLight.Define(stage, "/DiskLight") self.assertTrue(diskLight) cylLight = UsdLux.CylinderLight.Define(stage, "/CylLight") self.assertTrue(cylLight) sphereLight = UsdLux.SphereLight.Define(stage, "/SphereLight") self.assertTrue(sphereLight) # Verify the extent and bbox computations for each light given its # fallback attribute values. _VerifyExtentAndBBox(rectLight, [(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)]) _VerifyExtentAndBBox(diskLight, [(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)]) _VerifyExtentAndBBox(cylLight, [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]) _VerifyExtentAndBBox(sphereLight, [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]) # Change the size related attribute of each light and verify the extents # and bounding boxes are updated. rectLight.CreateWidthAttr(4.0) rectLight.CreateHeightAttr(6.0) _VerifyExtentAndBBox(rectLight, [(-2.0, -3.0, 0.0), (2.0, 3.0, 0.0)]) diskLight.CreateRadiusAttr(5.0) _VerifyExtentAndBBox(diskLight, [(-5.0, -5.0, 0.0), (5.0, 5.0, 0.0)]) cylLight.CreateRadiusAttr(4.0) cylLight.CreateLengthAttr(10.0) _VerifyExtentAndBBox(cylLight, [(-4.0, -4.0, -5.0), (4.0, 4.0, 5.0)]) sphereLight.CreateRadiusAttr(3.0) _VerifyExtentAndBBox(sphereLight, [(-3.0, -3.0, -3.0), (3.0, 3.0, 3.0)]) # Special case for portal light. Portal lights don't have any attributes # that affect their extent, but they do have a constant extent defined # for a unit rectangle in the XY plane. portalLight = UsdLux.PortalLight.Define(stage, "/PortalLight") self.assertTrue(portalLight) self.assertIsNone( UsdGeom.Boundable.ComputeExtentFromPlugins(portalLight, time)) self.assertEqual( portalLight.ComputeLocalBound(time, "default"), Gf.BBox3d( Gf.Range3d(Gf.Vec3d(-0.5, -0.5, 0.0), Gf.Vec3d(0.5, 0.5, 0.0)), Gf.Matrix4d(1.0))) # For completeness verify that distant and dome lights are not # boundable. domeLight = UsdLux.DomeLight.Define(stage, "/DomeLight") self.assertTrue(domeLight) self.assertFalse(UsdGeom.Boundable(domeLight)) distLight = UsdLux.DistantLight.Define(stage, "/DistLight") self.assertTrue(distLight) self.assertFalse(UsdGeom.Boundable(distLight))
def test_MethodsAndProperties(self): # set m = Gf.Matrix4d() r = Gf.Range3d() b = Gf.BBox3d() self.assertEqual(b.Set( r, m ), Gf.BBox3d( r, m )) # matrix prop b = Gf.BBox3d() b.matrix = Gf.Matrix4d(5) self.assertEqual(b.matrix, Gf.Matrix4d(5)) # box property b = Gf.BBox3d() self.assertTrue(b.box.IsEmpty()) b.box = Gf.Range3d( Gf.Vec3d(1,2,3), Gf.Vec3d(4,5,6) ) self.assertEqual(b.box, Gf.Range3d( Gf.Vec3d(1,2,3), Gf.Vec3d(4,5,6) )) self.assertFalse(b.box.IsEmpty()) # GetInverseGf.Matrix b = Gf.BBox3d() b.matrix = Gf.Matrix4d(5) m = Gf.Matrix4d(5).GetInverse() self.assertEqual(b.GetInverseMatrix(), Gf.Matrix4d(5).GetInverse()) # hasZeroAreaPrimitives b = Gf.BBox3d() b.hasZeroAreaPrimitives = True b.hasZeroAreaPrimitives = not b.hasZeroAreaPrimitives self.assertFalse(b.hasZeroAreaPrimitives) # GetVolume b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 2, 2, 2 ) ) ) self.assertEqual(b.GetVolume(), 8) b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1),Gf.Vec3d())) self.assertEqual(b.GetVolume(), 0) # Transform m1 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30)) m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60)) b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m1 ) b.Transform(m2) self.assertEqual(b.matrix, (m1 * m2)) # ComputeAlignedRange m = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30)) b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m ) r1 = b.ComputeAlignedRange() b = Gf.BBox3d( r1 ) r2 = b.ComputeAlignedRange() self.assertEqual(r1, r2) m = Gf.Matrix4d().SetScale(3) b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)), m) r = b.ComputeAlignedRange() self.assertEqual(r.GetSize(), Gf.Vec3d(6.0, 6.0, 6.0)) m = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30)) b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)), m) angle = math.pi / 6 # 30 degrees width = 2 * (math.cos(angle) + math.sin(angle)) size = Gf.Vec3d(2.0, width, width) r = b.ComputeAlignedRange() self.assertFalse((r.GetSize() - size).GetLength() > 0.000001) b = Gf.BBox3d() r = b.ComputeAlignedRange() self.assertTrue(r.IsEmpty()) # static combine method m1 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30)) m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60)) b1 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m1 ) b2 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 1, 1, 1 ), Gf.Vec3d( 2, 2, 2 ) ), m2 ) b3 = Gf.BBox3d.Combine( b1, b2 ) b4 = Gf.BBox3d.Combine( b2, b1 ) self.assertEqual(b3, b4) # centroid b1 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) ) m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60)) b2 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( -1, -1, -1 ), Gf.Vec3d( 1, 1, 1 ) ), m2) self.assertEqual(b1.ComputeCentroid(), Gf.Vec3d( .5, .5, .5 )) self.assertEqual(b2.ComputeCentroid(), Gf.Vec3d( 0, 0, 0 )) b3 = Gf.BBox3d() self.assertEqual(b3.ComputeCentroid(), Gf.Vec3d( 0, 0, 0 )) # other cases to hit code coverage. m1 = Gf.Matrix4d(Gf.Vec4d(1,0,0,0)) m2 = Gf.Matrix4d(Gf.Vec4d(0,1,0,0)) b1 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d()), m1) b2 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d(2,2,2)), m2) b3 = Gf.BBox3d.Combine(b1, b2) self.assertEqual(b3, b2) b3 = Gf.BBox3d.Combine(b2, b1) self.assertEqual(b3, b2) m1 = Gf.Matrix4d(Gf.Vec4d(1,0,0,0)) m2 = Gf.Matrix4d(Gf.Vec4d(0,1,0,0)) m3 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60)) b1 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(0,0,0), Gf.Vec3d(0,1,1)), m1) b2 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,0)), m2) b3 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d(2,2,2)), m3) b4 = Gf.BBox3d.Combine(b1,b2) b4 = Gf.BBox3d.Combine(b1,b2) b4 = Gf.BBox3d.Combine(b2,b3) b4 = Gf.BBox3d.Combine(b3,b2) self.assertEqual(b4, eval(repr(b4)))