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.