예제 #1
0
        public virtual void Rotate(IndexedQuaternion iq)
        {
            IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(iq);

            im._origin = m_graphicsWorldTrans._origin;
            SetWorldTransform(ref im);
        }
예제 #2
0
        public override void ClientMoveAndDisplay(GameTime gameTime)
        {
            // OPTIONAL: We simply move our ghost objects around (without rotating them.....)==============
            if (m_ghostObject != null || m_pairCachingGhostObject != null)
            {
                rad += 0.005f;    // Bad (depends on PC speed)
                float sinRad = (float)Math.Sin(rad);
                float cosRad = (float)Math.Cos(rad);
                if (m_ghostObject != null)
                {
                    IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y);
                    im._origin = new IndexedVector3(15 * cosRad, 5, -15 * sinRad);
                    m_ghostObject.SetWorldTransform(ref im);
                }
                if (m_pairCachingGhostObject != null)
                {
                    IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y);
                    im._origin = new IndexedVector3(-15 * cosRad, 7, 15 * sinRad);
                    m_pairCachingGhostObject.SetWorldTransform(ref im);
                }
            }



            base.ClientMoveAndDisplay(gameTime);
            // NEW => Retrives the content from all ghost objects in the world and call ProcessObectsInsideGhostObjects(...) for each ====
            if (m_dynamicsWorld != null)
            {
                ObjectArray <CollisionObject> objsInsidePairCachingGhostObject = new ObjectArray <CollisionObject>(); // We might want this to be a member variable...
                ObjectArray <CollisionObject> pObjsInsideGhostObject           = null;                                // We will store a reference of the current array in this pointer
                ObjectArray <CollisionObject> objs = m_dynamicsWorld.GetCollisionObjectArray();
                for (int i = 0, sz = objs.Count; i < sz; i++)
                {
                    CollisionObject o  = objs[i];
                    GhostObject     go = GhostObject.Upcast(o);
                    if (go != null)
                    {
                        objsInsidePairCachingGhostObject.Resize(0);
                        PairCachingGhostObject pgo = go as PairCachingGhostObject;                      // No upcast functionality...
                        if (pgo != null)
                        {
                            GetCollidingObjectsInsidePairCachingGhostObject((DiscreteDynamicsWorld)m_dynamicsWorld, pgo, objsInsidePairCachingGhostObject);
                            pObjsInsideGhostObject = objsInsidePairCachingGhostObject;
                        }
                        else
                        {
                            pObjsInsideGhostObject = go.GetOverlappingPairs();                          // It's better not to try and copy the whole array, but to keep a reference to it!
                            // Side Note: btAlignedObjectArray < btCollisionObject* > objs = go.getOverlappingPairs(); (at the moment) makes my program crash on my system...
                            // Nevermind, that was the wrong way of doing it: btAlignedObjectArray < btCollisionObject* >& objs = go.getOverlappingPairs(); is much better.
                        }
                        // Here pObjsInsideGhostObject should be valid.

                        ProcessObectsInsideGhostObjects(pObjsInsideGhostObject, pgo != null);
                    }
                }
            }
        }
