Skip to content

Archive

Tag: bullet

Most 3D applications use a scenegraph that stores scene node coordinates and we need a convenient way to update these coordinates from the physical simulation. In this case the simulation contains a dynamic object which moves ‘on its own’, being subject to gravity, collisions and other forces.

Often we want to animate objects ourselves, but we still want other objects to bounce off such objects, so we create a kind of alias or reference to the object we’re animating. Such an alias or reference is made into a kinematic object. A kinematic object still has physical properties (e.g. friction) that help determine how dynamic objects interact with it.

This article is a work in progress. Please refer to the motion state tutorial on the Bullet wiki. In theory motion states and kinematic bodies are ‘pretty simple’. I often find it easier to use dynamic bodies out of the box and rely on the default motion state.

The motion state

All bodies in the simulation are setup with a motion state.

The motion state allows sharing a node’s transform between the physics engine and the renderer. btMotionState is a small interface that specifies a getter/setter pair. The bullet API calls the getter to retrieve the shared transform and calls the setter to assign it.

Kinematic objects aren’t animated by the simulation, ‘we do it ourselves’. How do we let the simulation know that these objects have moved?

  1. Create a rigid body that will ‘stand for’ the kinematic object. This will be a kind of ‘alias’ or ‘reference’ to the object we’re animating, so we need to disable dynamics for this object (so it won’t be influenced by gravity or other objects).
  2. implement getWorldTransform() so that an up to date transform is returned whenever the simulation calls that function.
  3. Implement setWorldTransform() so that you (or the engine, if interpolating) can set the transform.
  4. Make the object ‘kinematic’ (see below)

Configuration:

There are two steps to ‘make an object kinematic’.

body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);

This flag tells the engine that the object is kinematic – so it shouldn’t move under the influence of gravity or because of colliding with other objects.

body->setActivationState(DISABLE_DEACTIVATION);

This prevents the object from ‘falling asleep’. Normally objects that haven’t moved in a while aren’t processed and keep sleeping until something bumps into them, or something that they’re in contact with wakes them up. Since kinematic objects aren’t affected by forces, we need to prevent them from falling asleep.

Back to dynamic state (UNTESTED)

body->setCollisionFlags( body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT));

body->activate(true); // or try… body->forceActivationState(ACTIVE_FLAG)

Tips and Caveats

  • Avoid relying on how many times or when the motion state’s get/set methods are accessed. Even if your object is not kinematic, the motion state’s getter may be called after the initial simulation step (TESTED).
  • If you ‘teleport’ a dynamic object, set the object’s transform by calling body->getWorldTransform().setOrigin(); even if you have removed the body from the simulation, after adding this object again the transform underlying your motion state may be overridden by a call to setWorldTransform before getWorldTransform is called by the engine.
  • In my experience it would appear that kinematic objects are somewhat less reliable than dynamic objects. I often seen tunneling effects that disappear if I use a dynamic object instead. Once again testing in a sandbox can be very helpful in such cases.

In the Bullet Physics Library, collision shapes are used to detect collisions between physical bodies.

You can get a feel of what’s available by looking at the inheritance diagram (from the Bullet docs). Depending on the workflow you’re implementing, just using meshes may be a quick-fix. However meshes have several disadvantages, which is why geometric primitives are thrown in:

  • Performance – colliding meshes can be slow
  • Reliability – high speed objects are more likely to miss/fall through when colliding with meshes. This can be fixed using ‘continuous collision detection’ or stepping the simulation slower, but it may reduce performance even more.
  • Memory – Primitives use very little memory.

Convex/Concave

Convex shapes tend to process collisions faster:

  • cone, capsule, sphere, box, cylinder …

Concave shapes tend to process collisions slower

  • Banana, bowl, ring, coffee cup…

If your mesh is convex (boulder?) or mainly interacts with objects 5-10 times bigger than itself, btConvexPointCloudShape has better performance than btBvhTriangleMeshShape.

