How to load Spatial casted as Geometry

I am creating a vehicle. I am to add wheels to a spatial with vehicle control. Here is my code for this method:

bulletAppState = new BulletAppState();
        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        stateManager.attach(bulletAppState);
        terrain.setSupportMultipleCollisions(true); 
        terrain.addControl(new RigidBodyControl(0));
        bulletAppState.getPhysicsSpace().addAll(terrain);
        spaceShipShape = new CompoundCollisionShape();
        spaceship.addControl(new RigidBodyControl(0));
        bulletAppState.getPhysicsSpace().add(spaceship);
        playerCapsule = new CapsuleCollisionShape(1.5f, 15f, 1);
        character = new CharacterControl(playerCapsule, 0.2f);
        character.setJumpSpeed(20);
        character.setFallSpeed(50);
        character.setGravity(new Vector3f(0,-40f,0));
        character.setLinearVelocity(new Vector3f(400, 0, 400));
        character.setPhysicsLocation(new Vector3f(-30f, 100f, -101f)); 
        bulletAppState.getPhysicsSpace().add(character);
        float stiffness = 120.0f;//200=f1 car
        float compValue = 0.2f; //(lower than damp!)
        float dampValue = 0.3f;
        final float mass = 400;

        //Load model and get chassis Geometry
        Node carNode = (Node)assetManager.loadModel("Models/Ferrari/Car.scene");
        
        Geometry chasis = findGeom(carNode, "Car");
        BoundingBox box = (BoundingBox) chasis.getModelBound();
        
        //Create a hull collision shape for the chassis
        CollisionShape carHull = CollisionShapeFactory.createDynamicMeshShape(chasis);

        //Create a vehicle control
        plane = new VehicleControl(carHull, mass);
        
        carNode.addControl(plane);

        //Setting default values for wheels
        plane.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
        plane.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
        plane.setSuspensionStiffness(stiffness);
        plane.setMaxSuspensionForce(10000);

        //Create four wheels and add them at their locations
        //note that our fancy car actually goes backwards..
        Vector3f wheelDirection = new Vector3f(0, -1, 0);
        Vector3f wheelAxle = new Vector3f(-1, 0, 0);

        Geometry wheel_fr = findGeom(carNode, "WheelFrontRight");
        wheel_fr.center();
        box = (BoundingBox) wheel_fr.getModelBound();
        float wheelRadius = box.getYExtent();
        float back_wheel_h = (wheelRadius * 1.7f) - 1f;
        float front_wheel_h = (wheelRadius * 1.9f) - 1f;
        plane.addWheel(wheel_fr.getParent(), box.getCenter().add(0, -front_wheel_h, 0),
                wheelDirection, wheelAxle, 0.2f, wheelRadius, true);

        Geometry wheel_fl = findGeom(carNode, "WheelFrontLeft");
        wheel_fl.center();
        box = (BoundingBox) wheel_fl.getModelBound();
        plane.addWheel(wheel_fl.getParent(), box.getCenter().add(0, -front_wheel_h, 0),
                wheelDirection, wheelAxle, 0.2f, wheelRadius, true);

        Geometry wheel_br = findGeom(carNode, "WheelBackRight");
        wheel_br.center();
        box = (BoundingBox) wheel_br.getModelBound();
        plane.addWheel(wheel_br.getParent(), box.getCenter().add(0, -back_wheel_h, 0),
                wheelDirection, wheelAxle, 0.2f, wheelRadius, false);

        Geometry wheel_bl = findGeom(carNode, "WheelBackLeft");
        wheel_bl.center();
        box = (BoundingBox) wheel_bl.getModelBound();
        plane.addWheel(wheel_bl.getParent(), box.getCenter().add(0, -back_wheel_h, 0),
                wheelDirection, wheelAxle, 0.2f, wheelRadius, false);

        plane.getWheel(2).setFrictionSlip(4);
        plane.getWheel(3).setFrictionSlip(4);

        rootNode.attachChild(carNode);
        carNode.scale(10f);
        bulletAppState.getPhysicsSpace().add(plane);

As you can see, alot of the code is the same as TestFancyCar.java, as I am trying to get a hang of the wheels/vehicle control.

However, I don’t want to use Car.scene – I have my own Spatial, that is loaded in w/ .obj, and I want to set the carNode to that. To do that, I need a Geometry chasis, and what I tried was (spaceship is my spatial):

1. Geometry chasis = (Geometry) spaceship;
2. Geometry chasis = (Geometry)((Node)spaceship).getChild("Spaceship"));

This didn’t work. I then tried setting my CollisionShape to:

   CollisionShape carHull = CollisionShapeFactory.createMeshShape(spaceship); // without doing any Geometry stuff

None of these work. I get “cannot cast Node to Geometry” even though I am casting a spatial to geometry, and the third one doesn’t work well. How can I load in my Spatial??? I’ve been staring at the javadoc but can’t find anything. Thank you for your help!

Try using a CompoundCollisionShape that can accumulate wheels to the car physics in a dynamic mesh shape not mesh shape:


CompoundCollisionShape compoundShape = (CompoundCollisionShape)CollisionShapeFactory.createDynamicMeshShape(chassis);

At the car node, create a new VehicleControl that’s a type of physically based Abstract control to control your car based on the CompoundCollisionShape that holds the chassis & the wheels, then add that control to the carNode :

VehicleControl vehicle = new VehicleControl(compoundShape, 600f);
            vehicleNode.addControl(vehicle);

600 is the mass of the car in kg…

