как бы вы рассчитали границы x и y области просмотра перспективной камеры в JavaFX? Метод camera.getBoundsInParent может использоваться для определения положения камеры, однако как вы можете использовать это положение для расчета размера окна просмотра камеры?
Вычисление области обзора камеры перспективы JavaFX
Ответы (1)
Согласно документации для PerspectiveCamera
:
По умолчанию эта камера расположена в центре сцены и смотрит вдоль положительной оси Z. Система координат, определяемая этой камерой, имеет начало в верхнем левом углу панели с осью Y, направленной вниз, и осью Z, направленной от зрителя (в экран).
Свойство fieldOfView
определяет угол подчиняется видимой части сцены камере, и по умолчанию этот угол составляет измерено по вертикали.
Наконец, по умолчанию
значение Z положения глаза регулируется в Z таким образом, что матрица проекции, сгенерированная с использованием указанного
fieldOfView
, будет создавать единицы с Z = 0 (плоскость проекции) в независимых от устройства пикселях, совпадающих с таковой дляParallelCamera
Другими словами, видимая часть сцены при Z = 0 имеет размер сцены в пиксельных координатах.
Итак, принимая эти значения по умолчанию, мы можем нарисовать следующую диаграмму:
Здесь точка слева представляет положение камеры по умолчанию. Прямоугольник - это видимая часть экрана в позиции z=0
. w
- ширина сцены, а h
- высота сцены (поэтому камера находится на (w/2, h/2, -z_c)
для некоторых z_c > 0
).
Линия от камеры, пересекающая верхний центр видимой части сцены при z = 0, продлевается на диаграмме до некоторой точки в верхнем центре видимой части сцены при произвольном значении z
. Легко видеть, что верхний треугольник представляет собой прямоугольный треугольник с высотой -y
и длиной z
, и он похож на прямоугольный треугольник, образованный от камеры к центру сцены в точке z=0
. Из-за похожих треугольников он имеет угол f/2
, где f
- угол поля зрения. Следовательно, для точки (w/2, y, z)
наверху видимой части сцены мы должны иметь
-y/z = tan(f/2)
or
y = -z tan(f/2)
Вы можете построить еще один треугольник внизу изображения и сделать вывод, что координата y
удовлетворяет
y = h + z tan(f/2)
Что касается ширины, просто обратите внимание, что пропорции видимой части сцены всегда находятся в соотношении w:h
, поэтому для точки (x, h/2, z)
в центре левого края видимой части сцены мы имеем
x = -z (w/h) tan(f/2)
и справа от видимой части сцены
x = w + z (w/h) tan(f/2)
Итак, вкратце, границы сцены простираются от
(-z (w/h) tan(f/2), -z tan(f/2))
в левом верхнем углу, чтобы
(w + z (w/h) tan(f/2), h + z tan(f/2))
в правом нижнем углу, где z
- z
-координата, w
ширина сцены, h
высота сцены и f
(вертикальный) угол поля зрения.
Вот демонстрация этого. Это четыре сферы, расположенные в центре вверху, в центре внизу, в центре слева и в центре справа видимой части сцены. z
-координаты всех четырех сфер анимируются (поэтому они удаляются от зрителя в z
-направлении, становясь меньше), а их x
- или y
-координаты привязаны так, чтобы они оставались на крайних уровнях видимого часть сцены. (Так, например, красная сфера анимируется вдоль гипотенузы прямоугольного треугольника в верхней части диаграммы выше, а другие сферы анимируются аналогичным образом.)
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PerspectiveCameraTest extends Application {
@Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
Scene scene = new Scene(pane, 800, 800, true);
PerspectiveCamera camera = new PerspectiveCamera();
camera.boundsInParentProperty().addListener((obs, oldB, newB) -> System.out.println(newB));
scene.setCamera(camera);
primaryStage.setScene(scene);
primaryStage.show();
Sphere top = new Sphere(40);
top.setMaterial(new PhongMaterial(Color.RED));
top.translateXProperty().bind(pane.widthProperty().divide(2));
top.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
double tanFOver2 = Math.tan(Math.toRadians(camera.getFieldOfView()/2));
return -top.getTranslateZ() * tanFOver2 ;
}, top.translateZProperty(), pane.heightProperty(), camera.fieldOfViewProperty()));
Sphere bottom = new Sphere(40);
bottom.setMaterial(new PhongMaterial(Color.BLUE));
bottom.translateXProperty().bind(pane.widthProperty().divide(2));
bottom.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
double tanFOver2 = Math.tan(Math.toRadians(camera.getFieldOfView()/2));
return scene.getHeight() + bottom.getTranslateZ() * tanFOver2 ;
}, bottom.translateZProperty(), pane.heightProperty(), camera.fieldOfViewProperty()));
bottom.translateZProperty().bind(top.translateZProperty());
Sphere left = new Sphere(40);
left.setMaterial(new PhongMaterial(Color.GREEN));
left.translateYProperty().bind(pane.heightProperty().divide(2));
left.translateXProperty().bind(Bindings.createDoubleBinding(() -> {
double tanFOver2 = Math.tan(Math.toRadians(camera.getFieldOfView()/2));
return -left.getTranslateZ() * tanFOver2 * pane.getWidth() / pane.getHeight();
}, left.translateZProperty(), pane.heightProperty(), pane.widthProperty(), camera.fieldOfViewProperty()));
left.translateZProperty().bind(top.translateZProperty());
Sphere right = new Sphere(40);
right.setMaterial(new PhongMaterial(Color.GOLD));
right.translateYProperty().bind(pane.heightProperty().divide(2));
right.translateXProperty().bind(Bindings.createDoubleBinding(() -> {
double tanFOver2 = Math.tan(Math.toRadians(camera.getFieldOfView()/2));
return pane.getWidth() + right.getTranslateZ() * tanFOver2 * pane.getWidth() / pane.getHeight() ;
}, right.translateZProperty(), pane.heightProperty(), pane.widthProperty(), camera.fieldOfViewProperty()));
right.translateZProperty().bind(top.translateZProperty());
TranslateTransition anim = new TranslateTransition(Duration.seconds(10), top);
anim.setByZ(5000);
anim.play();
pane.getChildren().addAll(top, bottom, left, right);
}
public static void main(String[] args) {
launch(args);
}
}
Если вы добавите камеру в сцену и переместите (и, возможно, поверните) ее, тогда геометрия станет значительно более сложной, хотя базовое изображение все равно останется прежним (только неудобно выровнять с осями). Подобные вычисления для более общего случая выходят за рамки сообщения на форуме (и оставлены в качестве упражнения для читателя ...).
fieldOfView
дает вам угол; вы можете вычислить это из этого. - person James_D   schedule 19.12.2017