If we model a coffee cup using a convex point cloud, we can’t shoot  a bullet through the handle(*). But there’s no effective difference when simulating a cup falling on the ground (either way it won’t shatter like the real one, which is sad).

(*) got this example from Wikipedia

Code samples

Collision mesh

To create a collision mesh, we can use…

Example:

#include “btBulletDynamicsCommon.h”

// … DIY: put this code in a function or class method…

btTriangleMesh* data = new btTriangleMesh();

btVector3 A(0.0f,0.0f,0.0f);

btVector3 B(1.0f,0.0f,0.0f);

btVector3 C(0.0f,0.0f,1.0f);

data->addTriangle(A,B,C,false); // false, don’t remove duplicate vertices

// true for using quantization; true for building the BVH

btBvhTriangleMeshShape* shape=new btBvhTriangleMeshShape(data,true,true);

The flags (quantization, BVH) have to do with internal optimizations, I just use the recommended defaults.

Note: I once idiotically created degenerate meshes (each triangle used 3 times the same point). A mesh setup in this awful way may sometimes generate collisions and cause fancy restitution effects. Before you start looking everywhere else for ways to fix tunneling and restitution, make sure your mesh is correctly setup (sigh).

Sphere

float radius=2.5f;

btCollisionShape* shape = new btSphereShape(radius);

Capsule

float totalHeight=5.0f;

float radius=1.0f;

btCollisionShape* shape = new btCapsuleShape(radius,totalHeight-radius*2.0f);

A capsule looks like a medicine pill standing upright. You can use btCapsuleShapeX / btCapsuleShapeZ if you want a different orientation. You could also use btMultiSphereShape if you want to create ‘thick segments’ with round caps (without using a transform) or other interesting things (rounded cuboids and such…)

Workflow notes

If you don’t want your setup to be completely game/application specific, simple techniques can be used to select the right primitives.

In my 3D editor, I use layers to hold various kinds of objects. So I have a layer for actors, another for the terrain, etc…

  • If you don’t need much realism, capsules are a popular choice for actors (another time, I’ll explain why I prefer using spheres).
  • boxes or spheres may be a good choice if you want to include collectible items in your simulation.

Instead of, or in combination with layers, you can use reference metrics to help you decide how an object should be represented:

  • large, concave objects (e.g, weird shaped platforms and such) may require ad-hoc meshes with as few triangles as possible (use a triangle mesh)
  • medium sized objects may use convex point clouds.
  • small objects can use box, cylinder or sphere primitives. If you don’t want your objects to roll, boxes and cylinders are a better choice.
  • fast, small objects (projectiles) can miss collisions easily. Using an elongated ‘dash-arrow-shaped-thing’ (triangle or cylinder) eliminates this problem.

‘Reference metrics’ means that you pass a descriptor defining ‘large, medium, small and fast’ to the class that builds your collision shapes. Then we can use the same factory over and over with game specific metrics. If you simulate very large or very small objects (‘not human scale’), you should worry about scaling (link to the Bullet wiki).

Next time…

Gravity’s fun. Applying forces and shoving bodies around is more fun. Next time we’ll look into dynamic and kinematic behavior.

The Bullet Physics Library is an open source (free for private and commercial use) physics engine mainly written by Erwin Coumans. After 8 years of development or more, it is a mature library. Integrations with Ogre, Irrlicht, Unity and other engines are available. It also integrates with content creation software, including Maya and Blender and has been used in a lot of games (wikipedia?)

After messing with the build a little (see my recent posts), we are ready for a friendly introduction.

How simple is simple?

Conceptually, this is how I want to setup a physics simulation:

  1. Create a container (‘physics world’).
  2. Add objects, aka ‘rigid bodies’.
  3. Step the simulation and enjoy the result.

That would be 3 lines of code, right? How about something like…

PhysicalWorld world=new PhysicalWorld();
world.addBody(new Ball());
for(int i=0;i<10;i++)world.step(10); // 10 milliseconds

There are countless assumptions underlying this code. Gravity. Friction. Flying cows. You name it. I’m not saying that a physics engine should provide this level of integration (who would ever need it?); definitely not saying that there shouldn’t be 3 or 4 additional constructors taking in quizzical parameters.