예제 #3
0
        //
        public float SignedDistance(ref IndexedVector3 position, float margin, ConvexShape shape0, ref IndexedMatrix wtrs0, ref GjkEpaSolver2Results results)
        {
            using (GjkEpaSolver2MinkowskiDiff shape = BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.Get())
                using (GJK gjk = BulletGlobals.GJKPool.Get())
                {
                    SphereShape shape1 = BulletGlobals.SphereShapePool.Get();
                    shape1.Initialize(margin);
                    IndexedMatrix wtrs1 = IndexedMatrix.CreateFromQuaternion(IndexedQuaternion.Identity);
                    wtrs0._origin = position;

                    Initialize(shape0, ref wtrs0, shape1, ref wtrs1, ref results, shape, false);
                    gjk.Initialise();
                    IndexedVector3 guess      = new IndexedVector3(1);
                    GJKStatus      gjk_status = gjk.Evaluate(shape, ref guess);
                    if (gjk_status == GJKStatus.Valid)
                    {
                        IndexedVector3 w0 = IndexedVector3.Zero;
                        IndexedVector3 w1 = IndexedVector3.Zero;
                        for (int i = 0; i < gjk.m_simplex.rank; ++i)
                        {
                            float p = gjk.m_simplex.p[i];
                            w0 += shape.Support(ref gjk.m_simplex.c[i].d, 0) * p;
                            IndexedVector3 temp = -gjk.m_simplex.c[i].d;
                            w1 += shape.Support(ref temp, 1) * p;
                        }
                        results.witnesses0 = wtrs0 * w0;
                        results.witnesses1 = wtrs0 * w1;
                        IndexedVector3 delta   = results.witnesses1 - results.witnesses0;
                        float          margin2 = shape0.GetMarginNonVirtual() + shape1.GetMarginNonVirtual();
                        float          length  = delta.Length();
                        results.normal      = delta / length;
                        results.witnesses0 += results.normal * margin2;
                        return(length - margin2);
                    }
                    else
                    {
                        if (gjk_status == GJKStatus.Inside)
                        {
                            if (Penetration(shape0, ref wtrs0, shape1, ref wtrs1, ref gjk.m_ray, ref results))
                            {
                                IndexedVector3 delta  = results.witnesses0 - results.witnesses1;
                                float          length = delta.Length();
                                if (length >= MathUtil.SIMD_EPSILON)
                                {
                                    results.normal = delta / length;
                                }
                                return(-length);
                            }
                        }
                    }
                    BulletGlobals.SphereShapePool.Free(shape1);
                }
            return(MathUtil.SIMD_INFINITY);
        }
예제 #4
0
	    public static void IntegrateTransform(ref IndexedMatrix curTrans,ref IndexedVector3 linvel,ref IndexedVector3 angvel,float timeStep,out IndexedMatrix predictedTransform)
	    {
            predictedTransform = IndexedMatrix.CreateTranslation(curTrans._origin + linvel * timeStep);
    //	#define QUATERNION_DERIVATIVE
	    #if QUATERNION_DERIVATIVE
            IndexedVector3 pos;
            IndexedQuaternion predictedOrn;
            IndexedVector3 scale;

            curTrans.Decompose(ref scale, ref predictedOrn, ref pos);


		    predictedOrn += (angvel * predictedOrn) * (timeStep * .5f));
		    predictedOrn.Normalize();
        #else
            //Exponential map
		    //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia

		    IndexedVector3 axis;
		    float	fAngle = angvel.Length(); 
		    //limit the angular motion
		    if (fAngle*timeStep > ANGULAR_MOTION_THRESHOLD)
		    {
			    fAngle = ANGULAR_MOTION_THRESHOLD / timeStep;
		    }

		    if ( fAngle < 0.001f )
		    {
			    // use Taylor's expansions of sync function
			    axis   = angvel*( 0.5f*timeStep-(timeStep*timeStep*timeStep)*(0.020833333333f)*fAngle*fAngle );
		    }
		    else
		    {
			    // sync(fAngle) = sin(c*fAngle)/t
			    axis   = angvel*( (float)Math.Sin(0.5f*fAngle*timeStep)/fAngle );
		    }
		    IndexedQuaternion dorn = new IndexedQuaternion(axis.X,axis.Y,axis.Z,(float)Math.Cos( fAngle*timeStep*.5f) );

            IndexedQuaternion orn0 = curTrans.GetRotation();

		    IndexedQuaternion predictedOrn = dorn * orn0;
		    predictedOrn.Normalize();
	    #endif

            IndexedMatrix newMatrix = IndexedMatrix.CreateFromQuaternion(predictedOrn);
            predictedTransform._basis = newMatrix._basis;
	    }
        //  min_y = -1000, max_y = 10
        public btRaycastBar(IDebugDraw debugDraw, float ray_length, float z, float min_y, float max_y, float minX, float maxX)
        {
            m_debugDraw    = debugDraw;
            frame_counter  = 0;
            ms             = 0;
            max_ms         = 0;
            min_ms         = 9999;
            sum_ms_samples = 0;
            sum_ms         = 0;
            dx             = 10.0f;
            //min_x = -20;
            //max_x = 20;
            this.min_x = minX;
            this.max_x = maxX;

            float startX = (minX + maxX) / 2;

            this.min_y = min_y;
            this.max_y = max_y;
            sign       = 1.0f;
            float dalpha = MathUtil.SIMD_2_PI / NUMRAYS_IN_BAR;

            for (int i = 0; i < NUMRAYS_IN_BAR; i++)
            {
                float alpha = dalpha * i;
                // rotate around by alpha degrees y
                IndexedMatrix tr = IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(Vector3.Up, alpha));
                direction[i] = new IndexedVector3(1.0f, 0.0f, 0.0f);
                direction[i] = tr * direction[i];
                direction[i] = direction[i] * ray_length;
                source[i]    = new IndexedVector3(startX, max_y, z);
                dest[i]      = source[i] + direction[i];
                dest[i].Y    = min_y;
                normal[i]    = new IndexedVector3(1.0f, 0.0f, 0.0f);
            }
        }
