如何在 JavaFX 3D 中创建雾?
How to create fog in JavaFX 3D?
我正在开发一个游戏,在 JavaFX 3D 中,玩家 运行 在漫长的道路上前进。他的路上有物品和障碍物。关键是:现在如果对象进入我的剪裁距离,它们就会突然出现。因此我想创建某种雾(或任何其他 "hides" 对象初始化)
问题是我找不到任何这样做的例子。我正在寻找 code/link 到 source/any 其他建议的示例。
话虽如此,这个问题太宽泛了,而且肯定有很多很多方法可以做到这一点,这里是一种可能的实现方式。这是 2D,但可以很容易地适应 3D 应用程序(我认为)。这个想法只是让一些浅灰色的圆圈在白色背景上四处漂浮,并对整个事物应用巨大的模糊。
然后您可以让您的对象以此为背景出现,并将它们从灰色淡化为真实颜色(或类似颜色)。圆圈的颜色和速度,以及模糊半径,可能需要一些调整...
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);
}
}
典型的 3D 系统使用粒子系统来执行此操作,其中涉及透明度、alpha 波动和广告牌纹理的组合。信不信由你 雾、烟和火焰……粒子效果……实际上根本不是 3D,而是经过定位、调整大小和着色以显示为 3D 的 2D 图像。然后它们以足够快的速度动画化,以至于人类观众无法分辨出 2D 图像的细微差别。
JavaFX 3D 的问题在于它不支持透明度 "yet"。(它是非官方可用的)。此外,没有粒子类型对象可以让您按照 James_D 的建议叠加形状和纹理,而无需手动管理相对于相机的定位。
但是还是有希望的……F(X)yz 项目提供了一个 BillBoard class,它允许您将图像垂直于相机放置。您可以使用定时器和一些 Random.next() 类型的 Circle creations 快速更新此图像,使用建议的方法 James_D。 BillBoardBehaviourTest 和 CameraViewTest 中有一个以这种方式使用 BillBoard 的示例。性能在 CameraViewTest 中展示。
如果我是你,我会做的是在你的平截头体的后 -Z 位置(对象进入场景的位置)设置一个大的平截头体宽 BillBoard 对象,然后在屏幕外的窗格中设置一个 Timer/Random 圆生成器。然后使用 CameraViewTest 中的方法,对屏幕外窗格(具有圆圈)进行快照,然后将该图像设置为 BillBoard。您必须让 SnapShot 调用在某个计时器本身上才能实现动画效果。 CameraViewTest 演示了如何执行此操作。对用户的影响将是一堆移动模糊的小圆圈。
便宜的雾!
我正在开发一个游戏,在 JavaFX 3D 中,玩家 运行 在漫长的道路上前进。他的路上有物品和障碍物。关键是:现在如果对象进入我的剪裁距离,它们就会突然出现。因此我想创建某种雾(或任何其他 "hides" 对象初始化)
问题是我找不到任何这样做的例子。我正在寻找 code/link 到 source/any 其他建议的示例。
话虽如此,这个问题太宽泛了,而且肯定有很多很多方法可以做到这一点,这里是一种可能的实现方式。这是 2D,但可以很容易地适应 3D 应用程序(我认为)。这个想法只是让一些浅灰色的圆圈在白色背景上四处漂浮,并对整个事物应用巨大的模糊。
然后您可以让您的对象以此为背景出现,并将它们从灰色淡化为真实颜色(或类似颜色)。圆圈的颜色和速度,以及模糊半径,可能需要一些调整...
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);
}
}
典型的 3D 系统使用粒子系统来执行此操作,其中涉及透明度、alpha 波动和广告牌纹理的组合。信不信由你 雾、烟和火焰……粒子效果……实际上根本不是 3D,而是经过定位、调整大小和着色以显示为 3D 的 2D 图像。然后它们以足够快的速度动画化,以至于人类观众无法分辨出 2D 图像的细微差别。
JavaFX 3D 的问题在于它不支持透明度 "yet"。(它是非官方可用的)。此外,没有粒子类型对象可以让您按照 James_D 的建议叠加形状和纹理,而无需手动管理相对于相机的定位。
但是还是有希望的……F(X)yz 项目提供了一个 BillBoard class,它允许您将图像垂直于相机放置。您可以使用定时器和一些 Random.next() 类型的 Circle creations 快速更新此图像,使用建议的方法 James_D。 BillBoardBehaviourTest 和 CameraViewTest 中有一个以这种方式使用 BillBoard 的示例。性能在 CameraViewTest 中展示。
如果我是你,我会做的是在你的平截头体的后 -Z 位置(对象进入场景的位置)设置一个大的平截头体宽 BillBoard 对象,然后在屏幕外的窗格中设置一个 Timer/Random 圆生成器。然后使用 CameraViewTest 中的方法,对屏幕外窗格(具有圆圈)进行快照,然后将该图像设置为 BillBoard。您必须让 SnapShot 调用在某个计时器本身上才能实现动画效果。 CameraViewTest 演示了如何执行此操作。对用户的影响将是一堆移动模糊的小圆圈。
便宜的雾!