I know this: if a physics engine’s hello world program looked like this, countless school kids would try it out, feel an atavistic surge of adrenaline and dive into the gory details.

You won’t get away without reading the bullet hello world tutorial

Let’s see how Bullet lives up to the leap of faith. I simplified their hello world tutorial for you, but frankly I’m just trying to encourage you to read it. I also highlighted the key steps.

#include <btBulletDynamicsCommon.h>

int main (void){

 // create the 'physical world'
 //
        btBroadphaseInterface* broadphase =
            new btDbvtBroadphase();
        btDefaultCollisionConfiguration* collisionConfiguration =
            new btDefaultCollisionConfiguration();
        btCollisionDispatcher* dispatcher =
            new btCollisionDispatcher(collisionConfiguration);

        btSequentialImpulseConstraintSolver* solver =
            new btSequentialImpulseConstraintSolver;

        btDiscreteDynamicsWorld* dynamicsWorld = 
            new btDiscreteDynamicsWorld(
                  dispatcher,broadphase,solver,collisionConfiguration);
        dynamicsWorld->setGravity(btVector3(0,-10,0));

 // create the ball
 //
        btCollisionShape* shape = new btSphereShape(1);
        btDefaultMotionState* motionState =
                new btDefaultMotionState(
                      btTransform(btQuaternion(0,0,0,1),
                                  btVector3(0,50,0))
                );
        btScalar mass = 1;
        btVector3 inertia(0,0,0);
        shape->calculateLocalInertia(mass,inertia);
        btRigidBody::btRigidBodyConstructionInfo
             bodyDescriptor(mass,motionState,shape,inertia);
        btRigidBody* ball = new btRigidBody(bodyDescriptor);
        dynamicsWorld->addRigidBody(ball);

 // step the simulation (and enjoy the result)
 //
        for (int i=0 ; i<10 ; i++){
          dynamicsWorld->stepSimulation(1/60.0f,10);
        }

 // remove and delete the ball
 //
        dynamicsWorld->removeRigidBody(ball);
        delete ball->getMotionState();
        delete ball;
        delete shape;

 // delete the world
 //
        delete dynamicsWorld;
        delete solver;
        delete collisionConfiguration;
        delete dispatcher;
        delete broadphase;

        return 0;
}

Not self explanatory

To avoid plagiarism and rest my keyboard, I suggest you go and read that tutorial. It explains everything step by step. Aside, the original tutorial includes a ground plane and log output so you can ‘see the ball falling and bouncing’ (that is, read the log and observe that the height of the ball varies).

Seeing is believing. Testing is learning.

After pasting in the original tutorial, we have a choice:

  1. Plug graphic output of sorts and start hacking way
  2. Read on, write sample code and verify our assumptions using tests.

I’m totally against option 1.

  • If you haven’t got a system that produces graphic output yet, trying out everything at once will bring utter confusion.
  • If you do have a system that produces graphic output and attempt integrating right away, you’re burdening yourself with the need to match your transforms and rotations to bullet’s before learning anything physics related, which is somewhat demotivating; or…
  • …you are blissfully ignoring the fact that with screwed up transforms, the physics will appear to go awfully wrong. Then you’ll be asking around, complaining and imagining bugs that aren’t there.

Option 2 consists in getting a test framework up and running and writing innocuous simulations using the hello world tutorial as a starting point. Use console output; assert results; use breakpoints.

You can test without a test framework but you’ll end up with a mess of ‘little tests’ that only run when you ask them to. Lining up tests using a test framework is cleaner, faster and documents our learning process.

Outlook

This article is retrospective. I’m integrating bullet with my game engine and hope to get ‘all basic stuff’ sorted this weekend. Seven rough days in, I can build a ‘physics world’ that matches my game scenes, got the transforms sorted and can mix dynamic and kinematic objects.

In the next articles I will cover the following:

  • collision and contact
  • dynamics and kinematics (aka ‘the motion state’)
  • creating meshes and other objects
  • transforms and rendering.

