2

如何在 JavaFX 中实现水 2D 波浪效果,我有图像并且想要当单击图像时,波浪(或更多)开始从该点扩展,就像我们将一块岩石放入平静的水中并看到波浪一样扩大。

4

2 回答 2

3

这是将旧 sun JavaFX 1 波纹生成器的部分转换为 JavaFX 2。

涟漪

这不是最逼真的水波纹效果,但也许足以让您开始创建自己的效果。你可以添加一个DisplacementMap效果来扭曲你的图像作为“波浪”的结果。

该代码使用 JavaFX 动画时间线来生成随着时间逐渐消失的不断扩大的同心圆。

import javafx.animation.*;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.*;
import javafx.scene.shape.Circle;
import javafx.stage.*;
import javafx.util.Duration;

public class FishSim extends Application {
  private static final Paint SCENE_FILL = new RadialGradient(
    0, 0, 300, 300, 500, false, CycleMethod.NO_CYCLE, 
    FXCollections.observableArrayList(new Stop(0, Color.BLACK), new Stop(1, Color.BLUE))
  );

  @Override public void start(Stage stage) {
    final RippleGenerator rippler = new RippleGenerator();

    final Scene scene = new Scene(rippler, 600, 400, SCENE_FILL);

    scene.setOnMousePressed(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent event) {
        rippler.setGeneratorCenterX(event.getSceneX());
        rippler.setGeneratorCenterY(event.getSceneY());
        rippler.createRipple();
        rippler.startGenerating();
      }
    });

    scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent event) {
        rippler.setGeneratorCenterX(event.getSceneX());
        rippler.setGeneratorCenterY(event.getSceneY());
      }
    });

    scene.setOnMouseReleased(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent event) {
        rippler.stopGenerating();
      }
    });

    stage.setTitle("Click, hold mouse button down and move around to create ripples");
    stage.setScene(scene);
    stage.setResizable(false);

    stage.show();
  }

  public static void main(String[] args) { launch(args); }
}

/**
 * Generates ripples on the screen every 0.5 seconds or whenever
 * the createRipple method is called. Ripples grow and fade out
 * over 3 seconds
 */
class RippleGenerator extends Group {
  private class Ripple extends Circle {
    Timeline animation = new Timeline(
      new KeyFrame(Duration.ZERO,       new KeyValue(radiusProperty(),  0)),
      new KeyFrame(Duration.seconds(1), new KeyValue(opacityProperty(), 1)),
      new KeyFrame(Duration.seconds(3), new KeyValue(radiusProperty(),  100)),
      new KeyFrame(Duration.seconds(3), new KeyValue(opacityProperty(), 0))
    );

    private Ripple(double centerX, double centerY) {
      super(centerX, centerY, 0, null);
      setStroke(Color.rgb(200, 200, 255));
    }
  }

  private double generatorCenterX = 100.0;
  private double generatorCenterY = 100.0;

  private Timeline generate = new Timeline(
      new KeyFrame(Duration.seconds(0.5), new EventHandler<ActionEvent>() {
        @Override public void handle(ActionEvent event) {
          createRipple();
        }
      }
    )
  );

  public RippleGenerator() {
    generate.setCycleCount(Timeline.INDEFINITE);
  }

  public void createRipple() {
    final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY);
    getChildren().add(ripple);
    ripple.animation.play();

    Timeline remover = new Timeline(
      new KeyFrame(Duration.seconds(3), new EventHandler<ActionEvent>() {
        @Override public void handle(ActionEvent event) {
          getChildren().remove(ripple);
          ripple.animation.stop(); 
        }
      })  
    );
    remover.play();
  }

  public void startGenerating() {
    generate.play();
  }

  public void stopGenerating() {
    generate.stop();
  }

  public void setGeneratorCenterX(double generatorCenterX) {
    this.generatorCenterX = generatorCenterX;
  }

  public void setGeneratorCenterY(double generatorCenterY) {
    this.generatorCenterY = generatorCenterY;
  }
}

转换所基于的原始 JavaFX 1 鱼模拟器代码来自jfrog 存储库(如果单击它可能不再存在)。

Robert Ladstätter为 JavaFX 2(使用 Scala)创建了一个2D 水效果示例动画。罗伯茨动画就像从侧面而不是从上面看水,但也许其中一些概念可能会对您有所帮助。

于 2013-06-06T23:27:06.547 回答
0

教程中,您可以了解如何将自定义GLSL/HLSL像素着色器用于JavaFX. 以及 HLSL 形式的 screenSpace 中的简单失真程序波的代码:

uniform extern texture ScreenTexture;    

sampler ScreenS = sampler_state
{
    Texture = <ScreenTexture>;    
};

float wave;                // pi/.75 is a good default
float distortion;        // 1 is a good default
float2 centerCoord;        // 0.5,0.5 is the screen center

float4 PixelShader(float2 texCoord: TEXCOORD0) : COLOR
{
    float2 distance = abs(texCoord - centerCoord);
    float scalar = length(distance);

    // invert the scale so 1 is centerpoint
    scalar = abs(1 - scalar);

    // calculate how far to distort for this pixel    
    float sinoffset = sin(wave / scalar);
    sinoffset = clamp(sinoffset, 0, 1);

    // calculate which direction to distort
    float sinsign = cos(wave / scalar);    

    // reduce the distortion effect
    sinoffset = sinoffset * distortion/32;

    // pick a pixel on the screen for this pixel, based on
    // the calculated offset and direction
    float4 color = tex2D(ScreenS, texCoord+(sinoffset*sinsign));    

    return color;
}
technique
{
    pass P0
    {
        PixelShader = compile ps_2_0 PixelShader();
    }
}

我希望它有所帮助。

于 2013-06-06T12:44:14.567 回答