我需要创建一个100fps的动画,它可以显示包含每秒100帧的文件的3d数据。但javaFx中的AnimationTimer只允许我获得60fps。如何克服它。
非常感谢。
答案 0 :(得分:6)
删除JavaFX帧率上限
您可以通过设置系统属性(例如
)来删除60fps JavaFX帧速率上限java -Djavafx.animation.fullspeed=true MyApp
这是undocumented and unsupported setting。
删除JavaFX帧速率上限可能会使您的应用程序在资源使用方面效率大大降低(例如,没有帧速率上限的JavaFX应用程序将比具有帧速率上限的应用程序消耗更多CPU)。
配置JavaFX帧率上限
此外,您还可以尝试另一种未记录的系统属性:
javafx.animation.framerate
我没试过。
调试JavaFX帧(脉冲)
您可以启用other settings like -Djavafx.pulseLogger=true
来帮助您调试JavaFX体系结构并验证您的应用程序实际上是否以您期望的帧速率运行。
JavaFX 8有一个脉冲记录器(
-Djavafx.pulseLogger=true
系统属性),它可以打印出很多废话" (以一种很好的方式)关于JavaFX引擎的执行。在每个脉冲的基础上提供了许多信息,包括脉冲数(自动递增的整数),脉冲持续时间和自上一次脉冲以来的时间。该信息还包括线程详细信息和事件详细信息。这些数据允许开发人员查看大部分时间的内容。
警告强>
使用未记录的功能的正常警告适用,如Richard Bair from the JavaFX team注意:
请注意,如果我们没有记录命令行开关,那么在后续版本中删除/修改它们是公平的游戏: - )
答案 1 :(得分:0)
底线是JavaFX目前的目标(即最大)帧速率为60fps;所以你每秒最多只能显示60帧。因此,假设您可以从文件中读取帧并快速处理它们,那么如果您使用JavaFX,则必须跳过文件中的某些帧。
我尝试的基本方法如下:
创建BlockingQueue<Image>
来存储框架。您将需要调整此队列的容量:太大而且内存不足,太小而您可能最终等待图像可用时间过长。
创建一个后台线程,从您的文件中读取,创建图像,并尽快将它们推送到队列。
创建一个周期为10毫秒的ScheduledService
,从队列中获取图像并将其放在AtomicReference<Image>
中。如果原子引用的当前值为null
,则在FX Application线程上安排调用以在原子引用中显示图像,并将其替换为null
。这将确保您不会更快地使FX应用程序线程充满呼叫,而不是处理它们。
出于性能原因,您可能需要使用除Image
之外的其他策略,但一般时序和线程策略应该有效。
一些代码:
final Duration frameFrequency = Duration.millis(10)
final int queueCapacity = 8 ; // may need tuning
BlockingQueue<Image> frameQueue = new ArrayBlockingQueue<>(queueCapacity);
AtomicReference<Image> nextFrame = new AtomicReference<>();
ImageView display = new ImageView();
Thread fileReadThread = new Thread(() -> {
// pseudocode...
while (moreImagesToRead()) {
Image image = readImageFromFile();
frameQueue.put(image);
}
});
fileReadThread.setDaemon(true);
fileReadThread.start();
ScheduledService<Void> service = new ScheduledService<Void>(frameFrequency) {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
public Void call() throws InterruptedException {
Image image = frameQueue.take();
if (nextFrame.getAndSet(image) == null) {
Platform.runLater(() -> {
Image img = nextFrame.getAndSet(null);
// display img:
display.setImage(img);
});
}
}
};
}
};
service.start();
请注意,ScheduledService
并不保证每10毫秒精确运行一次,因此如果绝对精度很重要,则需要其他技术。但是,如上所述,您无论如何都无法实际显示所有帧,或以超过60fps的速度显示它们。
答案 2 :(得分:0)
Fullspeed = true会在没有控制的情况下为您提供较高的帧速率(并由于渲染过多而降低了应用程序的性能),帧速率确实无法正常工作。 使用:
-Djavafx.animation.pulse=value
您可以使用以下代码检查帧率。我通过将脉搏频率设置为2、60和120(我有一个240Hz的显示器)来检查它是否也确实起作用,您会发现随机数变化的速度有所不同。
private final long[] frameTimes = new long[100];
private int frameTimeIndex = 0 ;
private boolean arrayFilled = false ;
Label label = new Label();
root.getChildren().add(label);
AnimationTimer frameRateMeter = new AnimationTimer() {
@Override
public void handle(long now) {
long oldFrameTime = frameTimes[frameTimeIndex] ;
frameTimes[frameTimeIndex] = now ;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
if (frameTimeIndex == 0) {
arrayFilled = true ;
}
if (arrayFilled) {
long elapsedNanos = now - oldFrameTime ;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
label.setText(String.format("Current frame rate: %.3f" +", Random number:" + Math.random(), frameRate));
}
}
};
frameRateMeter.start();