Last time I documented a rough setup for Bullet on iOS. I think this is much cleaner and would highly recommend you try it. It should take no more than an hour. If you have problems with this, please drop a comment and I’ll try to help you out.

Recipe for building bullet as an iOS ready static library

  1. Grab the archive. I used the *.tgz version (=> download page; Bullet physics engine homepage)
  2. Extract this somewhere you like; I put this under trunk/ext/bullet, thus renaming from bullet-x.xx to bullet
  3. Go to bullet/Extras/AllBulletDemosOSX; find a project named AllBulletDemos.xcodeproj
  4. Drag the project in your xcode workspace (requires XCode 4 or later). At the time of writing the OS X demos build correctly with XCode  4.0.2. Note that this is a MacOS project, not an iOS project – if you build and run you should see a window with lots of attractive demos. If you don’t see this window try to fix the project first(!).
  5. Create a new project (static library) in the same workspace. If you create this project inside the bullet folder, you could name it ios, then rename the project to bullet. You may let XCode create a unit tests target for you.
  6. Use the project navigator to find a group under AllBulletDemosOSX/src/src. Drag this group to the newly created bullet project.
  7. At project level in build settings, set the header search path to ../src and check ‘recursive’
  8. build.
  9. At this point you can remove AllBulletDemosOSX from your workspace if you wish.
  10. (strongly recommended) use the ‘hello world’ code from the bullet wiki to write a simple test, and make sure you get the test to build and run correctly. You probably need to add files that were not under AllBulletDemosOSX/src/src. This is likely to happen because there is no automation that reliably tells xcode to include new source files as they are added to the underlying src folder (sigh).
    In practice you will see a lot of linkage errors that can be easily fixed by adding the missing files from src/LinearMath/, src/BulletSoftBody, src/BulletCollision etc…
  11. (optional) fix the warnings that appear here and there and spoil the build.

Why do it this way?

There are several assumptions underlying this approach:

  • You won’t update very often and would like to check in the source in your own repository, or maybe you don’t use version control but want to keep tidy. I use the so called ‘ext’ folder for third party stuff.
  • You want a separate library; for this to work with iOS it has to be a static library.
  • You don’t want to ‘rearrange’ the archive content. You just want to refer the files you need. Using the archive ‘as is’ makes it easier to setup on several computers (you can check in your project along with the archive so anybody on your team can build it).
  • You want to have ‘unit tests’ handy so you can write tests while you’re learning how to use the library. I like to write tests to make sure I understand how the library works, and later the same tests can help me update to a newer version of the same library. Plus I find it much easier to write a few tests that output to the command line, rather than doing a big upfront integration with my software.
  • If you look at the sources it should become clear that you don’t need everything. I use AllBulletDemosOSX because it already contains references to most of the source files we need, so it saves time and effort (thanks to the bullet forums for the tip)

Is there a better way to do it?

I guess if you have the right make file or know how to create one and are willing to spend the time, maybe it would be better. Especially if it can automatically detect changes when you update to a more recent version of the library.

A few caveats

  • To rename a project, you can use the project navigator or the file inspector. You can rename a project the same way you rename a file in your xcode workspace and xcode will try to help you rename various entries. It’s easier than renaming the *.xcodeproj file yourself.
  • You may need help to setup unit tests. If you’ve never done it please consider doing it as it’s well worth it and there are good articles about this lying around.

This is a rough introduction to the Bullet physics engine.

I keep this article for reference. If you want a clean setup for building bullet as an iOS ready static library, please check this post.

You’re crying out for a physics engine. You wanna make one of these gimmicky, fashionable and ever profitable physics puzzlers, right?

If it’s a 2D engine you’re after, try Box 2D (<= links to a pocket gamer article!), it’s free, worth millions to some.

I sweated over my laptop 4 hours putting this together. It’s not so very difficult, but it’s summer and it’s HOT.

The bigger they come… (1.30 pm)

I decided to have a shot at building Bullet for a start.

