B4J Tutorial JavaFX 3D spinning Earth and Galaxy

Change it to your liking - download it from here:

Main Code:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

#AdditionalJar: j3dcore
#AdditionalJar: j3dutils
#AdditionalJar: vecmath


Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Pane1 As Pane
 
    Dim erth As earth
    Dim bb As JavaObject
 
    Dim t As Timer
 
 
 
    Private ImageView1 As ImageView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
     
    t.Initialize("t", 10)
    erth.Initialize

    bb = erth.makethecube
 
    Pane1.AddNode(bb, MainForm.Width * 0.06, MainForm.Height * 0.1, MainForm.Width * 0.8, MainForm.Height * 0.8)
    Pane1.Visible = True
 
    t.Enabled = True
 
End Sub


Sub t_tick
 
    erth.Rotationspeed = -0.2
 
End Sub

Earth Class Code:
Sub Class_Globals
    Private fx As JFX
 
    Dim nativeMe As JavaObject
    Dim ips1, ips2, ips3, ips4 As InputStream
 
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
 

    nativeMe = Me
    ips1 = File.OpenInput(File.DirAssets, "earth-d.jpg")
    ips2 = File.OpenInput(File.DirAssets, "earth-l.jpg")
    ips3 = File.OpenInput(File.DirAssets, "earth-s.jpg")
    ips4 = File.OpenInput(File.DirAssets, "earth-n.jpg")
 
 

End Sub

public Sub makethecube As JavaObject
 
    Return nativeMe.RunMethod("start1",  Array(ips1, ips2, ips3, ips4))
 
End Sub


public Sub setRotationspeed (spd As Float)
 
    nativeMe.RunMethod("rotateEarth", Array(spd))
 
 
End Sub



#if Java

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import java.io.InputStream;



  private static final float WIDTH = 300;
  private static final float HEIGHT = 300;

  private double anchorX, anchorY;
  private double anchorAngleX = 0;
  private double anchorAngleY = 0;
  private final DoubleProperty angleX = new SimpleDoubleProperty(0);
  private final DoubleProperty angleY = new SimpleDoubleProperty(0);

  private final Sphere sphere = new Sphere(150);

 
  public Group start1(InputStream ips1, InputStream ips2, InputStream ips3, InputStream ips4) {
    Camera camera = new PerspectiveCamera(true);
    camera.setNearClip(1);
    camera.setFarClip(10000);
    camera.translateZProperty().set(-900);

    Group world = new Group();
    world.getChildren().add(prepareEarth(ips1, ips2, ips3, ips4));

    Scene scene = new Scene(world, WIDTH, HEIGHT, true);
    scene.setFill(Color.SILVER);
    scene.setCamera(camera);

//    initMouseControl(world, scene, primaryStage);

//    prepareAnimation();
 
    return world;
  }


    public void rotateEarth(float rotspeed) {
 
        sphere.rotateProperty().set(sphere.getRotate() + rotspeed);
 
    }

/*
  private void prepareAnimation() {
    AnimationTimer timer = new AnimationTimer() {
      @Override
      public void handle(long now) {
        sphere.rotateProperty().set(sphere.getRotate() + 0.2);
      }
    };
    timer.start();
  }  */

  private Node prepareEarth(InputStream ips1, InputStream ips2, InputStream ips3, InputStream ips4) {
    PhongMaterial earthMaterial = new PhongMaterial();
    earthMaterial.setDiffuseMap(new Image(ips1));
    earthMaterial.setSelfIlluminationMap(new Image(ips2));
    earthMaterial.setSpecularMap(new Image(ips3));
    earthMaterial.setBumpMap(new Image(ips4));

    sphere.setRotationAxis(Rotate.Y_AXIS);
    sphere.setMaterial(earthMaterial);
    return sphere;
  }

  private void initMouseControl(Group group, Scene scene, Stage stage) {
    Rotate xRotate;
    Rotate yRotate;
    group.getTransforms().addAll(
        xRotate = new Rotate(0, Rotate.X_AXIS),
        yRotate = new Rotate(0, Rotate.Y_AXIS)
    );
    xRotate.angleProperty().bind(angleX);
    yRotate.angleProperty().bind(angleY);

    scene.setOnMousePressed(event -> {
      anchorX = event.getSceneX();
      anchorY = event.getSceneY();
      anchorAngleX = angleX.get();
      anchorAngleY = angleY.get();
    });

    scene.setOnMouseDragged(event -> {
      angleX.set(anchorAngleX - (anchorY - event.getSceneY()));
      angleY.set(anchorAngleY + anchorX - event.getSceneX());
    });

    stage.addEventHandler(ScrollEvent.SCROLL, event -> {
      double delta = event.getDeltaY();
      group.translateZProperty().set(group.getTranslateZ() + delta);
    });
  }

