JavaFX provides comprehensive support for 3D graphics, allowing you to create sophisticated 3D scenes with lighting, materials, cameras, and interactive controls.
1. Basic 3D Scene Setup
Simple 3D Scene with Basic Shapes
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class Basic3DScene extends Application {
private Group root;
private Scene scene;
private PerspectiveCamera camera;
private final double SCENE_WIDTH = 1024;
private final double SCENE_HEIGHT = 768;
@Override
public void start(Stage primaryStage) {
root = new Group();
scene = new Scene(root, SCENE_WIDTH, SCENE_HEIGHT, true);
scene.setFill(Color.LIGHTGRAY);
setupCamera();
setupLighting();
create3DShapes();
setupMouseControl();
primaryStage.setTitle("Basic JavaFX 3D Scene");
primaryStage.setScene(scene);
primaryStage.show();
}
private void setupCamera() {
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setTranslateZ(-1000);
camera.setFieldOfView(60);
scene.setCamera(camera);
}
private void setupLighting() {
// Ambient light
AmbientLight ambientLight = new AmbientLight(Color.WHITE.deriveColor(0, 1, 0.8, 1));
// Point light
PointLight pointLight = new PointLight(Color.WHITE);
pointLight.setTranslateX(300);
pointLight.setTranslateY(-200);
pointLight.setTranslateZ(-300);
root.getChildren().addAll(ambientLight, pointLight);
}
private void create3DShapes() {
// Create materials
PhongMaterial redMaterial = new PhongMaterial();
redMaterial.setDiffuseColor(Color.DARKRED);
redMaterial.setSpecularColor(Color.RED);
PhongMaterial blueMaterial = new PhongMaterial();
blueMaterial.setDiffuseColor(Color.DARKBLUE);
blueMaterial.setSpecularColor(Color.BLUE);
PhongMaterial greenMaterial = new PhongMaterial();
greenMaterial.setDiffuseColor(Color.DARKGREEN);
greenMaterial.setSpecularColor(Color.GREEN);
// Create 3D shapes
Box box = new Box(200, 200, 200);
box.setMaterial(redMaterial);
box.setTranslateX(-300);
box.setTranslateY(0);
Sphere sphere = new Sphere(100);
sphere.setMaterial(blueMaterial);
sphere.setTranslateX(0);
sphere.setTranslateY(0);
Cylinder cylinder = new Cylinder(80, 200);
cylinder.setMaterial(greenMaterial);
cylinder.setTranslateX(300);
cylinder.setTranslateY(0);
root.getChildren().addAll(box, sphere, cylinder);
}
private void setupMouseControl() {
Rotate xRotate = new Rotate(0, Rotate.X_AXIS);
Rotate yRotate = new Rotate(0, Rotate.Y_AXIS);
root.getTransforms().addAll(xRotate, yRotate);
scene.setOnMousePressed(event -> {
scene.setCursor(Cursor.MOVE);
});
scene.setOnMouseReleased(event -> {
scene.setCursor(Cursor.DEFAULT);
});
scene.setOnMouseDragged(event -> {
yRotate.setAngle(yRotate.getAngle() + event.getX() / 5);
xRotate.setAngle(xRotate.getAngle() - event.getY() / 5);
});
// Zoom with scroll
scene.setOnScroll(event -> {
double zoomFactor = 1.05;
double deltaY = event.getDeltaY();
if (deltaY < 0) {
zoomFactor = 0.95;
}
camera.setTranslateZ(camera.getTranslateZ() * zoomFactor);
});
}
public static void main(String[] args) {
launch(args);
}
}
2. Advanced 3D Shapes and Materials
Complex 3D Objects with Textures
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.image.Image;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class Advanced3DShapes extends Application {
private Group root;
private PerspectiveCamera camera;
@Override
public void start(Stage primaryStage) {
root = new Group();
Scene scene = new Scene(root, 1200, 800, true);
scene.setFill(Color.rgb(20, 20, 40));
setupCamera(scene);
setupLighting();
createAdvancedShapes();
primaryStage.setTitle("Advanced JavaFX 3D Shapes");
primaryStage.setScene(scene);
primaryStage.show();
}
private void setupCamera(Scene scene) {
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setTranslateZ(-1500);
camera.setFieldOfView(45);
scene.setCamera(camera);
}
private void setupLighting() {
// Multiple light sources for better 3D effect
AmbientLight ambientLight = new AmbientLight(Color.WHITE.deriveColor(0, 1, 0.3, 1));
PointLight pointLight1 = new PointLight(Color.LIGHTBLUE);
pointLight1.setTranslateX(-400);
pointLight1.setTranslateY(-300);
pointLight1.setTranslateZ(-500);
PointLight pointLight2 = new PointLight(Color.LIGHTYELLOW);
pointLight2.setTranslateX(400);
pointLight2.setTranslateY(300);
pointLight2.setTranslateZ(-500);
root.getChildren().addAll(ambientLight, pointLight1, pointLight2);
}
private void createAdvancedShapes() {
// Textured sphere
createTexturedSphere();
// Metallic torus
createTorus();
// Glass pyramid
createPyramid();
// Complex mesh (custom shape)
createCustomMesh();
}
private void createTexturedSphere() {
try {
// Load texture image
Image earthTexture = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Blue_Marble_2002.png/640px-Blue_Marble_2002.png");
PhongMaterial earthMaterial = new PhongMaterial();
earthMaterial.setDiffuseMap(earthTexture);
earthMaterial.setSpecularColor(Color.WHITE);
earthMaterial.setSpecularPower(64);
Sphere earth = new Sphere(150);
earth.setMaterial(earthMaterial);
earth.setTranslateX(-400);
earth.setTranslateY(-200);
root.getChildren().add(earth);
} catch (Exception e) {
// Fallback if texture loading fails
Sphere sphere = new Sphere(150);
PhongMaterial material = new PhongMaterial(Color.DARKBLUE);
sphere.setMaterial(material);
sphere.setTranslateX(-400);
sphere.setTranslateY(-200);
root.getChildren().add(sphere);
}
}
private void createTorus() {
// Create a torus using TriangleMesh
int divisions = 64;
float radius = 100;
float tubeRadius = 40;
TriangleMesh torusMesh = new TriangleMesh();
torusMesh.getTexCoords().addAll(0, 0);
// Generate vertices
for (int i = 0; i < divisions; i++) {
double theta = 2.0 * Math.PI * i / divisions;
for (int j = 0; j < divisions; j++) {
double phi = 2.0 * Math.PI * j / divisions;
float x = (float) ((radius + tubeRadius * Math.cos(phi)) * Math.cos(theta));
float y = (float) ((radius + tubeRadius * Math.cos(phi)) * Math.sin(theta));
float z = (float) (tubeRadius * Math.sin(phi));
torusMesh.getPoints().addAll(x, y, z);
}
}
// Generate faces
for (int i = 0; i < divisions; i++) {
for (int j = 0; j < divisions; j++) {
int i1 = i;
int i2 = (i + 1) % divisions;
int j1 = j;
int j2 = (j + 1) % divisions;
int a = i1 * divisions + j1;
int b = i2 * divisions + j1;
int c = i1 * divisions + j2;
int d = i2 * divisions + j2;
torusMesh.getFaces().addAll(a, 0, b, 0, c, 0);
torusMesh.getFaces().addAll(b, 0, d, 0, c, 0);
}
}
MeshView torus = new MeshView(torusMesh);
PhongMaterial goldMaterial = new PhongMaterial();
goldMaterial.setDiffuseColor(Color.GOLD);
goldMaterial.setSpecularColor(Color.YELLOW);
goldMaterial.setSpecularPower(32);
torus.setMaterial(goldMaterial);
torus.setTranslateX(400);
torus.setTranslateY(-200);
root.getChildren().add(torus);
}
private void createPyramid() {
float[] points = {
// Base vertices
-100, 100, -100, // 0: back-left
100, 100, -100, // 1: back-right
100, 100, 100, // 2: front-right
-100, 100, 100, // 3: front-left
// Apex
0, -100, 0 // 4: apex
};
float[] texCoords = {
0, 0, 1, 0, 1, 1, 0, 1
};
int[] faces = {
// Base
0, 0, 1, 1, 2, 2,
0, 0, 2, 2, 3, 3,
// Sides
0, 0, 4, 4, 1, 1,
1, 1, 4, 4, 2, 2,
2, 2, 4, 4, 3, 3,
3, 3, 4, 4, 0, 0
};
TriangleMesh pyramidMesh = new TriangleMesh();
pyramidMesh.getPoints().addAll(points);
pyramidMesh.getTexCoords().addAll(texCoords);
pyramidMesh.getFaces().addAll(faces);
MeshView pyramid = new MeshView(pyramidMesh);
PhongMaterial glassMaterial = new PhongMaterial();
glassMaterial.setDiffuseColor(Color.TRANSPARENT);
glassMaterial.setSpecularColor(Color.WHITE);
glassMaterial.setSpecularPower(128);
glassMaterial.setDiffuseColor(Color.rgb(200, 200, 255, 0.3));
pyramid.setMaterial(glassMaterial);
pyramid.setTranslateX(-400);
pyramid.setTranslateY(200);
root.getChildren().add(pyramid);
}
private void createCustomMesh() {
// Create a more complex custom shape (abstract sculpture)
TriangleMesh mesh = new TriangleMesh();
// Add points for a more complex shape
for (int i = 0; i < 50; i++) {
double theta = 2 * Math.PI * i / 50;
for (int j = 0; j < 20; j++) {
double phi = Math.PI * j / 19;
double r = 80 + 20 * Math.sin(5 * theta) * Math.cos(3 * phi);
float x = (float) (r * Math.sin(phi) * Math.cos(theta));
float y = (float) (r * Math.sin(phi) * Math.sin(theta));
float z = (float) (r * Math.cos(phi));
mesh.getPoints().addAll(x, y, z);
}
}
mesh.getTexCoords().addAll(0, 0);
// Create faces (simplified)
for (int i = 0; i < 49; i++) {
for (int j = 0; j < 19; j++) {
int a = i * 20 + j;
int b = (i + 1) * 20 + j;
int c = i * 20 + j + 1;
int d = (i + 1) * 20 + j + 1;
mesh.getFaces().addAll(a, 0, b, 0, c, 0);
mesh.getFaces().addAll(b, 0, d, 0, c, 0);
}
}
MeshView customShape = new MeshView(mesh);
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.PURPLE);
material.setSpecularColor(Color.PINK);
material.setSpecularPower(16);
customShape.setMaterial(material);
customShape.setTranslateX(400);
customShape.setTranslateY(200);
root.getChildren().add(customShape);
}
public static void main(String[] args) {
launch(args);
}
}
3. Interactive 3D Camera Control
Advanced Camera Navigation System
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.stage.Stage;
public class Interactive3DCamera extends Application {
private static final double WIDTH = 1200;
private static final double HEIGHT = 800;
private double anchorX, anchorY;
private double anchorAngleX = 0;
private double anchorAngleY = 0;
private final Rotate xRotate = new Rotate(0, Rotate.X_AXIS);
private final Rotate yRotate = new Rotate(0, Rotate.Y_AXIS);
@Override
public void start(Stage primaryStage) {
SmartGroup world = new SmartGroup();
world.getTransforms().addAll(xRotate, yRotate);
Camera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.translateZProperty().set(-2000);
Scene scene = new Scene(world, WIDTH, HEIGHT, true);
scene.setFill(Color.rgb(10, 10, 40));
scene.setCamera(camera);
prepareScene(world);
prepareCameraControls(scene, camera);
primaryStage.setTitle("Interactive 3D Camera Control");
primaryStage.setScene(scene);
primaryStage.show();
}
private void prepareScene(Group root) {
// Create a 3D grid for reference
create3DGrid(root);
// Create multiple objects at different positions
for (int i = -2; i <= 2; i++) {
for (int j = -2; j <= 2; j++) {
if (i == 0 && j == 0) continue; // Skip center
Box box = new Box(100, 100, 100);
box.setTranslateX(i * 300);
box.setTranslateZ(j * 300);
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.hsb((i + j) * 36, 0.8, 0.8));
material.setSpecularColor(Color.WHITE);
box.setMaterial(material);
root.getChildren().add(box);
}
}
// Center sphere
Sphere centerSphere = new Sphere(150);
PhongMaterial centerMaterial = new PhongMaterial();
centerMaterial.setDiffuseColor(Color.GOLD);
centerMaterial.setSpecularColor(Color.YELLOW);
centerSphere.setMaterial(centerMaterial);
root.getChildren().add(centerSphere);
}
private void create3DGrid(Group root) {
// Create grid lines
PhongMaterial gridMaterial = new PhongMaterial(Color.GRAY.deriveColor(0, 1, 1, 0.3));
for (int i = -5; i <= 5; i++) {
// X-axis lines
Box xLine = new Box(2000, 2, 2);
xLine.setMaterial(gridMaterial);
xLine.setTranslateZ(i * 200);
root.getChildren().add(xLine);
// Z-axis lines
Box zLine = new Box(2, 2, 2000);
zLine.setMaterial(gridMaterial);
zLine.setTranslateX(i * 200);
root.getChildren().add(zLine);
}
// Axes
Box xAxis = new Box(2200, 5, 5);
xAxis.setMaterial(new PhongMaterial(Color.RED));
root.getChildren().add(xAxis);
Box zAxis = new Box(5, 5, 2200);
zAxis.setMaterial(new PhongMaterial(Color.BLUE));
root.getChildren().add(zAxis);
// Y-axis (vertical)
Box yAxis = new Box(5, 1000, 5);
yAxis.setMaterial(new PhongMaterial(Color.GREEN));
yAxis.setTranslateY(-500);
root.getChildren().add(yAxis);
}
private void prepareCameraControls(Scene scene, Camera camera) {
// Rotation
scene.setOnMousePressed(event -> {
anchorX = event.getSceneX();
anchorY = event.getSceneY();
anchorAngleX = xRotate.getAngle();
anchorAngleY = yRotate.getAngle();
});
scene.setOnMouseDragged(event -> {
xRotate.setAngle(anchorAngleX - (anchorY - event.getSceneY()));
yRotate.setAngle(anchorAngleY + anchorX - event.getSceneX());
});
// Zoom
scene.setOnScroll(event -> {
double delta = event.getDeltaY();
double zoomFactor = 1.05;
if (delta < 0) {
zoomFactor = 0.95;
}
double currentZ = camera.getTranslateZ();
camera.setTranslateZ(currentZ * zoomFactor);
});
// Movement with arrow keys
scene.setOnKeyPressed(event -> {
double moveAmount = 50;
switch (event.getCode()) {
case W -> camera.setTranslateY(camera.getTranslateY() + moveAmount);
case S -> camera.setTranslateY(camera.getTranslateY() - moveAmount);
case A -> camera.setTranslateX(camera.getTranslateX() - moveAmount);
case D -> camera.setTranslateX(camera.getTranslateX() + moveAmount);
case Q -> camera.setTranslateZ(camera.getTranslateZ() + moveAmount);
case E -> camera.setTranslateZ(camera.getTranslateZ() - moveAmount);
case R -> resetCamera(camera);
}
});
// Reset on middle click
scene.setOnMouseClicked(event -> {
if (event.getButton() == MouseButton.MIDDLE) {
resetCamera(camera);
}
});
}
private void resetCamera(Camera camera) {
xRotate.setAngle(0);
yRotate.setAngle(0);
camera.setTranslateX(0);
camera.setTranslateY(0);
camera.setTranslateZ(-2000);
}
class SmartGroup extends Group {
void rotateByX(double angle) {
Rotate r = new Rotate(angle, Rotate.X_AXIS);
this.getTransforms().add(r);
}
void rotateByY(double angle) {
Rotate r = new Rotate(angle, Rotate.Y_AXIS);
this.getTransforms().add(r);
}
}
public static void main(String[] args) {
launch(args);
}
}
4. 3D Animation and Transformations
Animated 3D Scene with Transformations
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Animated3DScene extends Application {
private Group root;
private PerspectiveCamera camera;
@Override
public void start(Stage primaryStage) {
root = new Group();
Scene scene = new Scene(root, 1000, 700, true);
scene.setFill(Color.rgb(20, 20, 35));
setupCamera(scene);
setupLighting();
createAnimatedScene();
primaryStage.setTitle("Animated 3D Scene");
primaryStage.setScene(scene);
primaryStage.show();
startAnimations();
}
private void setupCamera(Scene scene) {
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setTranslateZ(-1200);
scene.setCamera(camera);
}
private void setupLighting() {
AmbientLight ambientLight = new AmbientLight(Color.WHITE.deriveColor(0, 1, 0.4, 1));
PointLight pointLight = new PointLight(Color.WHITE);
pointLight.setTranslateX(500);
pointLight.setTranslateY(-300);
pointLight.setTranslateZ(-500);
root.getChildren().addAll(ambientLight, pointLight);
}
private void createAnimatedScene() {
// Orbiting planets
createSolarSystem();
// Pulsating cubes
createPulsatingCubes();
// Rotating rings
createRotatingRings();
// Floating particles
createFloatingParticles();
}
private void createSolarSystem() {
// Sun
Sphere sun = new Sphere(80);
PhongMaterial sunMaterial = new PhongMaterial();
sunMaterial.setDiffuseColor(Color.ORANGE);
sunMaterial.setSelfIlluminationMap(new javafx.scene.image.Image(
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
));
sun.setMaterial(sunMaterial);
// Earth orbit
Group earthOrbit = new Group();
Sphere earth = new Sphere(30);
PhongMaterial earthMaterial = new PhongMaterial(Color.DODGERBLUE);
earth.setMaterial(earthMaterial);
earth.setTranslateX(300);
earthOrbit.getChildren().add(earth);
// Moon orbit around earth
Group moonOrbit = new Group();
Sphere moon = new Sphere(10);
moon.setMaterial(new PhongMaterial(Color.LIGHTGRAY));
moon.setTranslateX(60);
moonOrbit.getChildren().add(moon);
earthOrbit.getChildren().add(moonOrbit);
root.getChildren().addAll(sun, earthOrbit);
// Animations
RotateTransition earthRotation = new RotateTransition(Duration.seconds(10), earthOrbit);
earthRotation.setAxis(Rotate.Y_AXIS);
earthRotation.setByAngle(360);
earthRotation.setCycleCount(Animation.INDEFINITE);
earthRotation.setInterpolator(Interpolator.LINEAR);
RotateTransition moonRotation = new RotateTransition(Duration.seconds(2), moonOrbit);
moonRotation.setAxis(Rotate.Y_AXIS);
moonRotation.setByAngle(360);
moonRotation.setCycleCount(Animation.INDEFINITE);
moonRotation.setInterpolator(Interpolator.LINEAR);
earthRotation.play();
moonRotation.play();
}
private void createPulsatingCubes() {
for (int i = 0; i < 8; i++) {
Box cube = new Box(50, 50, 50);
cube.setTranslateX(Math.cos(i * Math.PI / 4) * 200);
cube.setTranslateZ(Math.sin(i * Math.PI / 4) * 200);
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.hsb(i * 45, 0.8, 0.8));
cube.setMaterial(material);
ScaleTransition scaleTransition = new ScaleTransition(Duration.seconds(1 + i * 0.2), cube);
scaleTransition.setFromX(1.0);
scaleTransition.setFromY(1.0);
scaleTransition.setFromZ(1.0);
scaleTransition.setToX(2.0);
scaleTransition.setToY(2.0);
scaleTransition.setToZ(2.0);
scaleTransition.setAutoReverse(true);
scaleTransition.setCycleCount(Animation.INDEFINITE);
RotateTransition rotateTransition = new RotateTransition(Duration.seconds(5), cube);
rotateTransition.setAxis(Rotate.Y_AXIS);
rotateTransition.setByAngle(360);
rotateTransition.setCycleCount(Animation.INDEFINITE);
SequentialTransition sequentialTransition = new SequentialTransition(
new PauseTransition(Duration.seconds(i * 0.5)),
scaleTransition
);
root.getChildren().add(cube);
rotateTransition.play();
sequentialTransition.play();
}
}
private void createRotatingRings() {
for (int i = 0; i < 3; i++) {
Box ring = new Box(400, 10, 10);
ring.setTranslateY(i * 100 - 100);
PhongMaterial ringMaterial = new PhongMaterial();
ringMaterial.setDiffuseColor(Color.hsb(i * 120, 0.9, 0.9));
ringMaterial.setSpecularColor(Color.WHITE);
ring.setMaterial(ringMaterial);
RotateTransition rotateTransition = new RotateTransition(Duration.seconds(8 - i * 2), ring);
rotateTransition.setAxis(Rotate.Y_AXIS);
rotateTransition.setByAngle(360);
rotateTransition.setCycleCount(Animation.INDEFINITE);
rotateTransition.setInterpolator(Interpolator.LINEAR);
RotateTransition tiltTransition = new RotateTransition(Duration.seconds(12 + i * 3), ring);
tiltTransition.setAxis(Rotate.Z_AXIS);
tiltTransition.setFromAngle(0);
tiltTransition.setToAngle(360);
tiltTransition.setCycleCount(Animation.INDEFINITE);
root.getChildren().add(ring);
rotateTransition.play();
tiltTransition.play();
}
}
private void createFloatingParticles() {
for (int i = 0; i < 50; i++) {
Sphere particle = new Sphere(2 + Math.random() * 8);
particle.setMaterial(new PhongMaterial(Color.WHITE.deriveColor(0, 1, 1, 0.7)));
// Random initial position
particle.setTranslateX((Math.random() - 0.5) * 1000);
particle.setTranslateY((Math.random() - 0.5) * 1000);
particle.setTranslateZ((Math.random() - 0.5) * 1000);
// Create floating animation
TranslateTransition floatTransition = new TranslateTransition(
Duration.seconds(5 + Math.random() * 10), particle);
floatTransition.setFromX(particle.getTranslateX());
floatTransition.setFromY(particle.getTranslateY());
floatTransition.setFromZ(particle.getTranslateZ());
floatTransition.setToX((Math.random() - 0.5) * 1000);
floatTransition.setToY((Math.random() - 0.5) * 1000);
floatTransition.setToZ((Math.random() - 0.5) * 1000);
floatTransition.setAutoReverse(true);
floatTransition.setCycleCount(Animation.INDEFINITE);
floatTransition.setInterpolator(Interpolator.EASE_BOTH);
FadeTransition fadeTransition = new FadeTransition(Duration.seconds(3), particle);
fadeTransition.setFromValue(0.3);
fadeTransition.setToValue(1.0);
fadeTransition.setAutoReverse(true);
fadeTransition.setCycleCount(Animation.INDEFINITE);
root.getChildren().add(particle);
floatTransition.play();
fadeTransition.play();
}
}
private void startAnimations() {
// Camera animation
RotateTransition cameraRotation = new RotateTransition(Duration.seconds(30), root);
cameraRotation.setAxis(Rotate.Y_AXIS);
cameraRotation.setByAngle(360);
cameraRotation.setCycleCount(Animation.INDEFINITE);
cameraRotation.setInterpolator(Interpolator.LINEAR);
cameraRotation.play();
}
public static void main(String[] args) {
launch(args);
}
}
5. 3D Import and Custom Models
Loading 3D Models and Custom Mesh Creation
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.stage.Stage;
public class ModelImport3D extends Application {
private Group root;
private PerspectiveCamera camera;
@Override
public void start(Stage primaryStage) {
root = new Group();
Scene scene = new Scene(root, 1000, 700, true);
scene.setFill(Color.rgb(25, 25, 40));
setupCamera(scene);
setupLighting();
createCustomModels();
primaryStage.setTitle("3D Model Import and Custom Meshes");
primaryStage.setScene(scene);
primaryStage.show();
}
private void setupCamera(Scene scene) {
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setTranslateZ(-800);
scene.setCamera(camera);
}
private void setupLighting() {
AmbientLight ambientLight = new AmbientLight(Color.WHITE.deriveColor(0, 1, 0.3, 1));
PointLight pointLight1 = new PointLight(Color.WHITE);
pointLight1.setTranslateX(300);
pointLight1.setTranslateY(-200);
pointLight1.setTranslateZ(-400);
PointLight pointLight2 = new PointLight(Color.LIGHTBLUE);
pointLight2.setTranslateX(-300);
pointLight2.setTranslateY(200);
pointLight2.setTranslateZ(-400);
root.getChildren().addAll(ambientLight, pointLight1, pointLight2);
}
private void createCustomModels() {
// Create a custom torus knot
createTorusKnot();
// Create a terrain-like surface
createTerrain();
// Create a wave surface
createWaveSurface();
}
private void createTorusKnot() {
int uSteps = 200;
int vSteps = 50;
float radius = 100;
float tubeRadius = 20;
int p = 2;
int q = 3;
TriangleMesh mesh = new TriangleMesh();
// Generate vertices
for (int i = 0; i < uSteps; i++) {
double u = 2 * Math.PI * i / uSteps;
double cu = Math.cos(u);
double su = Math.sin(u);
for (int j = 0; j < vSteps; j++) {
double v = 2 * Math.PI * j / vSteps;
double cv = Math.cos(v);
double sv = Math.sin(v);
// Torus knot formula
double x = radius * (2 + Math.cos(q * u)) * Math.cos(p * u) +
tubeRadius * cv * Math.cos(p * u) * (2 + Math.cos(q * u)) -
tubeRadius * sv * Math.sin(p * u) * Math.sin(q * u);
double y = radius * (2 + Math.cos(q * u)) * Math.sin(p * u) +
tubeRadius * cv * Math.sin(p * u) * (2 + Math.cos(q * u)) +
tubeRadius * sv * Math.cos(p * u) * Math.sin(q * u);
double z = -radius * Math.sin(q * u) - tubeRadius * sv * Math.cos(q * u);
mesh.getPoints().addAll((float)x, (float)y, (float)z);
}
}
mesh.getTexCoords().addAll(0, 0);
// Generate faces
for (int i = 0; i < uSteps; i++) {
for (int j = 0; j < vSteps; j++) {
int i1 = i;
int i2 = (i + 1) % uSteps;
int j1 = j;
int j2 = (j + 1) % vSteps;
int a = i1 * vSteps + j1;
int b = i2 * vSteps + j1;
int c = i1 * vSteps + j2;
int d = i2 * vSteps + j2;
mesh.getFaces().addAll(a, 0, b, 0, c, 0);
mesh.getFaces().addAll(b, 0, d, 0, c, 0);
}
}
MeshView torusKnot = new MeshView(mesh);
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.PURPLE);
material.setSpecularColor(Color.PINK);
material.setSpecularPower(32);
torusKnot.setMaterial(material);
torusKnot.setTranslateX(-300);
root.getChildren().add(torusKnot);
}
private void createTerrain() {
int width = 50;
int height = 50;
float scale = 200f / width;
TriangleMesh mesh = new TriangleMesh();
// Generate vertices with height variation
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float heightValue = (float) (
Math.sin(x * 0.2) * Math.cos(y * 0.2) * 20 +
Math.sin(x * 0.5) * Math.cos(y * 0.5) * 10
);
mesh.getPoints().addAll(
(x - width / 2) * scale,
heightValue,
(y - height / 2) * scale
);
}
}
mesh.getTexCoords().addAll(0, 0);
// Generate faces
for (int y = 0; y < height - 1; y++) {
for (int x = 0; x < width - 1; x++) {
int tl = y * width + x;
int tr = y * width + x + 1;
int bl = (y + 1) * width + x;
int br = (y + 1) * width + x + 1;
mesh.getFaces().addAll(tl, 0, bl, 0, tr, 0);
mesh.getFaces().addAll(tr, 0, bl, 0, br, 0);
}
}
MeshView terrain = new MeshView(mesh);
PhongMaterial terrainMaterial = new PhongMaterial();
terrainMaterial.setDiffuseColor(Color.FORESTGREEN);
terrainMaterial.setSpecularColor(Color.LIGHTGREEN);
terrain.setMaterial(terrainMaterial);
terrain.setTranslateX(300);
root.getChildren().add(terrain);
}
private void createWaveSurface() {
int size = 40;
float scale = 10f;
TriangleMesh mesh = new TriangleMesh();
// Generate vertices for wave surface
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
float x = (i - size / 2) * scale;
float z = (j - size / 2) * scale;
float y = (float) (Math.sin(Math.sqrt(x * x + z * z) * 0.3) * 20);
mesh.getPoints().addAll(x, y, z);
}
}
mesh.getTexCoords().addAll(0, 0);
// Generate faces
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - 1; j++) {
int a = i * size + j;
int b = (i + 1) * size + j;
int c = i * size + j + 1;
int d = (i + 1) * size + j + 1;
mesh.getFaces().addAll(a, 0, b, 0, c, 0);
mesh.getFaces().addAll(b, 0, d, 0, c, 0);
}
}
MeshView wave = new MeshView(mesh);
PhongMaterial waveMaterial = new PhongMaterial();
waveMaterial.setDiffuseColor(Color.DODGERBLUE);
waveMaterial.setSpecularColor(Color.LIGHTBLUE);
waveMaterial.setSpecularPower(64);
wave.setMaterial(waveMaterial);
wave.setTranslateY(200);
// Add animation to wave
javafx.animation.AnimationTimer waveAnimation = new javafx.animation.AnimationTimer() {
private long startTime = System.nanoTime();
@Override
public void handle(long now) {
double elapsed = (now - startTime) / 1_000_000_000.0;
// Update vertex positions to create animated wave
// Note: In a real application, you'd need to recreate the mesh
// or use a different approach for performance
}
};
waveAnimation.start();
root.getChildren().add(wave);
}
public static void main(String[] args) {
launch(args);
}
}
Key JavaFX 3D Concepts
- 3D Shapes: Box, Sphere, Cylinder, and custom MeshView
- Materials: PhongMaterial with colors, textures, and lighting properties
- Lighting: AmbientLight, PointLight, and SpotLight
- Camera: PerspectiveCamera for 3D viewing
- Transformations: Rotate, Scale, Translate for positioning objects
- Animation: Using JavaFX animation classes for dynamic scenes
- Interaction: Mouse and keyboard controls for camera navigation
This comprehensive guide covers the essential aspects of 3D graphics in JavaFX, from basic scene setup to advanced animations and custom mesh creation.