Downloading the source isn’t a problem; the archive itself is… …varied. Lots of stuff at the root level, and a promising ‘src’ folder.

I approached the “build issue” (with a pig) head on. I made a new project in XCode, added all files from the src folder, and started building.

Don’t do this (use => this article instead.)

I removed many things that stood in the way:

  • “imbsdk”/ folders
  • make files

Then the build started bumping on #include “foo/bar/file.h” style commands. Makes sense, because adding all the files the way I did puts all files ‘at the same level’, so there’s no need for a ‘foo/bar/’ unless you expect a collision. I didn’t expect a file-space collision, and I was right. Yea, I moronically search-killed all foo/bar/ sections from all files.

There’s another couple of libs I didn’t like. The multi-threaded library trashed the build and doesn’t seem that promising just yet. There’s also the mini-cl thing. I dunno what that is except it uses the multithreaded lib headers, so I unchecked a couple more files from that mini-cl thingy.

Yay. I built bullet, I haven’t read the docs or anything yet. I don’t even know if the build is any use to nothing since I trashed stuff on my way. But hey, it’s building, right?

Surgery time: ~35 minutes

Examples, any? (2.45 pm)

I searched for sample code in the archive. Maybe what I was looking for was a quick ‘falling ball world’ with stdout logs to explain what’s going on. I know it’s unpretty but it does away with the need to show things and I didn’t expect GL-ES ready code in the demos either.

Then I found:

  • The Bullet user manual [link now fixed]
  • Their hello world tutorial.
    (please have a look, the remainder of this article is about getting this example to compile and run in an Objective C environment).
  • This (although ‘it’ may be out of date).

They do have an article showing how to include Bullet in an MacOS-X project. It looks like it would take no more than 10 minutes. I skip-read that it causes a framework to be generated. I may be wrong, but I don’t think we can include any framework other than what ships directly with iOS devices. We need static libraries, right?

Clock ticking (3.45)

I did nothing impressive in the past hour. I pasted the example from that hello world tutorial (link, above) in a char testBullet() function. I put that in a *.cpp file, not just wishfully but because the includes won’t compile as C (well, it is C++ code – and by the way that didn’t work, see below… ).

Surely I made a sample project to contain this stuff. Any project template will do, just for a test. So I created a project, pasted the code in test_bullet.cpp which contained this char testIt() method (don’t google these names, follow the link to the tutorial instead).

Calling this cpp code from an objective C class caused a linkage error, leading to a shocking discovery.

Interlude

I like the hello balls or watchamacallit example A LOT. Because it has this line in it:

std::cout << “sphere height: “ << trans.getOrigin().getY() << std::endl;

For whatever obscure reason this great classic glitched my build. So I substituted a greater classic:

printf(“sphere height: %f\n”,trans.getOrigin().getY());

Overall the test didn’t go too well, expect it worked (ha!).

I muddled endlessly over the “btBulletDynamicsCommon.h” include. This includes this, this and that, and cutting and pasting the include folders into Build Settings > User Header Search Paths takes AGES (If you now a better way, absolutely please leave a comment after this post)

The shocking discovery

I started considering mournfully how I don’t really know how to bridge C++ and Objective C. Then I found a doc claiming that…

you can dump whatever C++ you want in an Objective C file as long as you substitute .mm to .m

Not believing it one bit, I renamed my .cpp file to .mm; wrapped my test code as a class function, like this:

#include “TestBullet.h”

#include <stdio.h>

#include “btBulletDynamicsCommon.h”

@implementation TestBullet

+(BOOL)test{

// Welcome to C++land.

// Paste here sample code found at the bottom of that page.

// …

// … what are you waiting for?

}

@end

Supernaturally, this compiles without twisting a nail.

Understanding is nothing (4.42pm)

The world is unfair. I picked bullet first because of all the hype surrounding it (July 2011).  I’m sure there are many decent physics engines out there, but that is that.

Other than producing a nasty project file that can build the library, I know nothing about Bullet physics. Feels good, in a kind of way.