Full example :

    public static class VehicleAutoShop{
        private Spatial chassis;
        private Node vehicleNode;
        private VehicleControl vehicle;

        public VehicleAutoShop(Spatial chassis){
            this.chassis=chassis;
        }

        public VehicleControl getVehicle() {
            return vehicle;
        }

        public Spatial getChassis() {
            return chassis;
        }

        public VehicleAutoShop initializeChassis(){
            //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0
            //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0
            //create vehicle node
            chassis.setLocalScale(2.2f,2.2f,2.2f);
            chassis.setLocalTranslation(new Vector3f(0, 1, 0));

            vehicleNode=new Node("vehicleNode");
            vehicleNode.attachChild(chassis);
            return this;
        }
        public VehicleAutoShop initializeCamera(){
            ChaseCamera chaseCam=new ChaseCamera(JmeGame.gameContext.getCamera(), vehicleNode);
            chaseCam.setDefaultDistance(-15f);
            chaseCam.registerWithInput(JmeGame.gameContext.getInputManager());
            chaseCam.setDragToRotate(true);
            return this;
        }
        public VehicleAutoShop initializeVehiclePhysics(){
            CompoundCollisionShape compoundShape = (CompoundCollisionShape)CollisionShapeFactory.createDynamicMeshShape(chassis);
            compoundShape.translate(new Vector3f(0,1,0));
            vehicle = new VehicleControl(compoundShape, 600f);
            vehicleNode.addControl(vehicle);

            return this;
        }
        public VehicleAutoShop initializePlayer(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, -458.60062f));
            return this;
        }
        public VehicleAutoShop initializeNPC(){
            vehicle.setPhysicsLocation(new Vector3f(0.2489425f, -9.613701f, 458.60062f));
            vehicle.setPhysicsRotation(new Quaternion().fromAngleAxis(FastMath.PI,Vector3f.UNIT_Y));
            return this;
        }
        public VehicleAutoShop loadWheels(){
            //Create four wheels and add them at their locations
            Vector3f wheelDirection = new Vector3f(0,-1F, 0); // was 0, -1, 0
            Vector3f wheelAxle = new Vector3f(-6, 0, 0); // was -1, 0, 0
            float radius = 0.5f;
            float restLength = 0.1f;
            float yOff = radius;
            float xOff = 4*radius;
            float zOff = 6.5f*radius;

            Material wheelsMat = new Material(JmeGame.gameContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
            wheelsMat.getAdditionalRenderState().setWireframe(false);
            wheelsMat.setColor("Color", ColorRGBA.Black);

            Material wireFrameMat = new Material(JmeGame.gameContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
            wireFrameMat.setColor("Color", ColorRGBA.White);

            Node node1 = new Node("wheel 1 node");
//            Geometry wheels1 = new Geometry("wheel 1", wheelMesh);
            Spatial wheels1=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels1).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels1).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels1.setLocalScale(0.35f,0.5f,0.35f);
            node1.attachChild(wheels1);
            wheels1.rotate(0, FastMath.PI, 0);
            vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff),
                    wheelDirection, wheelAxle, restLength, radius, true);

            Node node2 = new Node("wheel 2 node");
            Spatial wheels2=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels2).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels2).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels2.setLocalScale(0.35f,0.5f,0.35f);
            node2.attachChild(wheels2);
            wheels2.rotate(0, 0, 0);
            vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff),
                    wheelDirection, wheelAxle, restLength, radius, true);


            Node node3 = new Node("wheel 3 node");
            Spatial wheels3=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels3).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels3).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels3.setLocalScale(0.35f,0.5f,0.35f);
            node3.attachChild(wheels3);
            wheels3.rotate(0, FastMath.PI, 0);
            vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff),
                    wheelDirection, wheelAxle, restLength, radius, false);

            Node node4 = new Node("wheel 4 node");
            Spatial wheels4=JmeGame.gameContext.getAssetManager().loadModel("Models/tyre1.j3o");
            ((Node)wheels4).getChild("Cylinder.001").setMaterial(wheelsMat);
            ((Node)wheels4).getChild("Cylinder.002").setMaterial(wireFrameMat);
            wheels4.setLocalScale(0.35f,0.5f,0.35f);
            node4.attachChild(wheels4);
            wheels4.rotate(0, 0, 0);
            vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff),
                    wheelDirection, wheelAxle, restLength, radius, false);

            vehicleNode.attachChild(node1);
            vehicleNode.attachChild(node2);
            vehicleNode.attachChild(node3);
            vehicleNode.attachChild(node4);
            JmeGame.gameContext.getRootNode().attachChild(vehicleNode);
            JmeGame.gamePhysics.getPhysicsSpace().add(vehicle);

            return this;
        }
        public VehicleAutoShop startRealTimeCarSimulation(){

            //setting suspension values for wheels, this can be a bit tricky
            //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en
            float stiffness =30.0f;//200=f1 car
            float compValue = 0.5f; //(should be lower than damp)
            float dampValue = 3f;
            //compression force of spring(Shock Producer)
            vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
            //stretch force of spring(Shock Absorber)
            vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
            vehicle.setSuspensionStiffness(stiffness);
            vehicle.setMaxSuspensionForce(FastMath.pow(2, 20));

            return this;
        }

    }

You cannot do this type of conversion because Geometry isnot a subclass of Node class ie Geometry doesn’t extend Node…

1 Like

@Pavl_G is correct, a Spatial can be cast to a Node or to a Geometry, but you cannot cast a Geometry to a Node (or a Node to a Geometry).

If you want to understand even better, Id suggest checking out the part of the wiki that covers Spatials