JavaFX中的水2D波效应

时间:2013-06-06 11:48:40

标签: javafx-2

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

2 个答案:

答案 0 :(得分:3)

这是将旧太阳JavaFX 1纹波发生器的部分转换为JavaFX 2。

ripples

这不是最真实的水波纹效果,但也许它足以让你开始创建自己的水波纹效果。您可以添加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鱼模拟器代码来自a jfrog repository(如果单击它可能不再存在)。

RobertLadstätter为JavaFX 2创建了一个2D water effect sample animation(使用Scala)。罗伯茨动画就像从侧面而不是从上方观察水,但也许一些概念可能对你有帮助。

答案 1 :(得分:0)

this教程中,您可以找到如何为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();
    }
}

我希望它有所帮助。