예제 #6
0
            public virtual void ProcessTriangle(IndexedVector3[] triangle, int partId, int triangleIndex)
            {
                //skip self-collisions
                if ((m_partIdA == partId) && (m_triangleIndexA == triangleIndex))
                {
                    return;
                }

                //skip duplicates (disabled for now)
                //if ((m_partIdA <= partId) && (m_triangleIndexA <= triangleIndex))
                //	return;

                //search for shared vertices and edges
                int numshared = 0;

                int[] sharedVertsA = new int[] { -1, -1, -1 };
                int[] sharedVertsB = new int[] { -1, -1, -1 };

                ///skip degenerate triangles
                float crossBSqr = IndexedVector3.Cross((triangle[1] - triangle[0]), (triangle[2] - triangle[0])).LengthSquared();

                if (crossBSqr < m_triangleInfoMap.m_equalVertexThreshold)
                {
                    return;
                }

                float crossASqr = IndexedVector3.Cross((m_triangleVerticesA[1] - m_triangleVerticesA[0]), (m_triangleVerticesA[2] - m_triangleVerticesA[0])).LengthSquared();

                ///skip degenerate triangles
                if (crossASqr < m_triangleInfoMap.m_equalVertexThreshold)
                {
                    return;
                }

#if false
                printf("triangle A[0]	=	(%f,%f,%f)\ntriangle A[1]	=	(%f,%f,%f)\ntriangle A[2]	=	(%f,%f,%f)\n",
                       m_triangleVerticesA[0].GetX(), m_triangleVerticesA[0].GetY(), m_triangleVerticesA[0].GetZ(),
                       m_triangleVerticesA[1].GetX(), m_triangleVerticesA[1].GetY(), m_triangleVerticesA[1].GetZ(),
                       m_triangleVerticesA[2].GetX(), m_triangleVerticesA[2].GetY(), m_triangleVerticesA[2].GetZ());

                printf("partId=%d, triangleIndex=%d\n", partId, triangleIndex);
                printf("triangle B[0]	=	(%f,%f,%f)\ntriangle B[1]	=	(%f,%f,%f)\ntriangle B[2]	=	(%f,%f,%f)\n",
                       triangle[0].GetX(), triangle[0].GetY(), triangle[0].GetZ(),
                       triangle[1].GetX(), triangle[1].GetY(), triangle[1].GetZ(),
                       triangle[2].GetX(), triangle[2].GetY(), triangle[2].GetZ());
#endif

                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        if ((m_triangleVerticesA[i] - triangle[j]).LengthSquared() < m_triangleInfoMap.m_equalVertexThreshold)
                        {
                            sharedVertsA[numshared] = i;
                            sharedVertsB[numshared] = j;
                            numshared++;
                            ///degenerate case
                            if (numshared >= 3)
                            {
                                return;
                            }
                        }
                    }
                    ///degenerate case
                    if (numshared >= 3)
                    {
                        return;
                    }
                }
                switch (numshared)
                {
                case 0:
                {
                    break;
                }

                case 1:
                {
                    //shared vertex
                    break;
                }

                case 2:
                {
                    //shared edge
                    //we need to make sure the edge is in the order V2V0 and not V0V2 so that the signs are correct
                    if (sharedVertsA[0] == 0 && sharedVertsA[1] == 2)
                    {
                        sharedVertsA[0] = 2;
                        sharedVertsA[1] = 0;
                        int tmp = sharedVertsB[1];
                        sharedVertsB[1] = sharedVertsB[0];
                        sharedVertsB[0] = tmp;
                    }

                    int hash = GetHash(m_partIdA, m_triangleIndexA);


                    TriangleInfo info = null;
                    if (m_triangleInfoMap.ContainsKey(hash))
                    {
                        info = m_triangleInfoMap[hash];
                    }
                    else
                    {
                        info = new TriangleInfo();
                        m_triangleInfoMap[hash] = info;
                    }

                    int sumvertsA   = sharedVertsA[0] + sharedVertsA[1];
                    int otherIndexA = 3 - sumvertsA;


                    IndexedVector3 edge = new IndexedVector3(m_triangleVerticesA[sharedVertsA[1]] - m_triangleVerticesA[sharedVertsA[0]]);

                    TriangleShape tA          = new TriangleShape(m_triangleVerticesA[0], m_triangleVerticesA[1], m_triangleVerticesA[2]);
                    int           otherIndexB = 3 - (sharedVertsB[0] + sharedVertsB[1]);

                    TriangleShape tB = new TriangleShape(triangle[sharedVertsB[1]], triangle[sharedVertsB[0]], triangle[otherIndexB]);
                    //btTriangleShape tB(triangle[0],triangle[1],triangle[2]);

                    IndexedVector3 normalA;
                    IndexedVector3 normalB;
                    tA.CalcNormal(out normalA);
                    tB.CalcNormal(out normalB);
                    edge.Normalize();
                    IndexedVector3 edgeCrossA = IndexedVector3.Normalize(IndexedVector3.Cross(edge, normalA));

                    {
                        IndexedVector3 tmp = m_triangleVerticesA[otherIndexA] - m_triangleVerticesA[sharedVertsA[0]];
                        if (IndexedVector3.Dot(edgeCrossA, tmp) < 0)
                        {
                            edgeCrossA *= -1;
                        }
                    }

                    IndexedVector3 edgeCrossB = IndexedVector3.Cross(edge, normalB).Normalized();

                    {
                        IndexedVector3 tmp = triangle[otherIndexB] - triangle[sharedVertsB[0]];
                        if (IndexedVector3.Dot(edgeCrossB, tmp) < 0)
                        {
                            edgeCrossB *= -1;
                        }
                    }

                    float angle2 = 0;
                    float ang4   = 0.0f;

                    IndexedVector3 calculatedEdge = IndexedVector3.Cross(edgeCrossA, edgeCrossB);
                    float          len2           = calculatedEdge.LengthSquared();

                    float          correctedAngle    = 0f;
                    IndexedVector3 calculatedNormalB = normalA;
                    bool           isConvex          = false;

                    if (len2 < m_triangleInfoMap.m_planarEpsilon)
                    {
                        angle2 = 0.0f;
                        ang4   = 0.0f;
                    }
                    else
                    {
                        calculatedEdge.Normalize();
                        IndexedVector3 calculatedNormalA = IndexedVector3.Cross(calculatedEdge, edgeCrossA);
                        calculatedNormalA.Normalize();
                        angle2 = GetAngle(ref calculatedNormalA, ref edgeCrossA, ref edgeCrossB);
                        ang4   = MathUtil.SIMD_PI - angle2;
                        float dotA = IndexedVector3.Dot(normalA, edgeCrossB);
                        ///@todo: check if we need some epsilon, due to floating point imprecision
                        isConvex = (dotA < 0f);

                        correctedAngle = isConvex ? ang4 : -ang4;
                        IndexedQuaternion orn2         = new IndexedQuaternion(calculatedEdge, -correctedAngle);
                        IndexedMatrix     rotateMatrix = IndexedMatrix.CreateFromQuaternion(orn2);
                        calculatedNormalB = new IndexedBasisMatrix(orn2) * normalA;
                    }


                    //alternatively use
                    //IndexedVector3 calculatedNormalB2 = quatRotate(orn,normalA);


                    switch (sumvertsA)
                    {
                    case 1:
                    {
                        IndexedVector3    edge1           = m_triangleVerticesA[0] - m_triangleVerticesA[1];
                        IndexedQuaternion orn             = new IndexedQuaternion(edge1, -correctedAngle);
                        IndexedVector3    computedNormalB = MathUtil.QuatRotate(orn, normalA);
                        float             bla             = IndexedVector3.Dot(computedNormalB, normalB);
                        if (bla < 0)
                        {
                            computedNormalB *= -1;
                            info.m_flags    |= TriangleInfoMap.TRI_INFO_V0V1_SWAP_NORMALB;
                        }
#if DEBUG_INTERNAL_EDGE
                        if ((computedNormalB - normalB).Length() > 0.0001f)
                        {
                            System.Console.WriteLine("warning: normals not identical");
                        }
#endif//DEBUG_INTERNAL_EDGE

                        info.m_edgeV0V1Angle = -correctedAngle;

                        if (isConvex)
                        {
                            info.m_flags |= TriangleInfoMap.TRI_INFO_V0V1_CONVEX;
                        }
                        break;
                    }

                    case 2:
                    {
                        IndexedVector3    edge1           = m_triangleVerticesA[2] - m_triangleVerticesA[0];
                        IndexedQuaternion orn             = new IndexedQuaternion(edge1, -correctedAngle);
                        IndexedVector3    computedNormalB = MathUtil.QuatRotate(orn, normalA);
                        if (IndexedVector3.Dot(computedNormalB, normalB) < 0)
                        {
                            computedNormalB *= -1;
                            info.m_flags    |= TriangleInfoMap.TRI_INFO_V2V0_SWAP_NORMALB;
                        }

#if DEBUG_INTERNAL_EDGE
                        if ((computedNormalB - normalB).Length() > 0.0001)
                        {
                            System.Console.WriteLine("warning: normals not identical");
                        }
#endif //DEBUG_INTERNAL_EDGE
                        info.m_edgeV2V0Angle = -correctedAngle;
                        if (isConvex)
                        {
                            info.m_flags |= TriangleInfoMap.TRI_INFO_V2V0_CONVEX;
                        }
                        break;
                    }

                    case 3:
                    {
                        IndexedVector3    edge1           = m_triangleVerticesA[1] - m_triangleVerticesA[2];
                        IndexedQuaternion orn             = new IndexedQuaternion(edge1, -correctedAngle);
                        IndexedVector3    computedNormalB = MathUtil.QuatRotate(orn, normalA);
                        if (IndexedVector3.Dot(computedNormalB, normalB) < 0)
                        {
                            info.m_flags    |= TriangleInfoMap.TRI_INFO_V1V2_SWAP_NORMALB;
                            computedNormalB *= -1;
                        }
#if DEBUG_INTERNAL_EDGE
                        if ((computedNormalB - normalB).Length() > 0.0001)
                        {
                            System.Console.WriteLine("warning: normals not identical");
                        }
#endif //DEBUG_INTERNAL_EDGE
                        info.m_edgeV1V2Angle = -correctedAngle;

                        if (isConvex)
                        {
                            info.m_flags |= TriangleInfoMap.TRI_INFO_V1V2_CONVEX;
                        }
                        break;
                    }
                    }

                    break;
                }

                default:
                {
                    //				printf("warning: duplicate triangle\n");
                    break;
                }
                }
            }