#End If



 

max123

Well-Known Member
Licensed User
Longtime User
Hi @Johan Schoeman, I like a lot your spinning Earth example with inline java code. ?
In past I've managed a lot around Java 3D, in pure java language and using JavaObject on B4J.

I had success to it on B4J only after a lot of tests, and now I can see your really simple and clear example code.

Because of title of your thread JavaFX 3D spinning Earth and Galaxy I want to ask you if this is JavaFX 3D or Java3D because they are two completely different libraries.

The import you use are the same I used on all my Java3D regular Java and B4J projects, so this confuse me a lot.
Even using Java3D the user need to install on the system the Java3D library as addon for default installed JDK, and the installer copy the j3dcore.jar, j3dutils.jar and vecmath.jar inside the JDK. This can be done even manually, but it need to be in system enviroment variables.

Just by placing these 3 jar files in the final app package do not worked for me, so to distribuite it the user need to install Java3D on the system, I even made some automated bash script installer for Java3D on Raspberry to place on github.

Without these steps any compiled Java3D project crash on start.

So that confuse me a lot more...

Actually it load these three jar files from my B4J Libraries folder because I've placed here for my tests, even I installed Java3D on Win11.

I want to ask you what exact library you used and where you placed these 3 jar files, but most important, if final app works without have some 3D libraries installed on the system, may just distribuite the 3 jar library files with app, so it do not have any dependency of system.... like B4JPackager do.

Many thanks if you have time to explain me how you managed it.
 

Attachments

  • Screenshot 2023-11-29 172019.png
    12.2 KB · Views: 136
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
 

max123

Well-Known Member
Licensed User
Longtime User
You cannot be more precise.....

Thanks for very useful link....

So now it is confirmed that you really used JavaFX 3D.

And it use the same 3 library files than Java3D... Probably not the same, but same name. Even the API seem not too much different, but Java3D is on top of Swing and JavaFX 3D on top of JavaFX.

And you only copied 3 jar files in Library folder ?
And final app works without dependences ? Need to put three jar files in the final app folder?

And final jar is multiplatform like JOGL ?

Too many questions sorry, but now I want to investigate.

Many thanks
 
Last edited:

Johan Schoeman

Expert
Licensed User
Longtime User
My laptop that I have done it with was stolen. Can really not remember how I got it to work. Will have to find the jars again and read again about how to make it work. But not right now as too caught up with work at present.
 

Johan Schoeman

Expert
Licensed User
Longtime User
So now it is confirmed that you really used JavaFX 3D.
It is indeed JavaFX. I am using Java 14 with B4J.

You can ignore the AdditionalJar's (comment them out). It should run as is.

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

'#AdditionalJar: j3dcore
'#AdditionalJar: j3dutils
'#AdditionalJar: vecmath


Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Pane1 As Pane
 
    Dim erth As earth
    Dim bb As JavaObject
 
    Dim t As Timer
 
 
 
    Private ImageView1 As ImageView
End Sub
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
@Johan Schoeman, you are great. Many thanks for your interest.

So no need any library and dependency, it is ALREADY contained in JavaFX CORE ?
And it is just rendered on a regular JavaFX Pane... wow ?

Or you have to put these three jar files in B4J Libraries folder even if ignore AdditionalJars ?
If yes where I can download them to test with ?
But I suppose they not needed at all, right ?

This is very cool.....
Did you informed Erel about this ?

It looks like we have a default 3D engine on B4J, for games develop and general 3D applications.
And directly on top of JavaFX. It is working on Java11 too....

I will try to package your spinning Earth example with internal B4J IDE packager and test it on some other Windows pcs if it is working as is.
Next I will try to creare a package to test if it is working on Linux too (when I know how to package to Linux)

Many thanks
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
I've created a Windows package for spinning Earth , the build folder is 48.8 MB.
The spinning Earth works without dependencies.

I will experiment with other examples from a link you posted me.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…