Implement code and GUI elements for updating the rotation of objects

pull/35/head
James Ball 2021-05-17 19:54:27 +01:00
rodzic dcf15df8d6
commit 04dc9cb868
7 zmienionych plików z 82 dodań i 35 usunięć

Wyświetl plik

@ -79,6 +79,7 @@ public final class Vector3 {
); );
} }
// TODO: Is this correctly used?!
public double distance(Vector3 vector) { public double distance(Vector3 vector) {
return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2) + Math.pow(vector.z, 2)); return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2) + Math.pow(vector.z, 2));
} }

Wyświetl plik

@ -2,7 +2,6 @@ package sh.ball.engine;
import com.mokiat.data.front.parser.*; import com.mokiat.data.front.parser.*;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;

Wyświetl plik

@ -40,6 +40,7 @@ public class Controller implements Initializable {
private static final int SAMPLE_RATE = 192000; private static final int SAMPLE_RATE = 192000;
private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj"); private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
private static final double DEFAULT_ROTATE_SPEED = 0.1;
private final FileChooser fileChooser = new FileChooser(); private final FileChooser fileChooser = new FileChooser();
private final Renderer<List<Shape>> renderer; private final Renderer<List<Shape>> renderer;
@ -90,6 +91,16 @@ public class Controller implements Initializable {
@FXML @FXML
private TextField cameraZTextField; private TextField cameraZTextField;
@FXML @FXML
private Slider objectRotateSpeedSlider;
@FXML
private Label objectRotateSpeedLabel;
@FXML
private TextField rotateXTextField;
@FXML
private TextField rotateYTextField;
@FXML
private TextField rotateZTextField;
@FXML
private CheckBox vectorCancellingCheckBox; private CheckBox vectorCancellingCheckBox;
@FXML @FXML
private Slider vectorCancellingSlider; private Slider vectorCancellingSlider;
@ -117,7 +128,9 @@ public class Controller implements Initializable {
scaleSlider, scaleSlider,
new SliderUpdater<>(scaleLabel::setText, scaleEffect::setScale), new SliderUpdater<>(scaleLabel::setText, scaleEffect::setScale),
focalLengthSlider, focalLengthSlider,
new SliderUpdater<>(focalLengthLabel::setText, this::setFocalLength) new SliderUpdater<>(focalLengthLabel::setText, this::setFocalLength),
objectRotateSpeedSlider,
new SliderUpdater<>(objectRotateSpeedLabel::setText, this::setObjectRotateSpeed)
); );
} }
@ -132,6 +145,7 @@ public class Controller implements Initializable {
); );
} }
// TODO: Refactor and clean up duplication
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
Map<Slider, SliderUpdater<Double>> sliders = initializeSliderMap(); Map<Slider, SliderUpdater<Double>> sliders = initializeSliderMap();
@ -163,6 +177,17 @@ public class Controller implements Initializable {
cameraYTextField.textProperty().addListener(cameraPosUpdate); cameraYTextField.textProperty().addListener(cameraPosUpdate);
cameraZTextField.textProperty().addListener(cameraPosUpdate); cameraZTextField.textProperty().addListener(cameraPosUpdate);
InvalidationListener rotateUpdate = observable ->
producer.setFrameSettings(new ObjFrameSettings(new Vector3(
tryParse(rotateXTextField.getText()),
tryParse(rotateYTextField.getText()),
tryParse(rotateZTextField.getText())
), null));
rotateXTextField.textProperty().addListener(rotateUpdate);
rotateYTextField.textProperty().addListener(rotateUpdate);
rotateZTextField.textProperty().addListener(rotateUpdate);
InvalidationListener vectorCancellingListener = e -> InvalidationListener vectorCancellingListener = e ->
updateEffect(EffectType.VECTOR_CANCELLING, vectorCancellingCheckBox.isSelected(), updateEffect(EffectType.VECTOR_CANCELLING, vectorCancellingCheckBox.isSelected(),
EffectFactory.vectorCancelling((int) vectorCancellingSlider.getValue())); EffectFactory.vectorCancelling((int) vectorCancellingSlider.getValue()));
@ -183,6 +208,8 @@ public class Controller implements Initializable {
} }
}); });
setObjectRotateSpeed(DEFAULT_ROTATE_SPEED);
renderer.addEffect(EffectType.SCALE, scaleEffect); renderer.addEffect(EffectType.SCALE, scaleEffect);
renderer.addEffect(EffectType.ROTATE, rotateEffect); renderer.addEffect(EffectType.ROTATE, rotateEffect);
renderer.addEffect(EffectType.TRANSLATE, translateEffect); renderer.addEffect(EffectType.TRANSLATE, translateEffect);
@ -198,6 +225,10 @@ public class Controller implements Initializable {
cameraZTextField.setText(String.valueOf(pos.getZ())); cameraZTextField.setText(String.valueOf(pos.getZ()));
} }
private void setObjectRotateSpeed(double rotateSpeed) {
producer.setFrameSettings(new ObjFrameSettings(null, (Math.exp(3 * rotateSpeed) - 1) / 50));
}
private double tryParse(String value) { private double tryParse(String value) {
try { try {
return Double.parseDouble(value); return Double.parseDouble(value);

Wyświetl plik

@ -12,36 +12,41 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
private final WorldObject object; private final WorldObject object;
private final Camera camera; private final Camera camera;
private final Vector3 rotation;
private final boolean isDefaultPosition; private final boolean isDefaultPosition;
public ObjFrameSet(WorldObject object, Camera camera, Vector3 rotation, boolean isDefaultPosition) { private Vector3 rotation = new Vector3();
private Double rotateSpeed = 0.0;
public ObjFrameSet(WorldObject object, Camera camera, boolean isDefaultPosition) {
this.object = object; this.object = object;
this.camera = camera; this.camera = camera;
this.rotation = rotation;
this.isDefaultPosition = isDefaultPosition; this.isDefaultPosition = isDefaultPosition;
} }
@Override @Override
public List<Shape> next() { public List<Shape> next() {
object.rotate(rotation); object.rotate(rotation.scale(rotateSpeed));
return camera.draw(object); return camera.draw(object);
} }
// TODO: Refactor!
@Override @Override
public Object setFrameSettings(Object settings) { public Object setFrameSettings(Object settings) {
if (settings instanceof ObjFrameSettings obj) { if (settings instanceof ObjFrameSettings obj) {
Double focalLength = obj.focalLength(); if (obj.focalLength != null && camera.getFocalLength() != obj.focalLength) {
Vector3 cameraPos = obj.cameraPos(); camera.setFocalLength(obj.focalLength);
if (focalLength != null && camera.getFocalLength() != focalLength) {
camera.setFocalLength(focalLength);
if (isDefaultPosition) { if (isDefaultPosition) {
camera.findZPos(object); camera.findZPos(object);
} }
} }
if (cameraPos != null && camera.getPos() != cameraPos) { if (obj.cameraPos != null && camera.getPos() != obj.cameraPos) {
camera.setPos(cameraPos); camera.setPos(obj.cameraPos);
}
if (obj.rotation != null) {
this.rotation = obj.rotation;
}
if (obj.rotateSpeed != null) {
this.rotateSpeed = obj.rotateSpeed;
} }
} }

Wyświetl plik

@ -2,13 +2,23 @@ package sh.ball.parser.obj;
import sh.ball.engine.Vector3; import sh.ball.engine.Vector3;
public record ObjFrameSettings(Double focalLength, Vector3 cameraPos) { public class ObjFrameSettings {
protected Double focalLength;
protected Vector3 cameraPos;
protected Vector3 rotation;
protected Double rotateSpeed;
public ObjFrameSettings(double focalLength) { public ObjFrameSettings(double focalLength) {
this(focalLength, null); this.focalLength = focalLength;
} }
public ObjFrameSettings(Vector3 cameraPos) { public ObjFrameSettings(Vector3 cameraPos) {
this(null, cameraPos); this.cameraPos = cameraPos;
}
public ObjFrameSettings(Vector3 rotation, Double rotateSpeed) {
this.rotation = rotation;
this.rotateSpeed = rotateSpeed;
} }
} }

Wyświetl plik

@ -16,27 +16,22 @@ import sh.ball.shapes.Shape;
public class ObjParser extends FileParser<FrameSet<List<Shape>>> { public class ObjParser extends FileParser<FrameSet<List<Shape>>> {
private static final float DEFAULT_ROTATE_SPEED = 3;
private final Vector3 rotation;
private final boolean isDefaultPosition; private final boolean isDefaultPosition;
private final InputStream input; private final InputStream input;
private final Camera camera; private final Camera camera;
private WorldObject object; private WorldObject object;
public ObjParser(InputStream input, float rotateSpeed, float cameraX, float cameraY, float cameraZ, public ObjParser(InputStream input, float cameraX, float cameraY, float cameraZ,
float focalLength, boolean isDefaultPosition) { float focalLength, boolean isDefaultPosition) {
rotateSpeed *= Math.PI / 1000;
this.input = input; this.input = input;
this.isDefaultPosition = isDefaultPosition; this.isDefaultPosition = isDefaultPosition;
Vector3 cameraPos = new Vector3(cameraX, cameraY, cameraZ); Vector3 cameraPos = new Vector3(cameraX, cameraY, cameraZ);
this.camera = new Camera(focalLength, cameraPos); this.camera = new Camera(focalLength, cameraPos);
this.rotation = new Vector3(0, rotateSpeed, rotateSpeed);
} }
public ObjParser(InputStream input, float focalLength) { public ObjParser(InputStream input, float focalLength) {
this(input, DEFAULT_ROTATE_SPEED, 0, 0, 0, focalLength, true); this(input, 0, 0, 0, focalLength, true);
} }
public ObjParser(InputStream input) { public ObjParser(InputStream input) {
@ -60,7 +55,7 @@ public class ObjParser extends FileParser<FrameSet<List<Shape>>> {
camera.findZPos(object); camera.findZPos(object);
} }
return new ObjFrameSet(object, camera, rotation, isDefaultPosition); return new ObjFrameSet(object, camera, isDefaultPosition);
} }
// If camera position arguments haven't been specified, automatically work out the position of // If camera position arguments haven't been specified, automatically work out the position of
@ -75,8 +70,4 @@ public class ObjParser extends FileParser<FrameSet<List<Shape>>> {
public static boolean isObjFile(String path) { public static boolean isObjFile(String path) {
return path.matches(".*\\.obj"); return path.matches(".*\\.obj");
} }
public void setCameraPos(Vector3 vector) {
camera.setPos(vector);
}
} }

Wyświetl plik

@ -58,13 +58,23 @@
<Slider fx:id="focalLengthSlider" blockIncrement="2.0" layoutX="116.0" layoutY="15.0" max="2.0" min="1.0E-5" prefHeight="14.0" prefWidth="198.0" value="1.0" /> <Slider fx:id="focalLengthSlider" blockIncrement="2.0" layoutX="116.0" layoutY="15.0" max="2.0" min="1.0E-5" prefHeight="14.0" prefWidth="198.0" value="1.0" />
<Label layoutX="43.0" layoutY="14.0" text="Focal length" /> <Label layoutX="43.0" layoutY="14.0" text="Focal length" />
<Label fx:id="focalLengthLabel" layoutX="316.0" layoutY="14.0" text="1" /> <Label fx:id="focalLengthLabel" layoutX="316.0" layoutY="14.0" text="1" />
<TextField fx:id="cameraXTextField" layoutX="134.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" /> <TextField fx:id="cameraXTextField" layoutX="134.0" layoutY="42.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="44.0" layoutY="44.0" text="Camera pos" /> <Label layoutX="44.0" layoutY="47.0" text="Camera pos" />
<Label layoutX="118.0" layoutY="44.0" text="x :" /> <Label layoutX="118.0" layoutY="47.0" text="x :" />
<Label layoutX="199.0" layoutY="43.0" text="y :" /> <Label layoutX="199.0" layoutY="46.0" text="y :" />
<TextField fx:id="cameraYTextField" layoutX="218.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" /> <TextField fx:id="cameraYTextField" layoutX="218.0" layoutY="42.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="283.0" layoutY="43.0" text="z :" /> <Label layoutX="283.0" layoutY="46.0" text="z :" />
<TextField fx:id="cameraZTextField" layoutX="302.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" /> <TextField fx:id="cameraZTextField" layoutX="302.0" layoutY="42.0" prefHeight="26.0" prefWidth="58.0" text="-2.5" />
<Slider fx:id="objectRotateSpeedSlider" blockIncrement="2.0" layoutX="116.0" layoutY="83.0" max="1.0" prefHeight="14.0" prefWidth="198.0" value="0.1" />
<Label layoutX="36.0" layoutY="82.0" text="Rotate speed" />
<Label fx:id="objectRotateSpeedLabel" layoutX="316.0" layoutY="82.0" text="0.1" />
<TextField fx:id="rotateXTextField" layoutX="134.0" layoutY="111.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="62.0" layoutY="116.0" text="Rotation" />
<Label layoutX="118.0" layoutY="116.0" text="x :" />
<Label layoutX="199.0" layoutY="115.0" text="y :" />
<TextField fx:id="rotateYTextField" layoutX="218.0" layoutY="111.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="283.0" layoutY="115.0" text="z :" />
<TextField fx:id="rotateZTextField" layoutX="302.0" layoutY="111.0" prefHeight="26.0" prefWidth="58.0" text="0" />
</AnchorPane> </AnchorPane>
</TitledPane> </TitledPane>
</SplitPane> </SplitPane>