예제 #7
0
        protected override void Initialize()
        {
            base.Initialize();
            SetCameraDistance(50.0f);

            ///collision configuration contains default setup for memory, collision setup
            m_collisionConfiguration = new DefaultCollisionConfiguration();
            //m_collisionConfiguration.setConvexConvexMultipointIterations();

            ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
            m_dispatcher = new CollisionDispatcher(m_collisionConfiguration);

            m_broadphase = new DbvtBroadphase();

            ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
            m_constraintSolver = new SequentialImpulseConstraintSolver();

            m_dynamicsWorld = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_constraintSolver, m_collisionConfiguration);

            IndexedVector3 gravity = new IndexedVector3(0, -10, 0);

            m_dynamicsWorld.SetGravity(ref gravity);


            // NEW => btGhostPairCallback =================================
            m_ghostPairCallback = new GhostPairCallback();
            m_dynamicsWorld.GetBroadphase().GetOverlappingPairCache().SetInternalGhostPairCallback(m_ghostPairCallback);        // Needed once to enable ghost objects inside Bullet

            // NEW => btGhostObject =======================================
            m_ghostObject = new GhostObject();
            CollisionShape shape = new BoxShape(new IndexedVector3(5f));        // As far as I know only the world aabb of the shape will be used (i.e. a box always parallel to the x,y,z axis of variable size)

            m_collisionShapes.Add(shape);
            m_ghostObject.SetCollisionShape(shape);
            m_ghostObject.SetCollisionFlags(CollisionFlags.CF_NO_CONTACT_RESPONSE);             // We can choose to make it "solid" if we want...
            m_dynamicsWorld.AddCollisionObject(m_ghostObject, CollisionFilterGroups.SensorTrigger, CollisionFilterGroups.AllFilter & ~CollisionFilterGroups.SensorTrigger);
            //m_ghostObject.setWorldTransform(btTransform(btQuaternion::getIdentity(),btVector3(0,5,-15)));
            IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y);

            im._origin = new IndexedVector3(0, 5, -15);
            m_ghostObject.SetWorldTransform(im);

            // NEW => btPairCachingGhostObject ============================
            m_pairCachingGhostObject = new PairCachingGhostObject();
            shape = new ConeShape(7.0f, 14.0f);
            m_collisionShapes.Add(shape);
            m_pairCachingGhostObject.SetCollisionShape(shape);
            m_pairCachingGhostObject.SetCollisionFlags(CollisionFlags.CF_NO_CONTACT_RESPONSE);  // We can choose to make it "solid" if we want...
            m_dynamicsWorld.AddCollisionObject(m_pairCachingGhostObject, CollisionFilterGroups.SensorTrigger, CollisionFilterGroups.AllFilter & ~CollisionFilterGroups.SensorTrigger);
            //m_pairCachingGhostObject.setWorldTransform(btTransform(btQuaternion::getIdentity(),btVector3(0,5,15)));
            im._origin = new IndexedVector3(0, 7, 15);
            m_pairCachingGhostObject.SetWorldTransform(im);
            //=============================================================

            ///create a few basic rigid bodies
            CollisionShape groundShape = new BoxShape(new IndexedVector3(50));

            m_collisionShapes.Add(groundShape);

            IndexedMatrix groundTransform = IndexedMatrix.Identity;

            groundTransform._origin = new IndexedVector3(0, -50, 0);

            float mass = 0.0f;

            LocalCreateRigidBody(mass, groundTransform, groundShape);

            // spawn some cubes (code pasted from appBasicDemo...)
            if (true)
            {
                //create a few dynamic rigidbodies
                CollisionShape colShape = new BoxShape(new IndexedVector3(SCALING, SCALING, SCALING));
                //btCollisionShape* colShape = new btSphereShape(btScalar(1.));
                //CollisionShape colShape = new CylinderShape(new IndexedVector3(1f, 1, 1f));
                m_collisionShapes.Add(colShape);

                /// Create Dynamic Objects
                IndexedMatrix startTransform = IndexedMatrix.Identity;

                mass = 1f;

                //rigidbody is dynamic if and only if mass is non zero, otherwise static
                bool isDynamic = mass != 0f;

                IndexedVector3 localInertia = IndexedVector3.Zero;
                if (isDynamic)
                {
                    colShape.CalculateLocalInertia(mass, out localInertia);
                }
                float start_x = START_POS_X - ARRAY_SIZE_X / 2;
                float start_y = START_POS_Y;
                float start_z = START_POS_Z - ARRAY_SIZE_Z / 2;

                for (int k = 0; k < ARRAY_SIZE_Y; k++)
                {
                    for (int i = 0; i < ARRAY_SIZE_X; i++)
                    {
                        for (int j = 0; j < ARRAY_SIZE_Z; j++)
                        {
                            startTransform._origin = (new IndexedVector3(2.0f * i + start_x, 20 + 2.0f * k + start_y, 2.0f * j + start_z) * SCALING);

                            //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
                            DefaultMotionState        myMotionState = new DefaultMotionState(startTransform, IndexedMatrix.Identity);
                            RigidBodyConstructionInfo rbInfo        = new RigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
                            RigidBody body = new RigidBody(rbInfo);
                            //body.setContactProcessingThreshold(colShape.getContactBreakingThreshold());
                            body.SetActivationState(ActivationState.ISLAND_SLEEPING);

                            m_dynamicsWorld.AddRigidBody(body);
                            body.SetActivationState(ActivationState.ISLAND_SLEEPING);
                            body.SetUserPointer(String.Format("Box X{0} Y{1} Z{2}", k, i, j));
                        }
                    }
                }
            }

            ClientResetScene();
        }