Fixed merge-related bugs
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package visualiser.layout;
|
||||
|
||||
import com.sun.corba.se.impl.orbutil.graph.Graph;
|
||||
import javafx.scene.shape.Box;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.scene.shape.Sphere;
|
||||
import shared.model.GPSCoordinate;
|
||||
import visualiser.model.GraphCoordinate;
|
||||
import visualiser.utils.GPSConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class that creates a 3d boundary based on gps coordinates
|
||||
*/
|
||||
public class Boundary3D {
|
||||
|
||||
public static double thickness = 1;
|
||||
private List<Subject3D> boundaryNodes = new ArrayList<>();
|
||||
private List<Subject3D> boundaryConnectors = new ArrayList<>();
|
||||
private GPSConverter gpsConverter;
|
||||
|
||||
public Boundary3D(List<GPSCoordinate> points, GPSConverter gpsConverter){
|
||||
this.gpsConverter = gpsConverter;
|
||||
setBoundaryNodes(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits up the list so that it generates a edge of the boundary
|
||||
* @param points boundary gpscoordinate
|
||||
*/
|
||||
private void setBoundaryNodes(List<GPSCoordinate> points){
|
||||
if (points.size() < 2){
|
||||
return;
|
||||
}
|
||||
System.out.println(points.size());
|
||||
for (int i = 0; i < points.size(); i++){
|
||||
if (i + 1 != points.size()){
|
||||
addBound(points.get(i), points.get(i + 1));
|
||||
} else {
|
||||
addBound(points.get(i), points.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a two point boundary this will create a sphere at coord1 and a line to coord 2
|
||||
* this is to reduce double up (2 spheres in one point).
|
||||
* @param coord1 point to make sphere and start the line.
|
||||
* @param coord2 point to end the line.
|
||||
*/
|
||||
private void addBound(GPSCoordinate coord1, GPSCoordinate coord2){
|
||||
GraphCoordinate graphCoord1 = gpsConverter.convertGPS(coord1);
|
||||
GraphCoordinate graphCoord2 = gpsConverter.convertGPS(coord2);
|
||||
GraphCoordinate avgCoord = new GraphCoordinate((graphCoord1.getX() + graphCoord2.getX()) / 2,
|
||||
(graphCoord1.getY() + graphCoord2.getY()) / 2);
|
||||
|
||||
double a = (graphCoord1.getX() - graphCoord2.getX());
|
||||
double b = (graphCoord1.getY() - graphCoord2.getY());
|
||||
double c = Math.sqrt(a * a + b * b);
|
||||
|
||||
|
||||
Subject3D bound1 = new Subject3D(new Sphere(thickness * 2));
|
||||
bound1.setX(graphCoord1.getX());
|
||||
bound1.setZ(graphCoord1.getY());
|
||||
boundaryNodes.add(bound1);
|
||||
|
||||
Subject3D connector = new Subject3D(new Box(c, thickness, thickness));
|
||||
connector.setX(avgCoord.getX());
|
||||
connector.setZ(avgCoord.getY());
|
||||
double angle = 90 + Math.toDegrees(GPSConverter.getAngle(graphCoord2, graphCoord1));
|
||||
connector.setHeading(angle);
|
||||
|
||||
boundaryConnectors.add(connector);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the 3d objects to draw
|
||||
* @return 3d boundary to draw
|
||||
*/
|
||||
public List<Subject3D> getBoundaryNodes(){
|
||||
//these two must be concatenated with nodes after connectors else the spheres will not overlap the lines
|
||||
ArrayList<Subject3D> result = new ArrayList<>(boundaryConnectors);
|
||||
result.addAll(boundaryNodes);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package visualiser.layout;
|
||||
|
||||
import com.sun.javafx.geom.PickRay;
|
||||
import com.sun.javafx.scene.input.PickResultChooser;
|
||||
import com.sun.javafx.sg.prism.NGNode;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.shape.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 3D plane
|
||||
*/
|
||||
public class Plane3D extends TriangleMesh{
|
||||
|
||||
/**
|
||||
* Length is up down, and width is left right. Drawn on the x-y plane with z kept at 0.
|
||||
* @param width width of the plane
|
||||
* @param length length of the plane
|
||||
* @param subdivisionsWidth number of divisions along the width of the plane
|
||||
* @param subdivisionsLength number of division along the length of the plane
|
||||
*/
|
||||
public Plane3D(float width, float length, int subdivisionsWidth, int subdivisionsLength){
|
||||
//add texture points and vertex points
|
||||
float subWidth = width / (float) subdivisionsWidth;
|
||||
float subLength = length / (float) subdivisionsLength;
|
||||
|
||||
ArrayList<Float> pointsList = new ArrayList<>();
|
||||
ArrayList<Float> textureCoord = new ArrayList<>();
|
||||
float startW = -width/2;
|
||||
float startL = -length/2;
|
||||
|
||||
for (float l = 0; l <= length; l += subLength) {
|
||||
for (float w = 0; w <= width; w += subWidth){
|
||||
//add points
|
||||
pointsList.add(w + startW);
|
||||
pointsList.add(l + startL);
|
||||
pointsList.add(0f);
|
||||
//addTexture coords
|
||||
textureCoord.add(1 - w/width);
|
||||
textureCoord.add(1 - l/length);
|
||||
}
|
||||
}
|
||||
|
||||
this.getPoints().setAll(copyListToArray(pointsList));
|
||||
this.getTexCoords().setAll(copyListToArray(textureCoord));
|
||||
|
||||
//connect points to make faces
|
||||
ArrayList<Integer> faces = new ArrayList<>();
|
||||
|
||||
int listSize = pointsList.size()/3;
|
||||
int divsInRow = subdivisionsWidth + 1;
|
||||
for (int i = 0; i < listSize; i++){
|
||||
int row = i/divsInRow;
|
||||
|
||||
if (row < 1){
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean notFirstCol = (i) % divsInRow != 0;
|
||||
boolean notLastCol = (i + 1) % divsInRow != 0;
|
||||
if (notFirstCol){
|
||||
faces.add(i);
|
||||
faces.add(i);
|
||||
// printPointAtIndex(i);
|
||||
faces.add(i - divsInRow);
|
||||
faces.add(i - divsInRow);
|
||||
// printPointAtIndex(i - divsInRow);
|
||||
faces.add(i - 1);
|
||||
faces.add(i - 1);
|
||||
// printPointAtIndex(i-1);
|
||||
}
|
||||
if (notLastCol) {
|
||||
faces.add(i - divsInRow + 1);
|
||||
faces.add(i - divsInRow + 1);
|
||||
// printPointAtIndex(i - divsInRow + 1);
|
||||
faces.add(i - divsInRow);
|
||||
faces.add(i - divsInRow);
|
||||
// printPointAtIndex(i - divsInRow);
|
||||
faces.add(i);
|
||||
faces.add(i);
|
||||
// printPointAtIndex(i);
|
||||
}
|
||||
|
||||
}
|
||||
this.getFaces().setAll(copyListToIntArray(faces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing function to see if the points are correct
|
||||
* @param index index that the points correspond to (remember 3 is a point)
|
||||
*/
|
||||
private void printPointAtIndex(int index){
|
||||
int i = index * 3;
|
||||
float x = this.getPoints().get(i);
|
||||
float y = this.getPoints().get(i + 1);
|
||||
float z = this.getPoints().get(i + 2);
|
||||
System.out.println(String.format("Point at %d is x:%f, y:%f, z:%f", index, x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* copies the list to a float array because java List.toArray isn't working
|
||||
* @param list list to copy
|
||||
* @return array
|
||||
*/
|
||||
private static float[] copyListToArray(List<Float> list){
|
||||
float[] res = new float[list.size()];
|
||||
for (int i = 0; i < list.size(); i++){
|
||||
res[i] = list.get(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* copies the list to an integer array because java List.toArray isn't working
|
||||
* @param list list to copy
|
||||
* @return array
|
||||
*/
|
||||
private static int[] copyListToIntArray(List<Integer> list){
|
||||
int[] res = new int[list.size()];
|
||||
for (int i = 0; i < list.size(); i++){
|
||||
res[i] = list.get(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package visualiser.layout;
|
||||
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.PixelWriter;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.Box;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.shape.Shape3D;
|
||||
import javafx.scene.shape.TriangleMesh;
|
||||
import visualiser.utils.PerlinNoiseGenerator;
|
||||
|
||||
/**
|
||||
* Creates a SeaSurface
|
||||
*/
|
||||
public class SeaSurface extends Subject3D {
|
||||
/**
|
||||
* Sea Surface Constructor
|
||||
* @param size size of the sea surface (has to be square for simplicity's sake)
|
||||
* @param freq frequency the perlin noise is to be generated at
|
||||
*/
|
||||
public SeaSurface(int size, double freq){
|
||||
super(createSurface(size, freq));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the sea surface
|
||||
*/
|
||||
private static Shape3D createSurface(int size, double freq){
|
||||
float[][] noiseArray = PerlinNoiseGenerator.createNoise(size, freq);
|
||||
Image diffuseMap = createImage(noiseArray.length, noiseArray);
|
||||
|
||||
PhongMaterial material = new PhongMaterial();
|
||||
material.setDiffuseMap(diffuseMap);
|
||||
|
||||
Plane3D seaPlane = new Plane3D(noiseArray.length, noiseArray.length, 10, 10);
|
||||
MeshView seaSurface = new MeshView(seaPlane);
|
||||
seaSurface.setMaterial(material);
|
||||
seaSurface.setMouseTransparent(true);
|
||||
seaSurface.toFront();
|
||||
|
||||
return seaSurface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create texture for uv mapping
|
||||
* @param size size of the image to make
|
||||
* @param noise array of noise
|
||||
* @return image that is created
|
||||
*/
|
||||
private static Image createImage(double size, float[][] noise) {
|
||||
|
||||
int width = (int) size;
|
||||
int height = (int) size;
|
||||
|
||||
WritableImage wr = new WritableImage(width, height);
|
||||
PixelWriter pw = wr.getPixelWriter();
|
||||
//interpolate colours based on noise
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
|
||||
float value = noise[x][y];
|
||||
|
||||
double gray = normalizeValue(value, -.5, .5, 0., 1.);
|
||||
|
||||
gray = clamp(gray, 0, 1);
|
||||
|
||||
//values to interpolate on
|
||||
Color brightBlue = new Color(0.06, 0.5, .78, 1);
|
||||
Color lightBlue = new Color(0.15, 0.68, .88, 1);
|
||||
Color lighterBlue = new Color(0.28, 0.73, .91, 1);
|
||||
|
||||
Color colour = Color.WHITE.interpolate(brightBlue, gray).interpolate(lighterBlue, gray).interpolate(lightBlue, gray);
|
||||
|
||||
pw.setColor(x, y, colour);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return wr;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Nomalises the values so that the colours are correct
|
||||
* @param value value to normalise
|
||||
* @param min current min
|
||||
* @param max current max
|
||||
* @param newMin new min
|
||||
* @param newMax new max
|
||||
* @return returns normalised value
|
||||
*/
|
||||
private static double normalizeValue(double value, double min, double max, double newMin, double newMax) {
|
||||
|
||||
return (value - min) * (newMax - newMin) / (max - min) + newMin;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* clamps a value between a min and max
|
||||
* @param value value to clamp
|
||||
* @param min minimum value it can be
|
||||
* @param max maximum value it can be
|
||||
* @return result after clamp
|
||||
*/
|
||||
private static double clamp(double value, double min, double max) {
|
||||
|
||||
if (Double.compare(value, min) < 0)
|
||||
return min;
|
||||
|
||||
if (Double.compare(value, max) > 0)
|
||||
return max;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent rescaling of sea surface
|
||||
* @param scale ignored
|
||||
*/
|
||||
@Override
|
||||
public void setScale(double scale) {}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package visualiser.layout;
|
||||
|
||||
import javafx.geometry.Point3D;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.PixelWriter;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.PhongMaterial;
|
||||
import javafx.scene.shape.MeshView;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import visualiser.utils.PerlinNoiseGenerator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Creates a skyBox
|
||||
*/
|
||||
public class SkyBox {
|
||||
private int size;
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private double freq;
|
||||
private List<Subject3D> skyBoxPlanes = new ArrayList<>();
|
||||
|
||||
public SkyBox(int edgeLength, double freq, double x, double y, double z) {
|
||||
this.size = edgeLength;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.freq = freq;
|
||||
makeSkyBox();
|
||||
}
|
||||
|
||||
private void makeSkyBox() {
|
||||
addTop();
|
||||
addFront();
|
||||
addBack();
|
||||
addLeft();
|
||||
addRight();
|
||||
addSeaOverlay();
|
||||
}
|
||||
|
||||
private void addTop() {
|
||||
MeshView surface = makeSurface(new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/skyTop.png")));
|
||||
|
||||
surface.setRotationAxis(new Point3D(0, 0, 1));
|
||||
surface.setRotate(180);
|
||||
|
||||
surface.setTranslateX(x);
|
||||
surface.setTranslateY(y - size + 1);
|
||||
surface.setTranslateZ(z);
|
||||
|
||||
Subject3D top = new Subject3D(surface);
|
||||
skyBoxPlanes.add(top);
|
||||
}
|
||||
|
||||
private void addRight() {
|
||||
MeshView surface = makeSurface(new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/skyRight.png")));
|
||||
|
||||
surface.setTranslateX(size/2);
|
||||
surface.setTranslateY(size/2);
|
||||
surface.setRotationAxis(new Point3D(1, 0, 0));
|
||||
surface.setRotate(90);
|
||||
surface.setTranslateX(-size/2);
|
||||
surface.setTranslateY(-size/2);
|
||||
|
||||
surface.setTranslateX(x);
|
||||
surface.setTranslateY(y - size/2);
|
||||
surface.setTranslateZ(z + size/2 - 1);
|
||||
|
||||
|
||||
Subject3D right = new Subject3D(surface);
|
||||
skyBoxPlanes.add(right);
|
||||
}
|
||||
|
||||
private void addLeft() {
|
||||
MeshView surface = makeSurface(new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/skyLeft.png")));
|
||||
|
||||
surface.setTranslateX(size/2);
|
||||
surface.setTranslateY(size/2);
|
||||
surface.setRotationAxis(new Point3D(1, 0, 0));
|
||||
surface.setRotate(-90);
|
||||
surface.setTranslateX(-size/2);
|
||||
surface.setTranslateY(-size/2);
|
||||
|
||||
surface.setScaleX(-1);
|
||||
surface.setScaleZ(-1);
|
||||
|
||||
surface.setTranslateX(x);
|
||||
surface.setTranslateY(y - size/2);
|
||||
surface.setTranslateZ(z - size/2 + 1);
|
||||
|
||||
|
||||
Subject3D left = new Subject3D(surface);
|
||||
skyBoxPlanes.add(left);
|
||||
}
|
||||
|
||||
private void addBack() {
|
||||
MeshView surface = makeSurface(new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/skyBack.png")));
|
||||
surface.getTransforms().add(new Rotate(90, 0, 0));
|
||||
|
||||
surface.setRotationAxis(new Point3D(1, 0, 0));
|
||||
surface.setRotate(-90);
|
||||
|
||||
surface.setScaleY(-1);
|
||||
surface.setScaleZ(-1);
|
||||
|
||||
surface.setTranslateX(x - size/2 + 1);
|
||||
surface.setTranslateY(y - size/2);
|
||||
surface.setTranslateZ(z);
|
||||
|
||||
Subject3D back = new Subject3D(surface);
|
||||
skyBoxPlanes.add(back);
|
||||
}
|
||||
|
||||
private void addFront() {
|
||||
MeshView surface = makeSurface(new Image(getClass().getClassLoader().getResourceAsStream("images/skybox/skyFront.png")));
|
||||
|
||||
surface.setTranslateX(size/2);
|
||||
surface.setTranslateY(size/2);
|
||||
surface.setRotationAxis(new Point3D(0, 0, 1));
|
||||
surface.setRotate(-90);
|
||||
surface.setTranslateX(-size/2);
|
||||
surface.setTranslateY(-size/2);
|
||||
|
||||
surface.setTranslateX(x + size/2 - 1);
|
||||
surface.setTranslateY(y - size/2);
|
||||
surface.setTranslateZ(z);
|
||||
|
||||
Subject3D front = new Subject3D(surface);
|
||||
skyBoxPlanes.add(front);
|
||||
}
|
||||
|
||||
private MeshView makeSurface(Image diffuseMap) {
|
||||
|
||||
PhongMaterial material = new PhongMaterial();
|
||||
//material.setDiffuseColor(Color.BLUE);
|
||||
material.setDiffuseMap(diffuseMap);
|
||||
//material.setSpecularColor(Color.WHITE);
|
||||
|
||||
Plane3D plane = new Plane3D(size, size, 10, 10);
|
||||
MeshView surface = new MeshView(plane);
|
||||
surface.setMaterial(material);
|
||||
surface.setMouseTransparent(true);
|
||||
return surface;
|
||||
}
|
||||
|
||||
private void addSeaOverlay() {
|
||||
SeaSurface seaSurface = new SeaSurface(size * 3, freq);
|
||||
seaSurface.setX(x);
|
||||
seaSurface.setY(y - size/4 + 1);
|
||||
seaSurface.setZ(z);
|
||||
skyBoxPlanes.add(seaSurface);
|
||||
}
|
||||
|
||||
public List<Subject3D> getSkyBoxPlanes() {
|
||||
return skyBoxPlanes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package visualiser.layout;
|
||||
|
||||
import javafx.scene.shape.Shape3D;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Scale;
|
||||
import javafx.scene.transform.Translate;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,8 @@ public class Subject3D {
|
||||
*/
|
||||
private Rotate heading;
|
||||
|
||||
private Scale scale;
|
||||
|
||||
/**
|
||||
* Constructor for view subject wrapper
|
||||
* @param mesh to be rendered
|
||||
@@ -34,10 +37,11 @@ public class Subject3D {
|
||||
public Subject3D(Shape3D mesh, int sourceID) {
|
||||
this.mesh = mesh;
|
||||
this.sourceID = sourceID;
|
||||
this.scale = new Scale();
|
||||
this.position = new Translate();
|
||||
this.heading = new Rotate(0, Rotate.Y_AXIS);
|
||||
|
||||
this.mesh.getTransforms().addAll(position, heading, new Rotate(90, Rotate.X_AXIS), new Rotate(180, Rotate.Y_AXIS));
|
||||
this.mesh.getTransforms().addAll(position, scale, heading, new Rotate(90, Rotate.X_AXIS), new Rotate(180, Rotate.Y_AXIS));
|
||||
}
|
||||
|
||||
public Shape3D getMesh() {
|
||||
@@ -56,6 +60,12 @@ public class Subject3D {
|
||||
return heading;
|
||||
}
|
||||
|
||||
public void setScale(double scale) {
|
||||
this.scale.setX(scale);
|
||||
this.scale.setY(scale);
|
||||
this.scale.setZ(scale);
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
position.setX(x);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ package visualiser.layout;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.PerspectiveCamera;
|
||||
import javafx.scene.SubScene;
|
||||
import javafx.scene.*;
|
||||
import javafx.scene.input.PickResult;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
@@ -89,12 +87,17 @@ public class View3D extends Pane {
|
||||
/**
|
||||
* Distance to switch from third person to bird's eye
|
||||
*/
|
||||
private double THIRD_PERSON_LIMIT = 100;
|
||||
private final double THIRD_PERSON_LIMIT = 100;
|
||||
/**
|
||||
* Distance to stop zoom
|
||||
*/
|
||||
private final double FIRST_PERSON_LIMIT = 2;
|
||||
|
||||
/**
|
||||
* Default constructor for View3D. Sets up Scene and PerspectiveCamera.
|
||||
* @param fill whether or not to fill the background of the view.
|
||||
*/
|
||||
public View3D() {
|
||||
public View3D(boolean fill) {
|
||||
this.world = new Group();
|
||||
this.shapeMap = new HashMap<>();
|
||||
this.sourceMap = new HashMap<>();
|
||||
@@ -103,13 +106,18 @@ public class View3D extends Pane {
|
||||
|
||||
scene.widthProperty().bind(this.widthProperty());
|
||||
scene.heightProperty().bind(this.heightProperty());
|
||||
scene.setFill(new Color(0.2, 0.6, 1, 1));
|
||||
|
||||
if (fill) {
|
||||
scene.setFill(new Color(0.2, 0.6, 1, 1));
|
||||
}
|
||||
scene.setCamera(buildCamera());
|
||||
|
||||
this.getChildren().add(scene);
|
||||
}
|
||||
|
||||
public View3D(){
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up camera view frustum and binds transformations
|
||||
* @return perspective camera
|
||||
@@ -169,11 +177,37 @@ public class View3D extends Pane {
|
||||
scene.setOnMousePressed(e -> {
|
||||
PickResult result = e.getPickResult();
|
||||
if(result != null && result.getIntersectedNode() != null && result.getIntersectedNode() instanceof Shape3D) {
|
||||
untrackSubject();
|
||||
trackSubject(shapeMap.get(result.getIntersectedNode()));
|
||||
setThirdPerson();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures camera to third person view
|
||||
*/
|
||||
public void setThirdPerson() {
|
||||
this.setDistance(THIRD_PERSON_LIMIT / 2);
|
||||
this.setPitch(10);
|
||||
|
||||
for(Subject3D item: items) {
|
||||
item.setScale(0.1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures camera to bird's eye view
|
||||
*/
|
||||
public void setBirdsEye() {
|
||||
this.setYaw(0);
|
||||
this.setPitch(60);
|
||||
|
||||
for(Subject3D item: items) {
|
||||
item.setScale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop camera from following the last selected subject
|
||||
*/
|
||||
@@ -191,7 +225,6 @@ public class View3D extends Pane {
|
||||
* @param subject to track
|
||||
*/
|
||||
private void trackSubject(Subject3D subject) {
|
||||
untrackSubject();
|
||||
target = subject;
|
||||
|
||||
updatePivot(target.getPosition());
|
||||
@@ -201,9 +234,6 @@ public class View3D extends Pane {
|
||||
target.getPosition().yProperty().addListener(pivotY);
|
||||
target.getPosition().zProperty().addListener(pivotZ);
|
||||
target.getHeading().angleProperty().addListener(pivotHeading);
|
||||
|
||||
this.setDistance(THIRD_PERSON_LIMIT);
|
||||
this.setPitch(20);
|
||||
}
|
||||
|
||||
public void setNearClip(double nearClip) {
|
||||
@@ -241,13 +271,12 @@ public class View3D extends Pane {
|
||||
public void updateDistance(double delta) {
|
||||
double distance = -this.distance.getZ() + delta;
|
||||
|
||||
if(distance <= 0) {
|
||||
this.setDistance(0);
|
||||
if(distance <= FIRST_PERSON_LIMIT) {
|
||||
this.setDistance(FIRST_PERSON_LIMIT);
|
||||
} else if(distance > THIRD_PERSON_LIMIT) {
|
||||
untrackSubject();
|
||||
this.setYaw(0);
|
||||
this.setPitch(60);
|
||||
this.setDistance(distance);
|
||||
untrackSubject();
|
||||
setBirdsEye();
|
||||
} else {
|
||||
this.setDistance(distance);
|
||||
}
|
||||
@@ -268,4 +297,12 @@ public class View3D extends Pane {
|
||||
public void setPitch(double pitch) {
|
||||
this.pitch.setAngle(-pitch);
|
||||
}
|
||||
|
||||
public void addAmbientLight(AmbientLight ambientLight) {
|
||||
this.world.getChildren().add(ambientLight);
|
||||
}
|
||||
|
||||
public void addPointLight(PointLight pointLight) {
|
||||
this.world.getChildren().add(pointLight);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user