Looking at the fine print below – a mantra much simpler than the sample code – there’s a couple of things we can infer:

  • There is a ball. Likely, a solid thing. That’s a bit cheated from the console output but let’s believe it.
  • There is gravity. Gravity’s good.
  • There is a ground abstraction. Ground is good.
  • No input file or likewise cheat. Everything is setup programatically.

Their sample code is 65 lines long. Didn’t expect anything better (sigh). For better and for worse, the tutorial explains this step by step. Maybe I’ll understand if I set a few hours aside to read it.

Attaching to process 2589.

sphere height: 49.997223
sphere height: 49.991669
sphere height: 49.983334
sphere height: 49.972221
sphere height: 49.958332
sphere height: 49.941666
sphere height: 49.922222
sphere height: 49.900002
sphere height: 49.875000
sphere height: 49.847221
sphere height: 49.816666
sphere height: 49.783333
sphere height: 49.747223
sphere height: 49.708336
sphere height: 49.666668
sphere height: 49.622223
sphere height: 49.575001
sphere height: 49.525002
sphere height: 49.472225
sphere height: 49.416668
sphere height: 49.358334
sphere height: 49.297222
sphere height: 49.233334
sphere height: 49.166668
sphere height: 49.097225
sphere height: 49.025002
sphere height: 48.950001
sphere height: 48.872223
sphere height: 48.791668
sphere height: 48.708336
sphere height: 48.622223
sphere height: 48.533333
sphere height: 48.441666
sphere height: 48.347221
sphere height: 48.250000
sphere height: 48.150002
sphere height: 48.047222
sphere height: 47.941666
sphere height: 47.833332
sphere height: 47.722221
sphere height: 47.608334
sphere height: 47.491669
sphere height: 47.372223
sphere height: 47.250000
sphere height: 47.125000
sphere height: 46.997223
sphere height: 46.866669
sphere height: 46.733334
sphere height: 46.597221
sphere height: 46.458332
sphere height: 46.316666
sphere height: 46.172222
sphere height: 46.025002
sphere height: 45.875000
sphere height: 45.722221
sphere height: 45.566666
sphere height: 45.408333
sphere height: 45.247223
sphere height: 45.083336
sphere height: 44.916668
sphere height: 44.747223
sphere height: 44.575001
sphere height: 44.400002
sphere height: 44.222225
sphere height: 44.041668
sphere height: 43.858334
sphere height: 43.672222
sphere height: 43.483334
sphere height: 43.291668
sphere height: 43.097225
sphere height: 42.900002
sphere height: 42.700001
sphere height: 42.497223
sphere height: 42.291668
sphere height: 42.083336
sphere height: 41.872223
sphere height: 41.658333
sphere height: 41.441666
sphere height: 41.222221
sphere height: 41.000000
sphere height: 40.775002
sphere height: 40.547222
sphere height: 40.316666
sphere height: 40.083332
sphere height: 39.847221
sphere height: 39.608334
sphere height: 39.366665
sphere height: 39.122219
sphere height: 38.874996
sphere height: 38.624996
sphere height: 38.372219
sphere height: 38.116665
sphere height: 37.858330
sphere height: 37.597218
sphere height: 37.333328
sphere height: 37.066662
sphere height: 36.797218
sphere height: 36.524998
sphere height: 36.249996
sphere height: 35.972218
sphere height: 35.691662
sphere height: 35.408329
sphere height: 35.122219
sphere height: 34.833328
sphere height: 34.541660
sphere height: 34.247215
sphere height: 33.949993
sphere height: 33.649994
sphere height: 33.347218
sphere height: 33.041660
sphere height: 32.733326
sphere height: 32.422215
sphere height: 32.108326
sphere height: 31.791658
sphere height: 31.472214
sphere height: 31.149992
sphere height: 30.824991
sphere height: 30.497213
sphere height: 30.166658
sphere height: 29.833324
sphere height: 29.497213
sphere height: 29.158325
sphere height: 28.816658
sphere height: 28.472214
sphere height: 28.124992
sphere height: 27.774992
sphere height: 27.422215
sphere height: 27.066660
sphere height: 26.708326
sphere height: 26.347216
sphere height: 25.983326
sphere height: 25.616659
sphere height: 25.247215
sphere height: 24.874992
sphere height: 24.499992
sphere height: 24.122215
sphere height: 23.741659
sphere height: 23.358326
sphere height: 22.972216
sphere height: 22.583326
sphere height: 22.191660
sphere height: 21.797216
sphere height: 21.399994
sphere height: 20.999994
sphere height: 20.597218
sphere height: 20.191662
sphere height: 19.783329
sphere height: 19.372219
sphere height: 18.958330
sphere height: 18.541664
sphere height: 18.122219
sphere height: 17.699997
sphere height: 17.274998
sphere height: 16.847219
sphere height: 16.416664
sphere height: 15.983332
sphere height: 15.547221
sphere height: 15.108333
sphere height: 14.666666
sphere height: 14.222222
sphere height: 13.775001
sphere height: 13.325001
sphere height: 12.872224
sphere height: 12.416669
sphere height: 11.958336
sphere height: 11.497225
sphere height: 11.033337
sphere height: 10.566670
sphere height: 10.097226
sphere height: 9.625005
sphere height: 9.150005
sphere height: 8.672228
sphere height: 8.191673
sphere height: 7.708341
sphere height: 7.222230
sphere height: 6.733342
sphere height: 6.241676
sphere height: 5.747232
sphere height: 5.250010
sphere height: 4.750011
sphere height: 4.247234
sphere height: 3.741679
sphere height: 3.233346
sphere height: 2.722236
sphere height: 2.208348
sphere height: 1.691682
sphere height: 1.172238
sphere height: 0.650017
sphere height: 0.720013
sphere height: 0.787232
sphere height: 0.851673
sphere height: 0.913337
sphere height: 0.972222
sphere height: 1.028330
sphere height: 1.081660
sphere height: 1.132212
sphere height: 1.179986
sphere height: 1.224983
sphere height: 1.267202
sphere height: 1.306643
sphere height: 1.343306
sphere height: 1.377192
sphere height: 1.408299
sphere height: 1.436629
sphere height: 1.462181
sphere height: 1.484956
sphere height: 1.504952
sphere height: 1.522171
sphere height: 1.536612
sphere height: 1.548276
sphere height: 1.557161
sphere height: 1.563269
sphere height: 1.566599
sphere height: 1.567151
sphere height: 1.564925
sphere height: 1.559922
sphere height: 1.552141
sphere height: 1.541582
sphere height: 1.528245
sphere height: 1.512130
sphere height: 1.493238
sphere height: 1.471568
sphere height: 1.447120
sphere height: 1.419895
sphere height: 1.389891
sphere height: 1.357110
sphere height: 1.321551
sphere height: 1.283214
sphere height: 1.242100
sphere height: 1.198208
sphere height: 1.151538
sphere height: 1.102090
sphere height: 1.049864
sphere height: 0.994861
sphere height: 0.995889
sphere height: 0.996711
sphere height: 0.997369
sphere height: 0.997895
sphere height: 0.998316
sphere height: 0.998653
sphere height: 0.998922
sphere height: 0.999138
sphere height: 0.999310
sphere height: 0.999448
sphere height: 0.999559
sphere height: 0.999647
sphere height: 0.999717
sphere height: 0.999774
sphere height: 0.999819
sphere height: 0.999855
sphere height: 0.999884
sphere height: 0.999907
sphere height: 0.999926
sphere height: 0.999941
sphere height: 0.999953
sphere height: 0.999962
sphere height: 0.999970
sphere height: 0.999976
sphere height: 0.999981
sphere height: 0.999984
sphere height: 0.999988
sphere height: 0.999990
sphere height: 0.999992
sphere height: 0.999994
sphere height: 0.999995
sphere height: 0.999996
sphere height: 0.999997
sphere height: 0.999997
sphere height: 0.999998
sphere height: 0.999998
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 0.999999
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000
sphere height: 1.000000