2

I am developping a game, in JavaFX 3D, in which the player is running down a long road. There are items and obstacles coming his way. The point is: now the objects just appear out of nowhere if they enter my clipping distance. Therefore I want to create some kind of fog (or anything else that "hides" the initialization of the objects)

The problem is that I cannot find any example in which this is done. I am looking for an example piece of code/link to source/any other advice.

  • Way too broad a question to provide a definitive answer, but maybe a [`FadeTransition`](http://docs.oracle.com/javase/8/javafx/api/javafx/animation/FadeTransition.html) would help. – James_D Sep 22 '15 at 20:24

2 Answers2

3

Having said it's too broad a question, and there must be many, many ways to do this, here's one possible implementation. This is 2D but could easily be adapted for a 3D app (I think). The idea is just to let a few light gray circles drift around on a white background, and apply an enormous blur to the whole thing.

You could then let your objects appear with this as a background, and fade them in from gray to their real color (or some such). The colors and velocities of the circles, and the blur radius, probably need some tuning...

import java.util.Random;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class FogExample extends Application {

    private static final int WIDTH = 600 ;
    private static final int HEIGHT = 600 ;


    @Override
    public void start(Stage primaryStage) {

        Fog fog = new Fog(WIDTH, HEIGHT);

        Scene scene = new Scene(new StackPane(fog.getView()), WIDTH, HEIGHT);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static class Fog {
        private final int width ;
        private final int height ;
        private final Pane fog ;
        private final Random RNG = new Random();

        public Fog(int width, int height) {
            this.width = width ;
            this.height = height ;
            this.fog = new Pane();
            Rectangle rect = new Rectangle(0, 0, width, height);
            rect.setFill(Color.rgb(0xe0, 0xe0, 0xe0));
            fog.getChildren().add(rect);

            for (int i = 0; i < 50; i++) {
                fog.getChildren().add(createFogElement());
            }

            fog.setEffect(new GaussianBlur((width + height) / 2.5));

        }

        private Circle createFogElement() {
            Circle circle = new Circle(RNG.nextInt(width - 50) + 25, RNG.nextInt(height - 50) + 25, 15 + RNG.nextInt(50));
            int shade = 0xcf + RNG.nextInt(0x20);
            circle.setFill(Color.rgb(shade, shade, shade));
            AnimationTimer anim = new AnimationTimer() {

                double xVel = RNG.nextDouble()*40 - 20 ;
                double yVel = RNG.nextDouble()*40 - 20 ;

                long lastUpdate = 0 ;

                @Override
                public void handle(long now) {
                    if (lastUpdate > 0) {
                        double elapsedSeconds = (now - lastUpdate) / 1_000_000_000.0 ;
                        double x = circle.getCenterX() ;
                        double y = circle.getCenterY() ;
                        if ( x + elapsedSeconds * xVel > width || x + elapsedSeconds * xVel < 0) {
                            xVel = - xVel ; 
                        }
                        if ( y + elapsedSeconds * yVel > height || y + elapsedSeconds * yVel < 0) {
                            yVel = - yVel ; 
                        }
                        circle.setCenterX(x + elapsedSeconds*xVel);
                        circle.setCenterY(y + elapsedSeconds * yVel);
                    }
                    lastUpdate = now ;
                }

            };
            anim.start();
            return circle ;
        }

        public Node getView() {
            return fog ;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
1

Typical 3D systems use a Particle system to do this which involves a combination of transparency, alpha fluctuations, and billboard textures. Believe it or not Fog, smoke and flames... particle effects... are not actually 3D at all but 2D images that have been positioned, sized, and colored to appear in 3D. They are then animated rapidly enough so that the human viewer can't make out the nuances of the 2D images. The problem with JavaFX 3D is that it does not support transparency "yet".(it is unofficially available). Also there is no particle type object that will let you overlay shapes and textures as James_D suggests without manually managing the positioning with respect to the camera. However there is hope... the F(X)yz project provides a BillBoard class which will allow you to place an image perpendicular to the camera. You can rapidly update this image using a Timer and some Random.next() type Circle creations for the fog using the approach James_D suggested. An example on using the BillBoard in a manner like this is in BillBoardBehaviourTest and CameraViewTest. Performance is demonstrated in CameraViewTest. What I would do if I were you is setup a large frustrum wide BillBoard object at the back -Z position of your frustrum (where the objects enter the scene) and then setup a Timer/Random circle generator in a pane off screen. Then using the approach in the CameraViewTest, snapshot the off screen pane (which has the circles) and then set that image to the BillBoard. You will have to have the SnapShot call be on some timer itself to achieve an effect of animation. The CameraViewTest demonstrates how to do that. The effect to the user will be a bunch of moving blurry tiny circles.
Fog on the cheap!

Birdasaur
  • 736
  • 7
  • 10