Implemented 3D code from ICHack project

pull/35/head
James Ball 2020-02-11 21:00:47 +00:00
rodzic a55f57163c
commit ca9382d272
15 zmienionych plików z 345 dodań i 56 usunięć

Wyświetl plik

@ -2,7 +2,7 @@ package audio;
import shapes.Ellipse;
import shapes.Shapes;
import shapes.Vector;
import shapes.Vector2;
public class AudioClient {
private static final int SAMPLE_RATE = 192000;
@ -13,12 +13,20 @@ public class AudioClient {
AudioPlayer player = new AudioPlayer();
AudioPlayer.FORMAT = AudioPlayer.defaultFormat(SAMPLE_RATE);
AudioPlayer.addShapes(Shapes.generatePolygram(5, 3, 0.5, 60));
// AudioPlayer.addShapes(Shapes.generatePolygram(5, 3, 0.5, 60));
//AudioPlayer.addShapes(Shapes.generatePolygon(500, 0.5, 10));
AudioPlayer.addShape(new Ellipse(0.5, 1));
// AudioPlayer.addShape(new Ellipse(0.5, 1));
// AudioPlayer.setRotateSpeed(0.8);
// AudioPlayer.setTranslation(2, new Vector(0.5, 0.5));
AudioPlayer.addShapes(Shapes.generatePolygon(4, new Vector2(0.25, 0.25)));
AudioPlayer.addShapes(Shapes.generatePolygon(4, new Vector2(0.5, 0.5)));
AudioPlayer.addShapes(Shapes.generatePolygon(4, new Vector2(-0.8, -0.8)));
for (int i = 0; i < 10; i++) {
AudioPlayer.addShape(new Ellipse(i / 10d, i / 10d));
}
AudioPlayer.setRotateSpeed(0.8);
AudioPlayer.setTranslation(2, new Vector(0.5, 0.5));
AudioPlayer.setScale(0.5);
player.start();

Wyświetl plik

@ -2,7 +2,7 @@ package audio;
import com.xtaudio.xt.*;
import shapes.Shape;
import shapes.Vector;
import shapes.Vector2;
import java.util.ArrayList;
import java.util.List;
@ -17,7 +17,7 @@ public class AudioPlayer extends Thread {
public static XtFormat FORMAT;
private static double TRANSLATE_SPEED = 0;
private static Vector TRANSLATE_VECTOR;
private static Vector2 TRANSLATE_VECTOR;
private static final int TRANSLATE_PHASE_INDEX = 0;
private static double ROTATE_SPEED = 0.4;
private static final int ROTATE_PHASE_INDEX = 1;
@ -81,7 +81,7 @@ public class AudioPlayer extends Thread {
}
private static Shape translate(Shape shape, double sampleRate) {
if (TRANSLATE_SPEED != 0 && !TRANSLATE_VECTOR.equals(new Vector())) {
if (TRANSLATE_SPEED != 0 && !TRANSLATE_VECTOR.equals(new Vector2())) {
return shape.translate(TRANSLATE_VECTOR.scale(
Math.sin(nextTheta(sampleRate, TRANSLATE_SPEED, ROTATE_PHASE_INDEX))
));
@ -110,7 +110,7 @@ public class AudioPlayer extends Thread {
AudioPlayer.ROTATE_SPEED = speed;
}
public static void setTranslation(double speed, Vector translation) {
public static void setTranslation(double speed, Vector2 translation) {
AudioPlayer.TRANSLATE_SPEED = speed;
AudioPlayer.TRANSLATE_VECTOR = translation;
}

Wyświetl plik

@ -0,0 +1,43 @@
package engine;
import shapes.Line;
import shapes.Vector2;
import java.util.ArrayList;
import java.util.List;
public class Camera extends Renderer{
// position at 0,0,0,0
// rotation towards positive z axis
private double focalLength;
private double clipping = 0.001;
private Vector3 position;
private double fov;
public Camera() {
this.focalLength = 0.6;
this.position = new Vector3(0,0,-2);
this.fov = 60;
}
public List<Line> draw(WorldObject worldObject) {
List<Vector2> vertices = new ArrayList<>();
for(Vector3 vertex : worldObject.getVertices()) {
vertices.add(this.project(vertex));
}
return this.getFrame(vertices, worldObject.getEdgeData());
}
private Vector2 project(Vector3 vertex) {
if(vertex.getZ() - this.position.getZ() < clipping) {
return new Vector2(0, 0);
}
return new Vector2(
vertex.getX() * focalLength / (vertex.getZ() - this.position.getZ()) + this.position.getX(),
vertex.getY() * focalLength / (vertex.getZ() - this.position.getZ()) + this.position.getY()
);
}
}

Wyświetl plik

@ -0,0 +1,18 @@
package engine;
public class Main {
public static void main(String[] args) throws InterruptedException {
Camera camera = new Camera();
WorldObject cube = new WorldObject("resources/machine.obj", new Vector3(0,0,0), new Vector3());
while(true) {
camera.draw(cube);
cube.rotate(new Vector3(
0,
Math.PI / 100,
0
));
Thread.sleep(1000/30);
}
}
}

Wyświetl plik

@ -0,0 +1,77 @@
package engine;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.stream.Collectors;
public class Mesh {
private static final String VERTEX_PATTERN = "(?m)^v .*";
private static final String FACE_PATTERN = "(?m)^f .*";
private List<Vector3> vertices;
private List<Integer> edgeData;
public Mesh() {
this.vertices = new ArrayList<>();
this.edgeData = new ArrayList<>();
}
public Mesh(List<Vector3> vertices, List<Integer> edgeData) {
this.vertices = vertices;
this.edgeData = edgeData;
}
public List<Vector3> getVertices() {
return vertices;
}
public List<Integer> getEdgeData() {
return edgeData;
}
public static Mesh loadFromFile(String filename) {
Scanner sc;
try {
sc = new Scanner(new File(filename));
} catch (Exception e) {
System.err.println("Cannot load mesh data from: " + filename);
return new Mesh();
}
// load vertices
List<Vector3> vertices =
sc.findAll(VERTEX_PATTERN)
.map(s -> parseVertex(s.group(0)))
.collect(Collectors.toList());
// load edge data
List<Integer> edgeData = new ArrayList<>();
for(MatchResult result : sc.findAll(FACE_PATTERN).collect(Collectors.toList())) {
List<Integer> indices = parseFace(result.group(0));
for(int i = 0; i < indices.size(); i++ ) {
edgeData.add(indices.get(i));
edgeData.add(indices.get((i + 1) % indices.size()));
}
}
return new Mesh(vertices, edgeData);
}
private static Vector3 parseVertex(String data) {
String[] coords = data.split(" ");
double x = Double.parseDouble(coords[1]);
double y = Double.parseDouble(coords[2]);
double z = Double.parseDouble(coords[3]);
return new Vector3(x, y, z);
}
private static List<Integer> parseFace(String data) {
List<Integer> indices = new ArrayList<>();
String[] datas = data.split(" ");
for(int i = 1; i < datas.length; i++) {
indices.add(Integer.parseInt(datas[i].split("/")[0]) - 1);
}
return indices;
}
}

Wyświetl plik

@ -0,0 +1,26 @@
package engine;
import shapes.Line;
import shapes.Vector2;
import java.util.ArrayList;
import java.util.List;
public abstract class Renderer {
public List<Line> getFrame(List<Vector2> vertices, List<Integer> connections) {
List<Line> lines = new ArrayList<>();
for (int i = 0; i < connections.size(); i+=2) {
Vector2 start = vertices.get(connections.get(i));
Vector2 end = vertices.get(connections.get(i+1));
double x1 = start.getX();
double y1 = start.getY();
double x2 = end.getX();
double y2 = end.getY();
lines.add(new Line(x1, y1, x2, y2));
}
return lines;
}
}

Wyświetl plik

@ -0,0 +1,79 @@
package engine;
import java.util.List;
public class Vector3 {
private double x, y, z;
public Vector3() {
this.x = 0;
this.y = 0;
this.z = 0;
}
public Vector3(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public Vector3 add(Vector3 other) {
return new Vector3(
this.getX() + other.getX(),
this.getY() + other.getY(),
this.getZ() + other.getZ()
);
}
public Vector3 scale(double scalar) {
return new Vector3(
this.getX() * scalar,
this.getY() * scalar,
this.getZ() * scalar
);
}
public Vector3 rotateX(double delta) {
return new Vector3(
getX(),
Math.cos(delta) * getY() - Math.sin(delta) * getZ(),
Math.sin(delta) * getY() + Math.cos(delta) * getZ()
);
}
public Vector3 rotateY(double delta) {
return new Vector3(
Math.cos(delta) * getX() + Math.sin(delta) * getZ(),
getY(),
-Math.sin(delta) * getX() + Math.cos(delta) * getZ()
);
}
public Vector3 rotateZ(double delta) {
return new Vector3(
Math.cos(delta) * getX() - Math.sin(delta) * getY(),
Math.sin(delta) * getX() + Math.cos(delta) * getY(),
getZ()
);
}
public static Vector3 meanPoint(List<Vector3> points) {
Vector3 mean = new Vector3();
for(Vector3 point : points) {
mean = mean.add(point);
}
return mean.scale(1f / (points.size()));
}
}

Wyświetl plik

@ -0,0 +1,38 @@
package engine;
import java.util.ArrayList;
import java.util.List;
public class WorldObject {
private Mesh mesh;
private Vector3 position;
private Vector3 rotation;
public WorldObject(String filename, Vector3 position, Vector3 rotation) {
this.mesh = Mesh.loadFromFile(filename);
this.position = position;
this.rotation = rotation;
}
public void rotate(Vector3 theta) {
this.rotation = this.rotation.add(theta);
}
public List<Vector3> getVertices() {
List<Vector3> vertices = new ArrayList<>();
for(Vector3 vertex : mesh.getVertices()) {
vertices.add(
vertex
.rotateX(this.rotation.getX())
.rotateY(this.rotation.getY())
.rotateZ(this.rotation.getY())
.add(this.position));
}
return vertices;
}
public List<Integer> getEdgeData() {
return mesh.getEdgeData();
}
}

Wyświetl plik

@ -1,7 +1,7 @@
package graphs;
import shapes.Line;
import shapes.Vector;
import shapes.Vector2;
import java.util.HashMap;
import java.util.List;
@ -10,7 +10,7 @@ import java.util.Map;
// TODO: Implement Chinese postman solving.
public class Graph {
private Map<Vector, Node> nodes;
private Map<Vector2, Node> nodes;
public Graph(List<Line> lines) {
this.nodes = new HashMap<>();

Wyświetl plik

@ -1,23 +1,23 @@
package graphs;
import shapes.Vector;
import shapes.Vector2;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Node {
private Vector location;
private Vector2 location;
private List<Node> adjacentNodes;
private List<Double> adjacentWeights;
public Node(Vector location) {
public Node(Vector2 location) {
this.location = location;
this.adjacentNodes = new ArrayList<>();
this.adjacentWeights = new ArrayList<>();
}
public Vector getLocation() {
public Vector2 getLocation() {
return location;
}

Wyświetl plik

@ -4,9 +4,9 @@ public class Ellipse extends Shape {
private final double a;
private final double b;
private final double rotation;
private final Vector position;
private final Vector2 position;
public Ellipse(double a, double b, double weight, double rotation, Vector position) {
public Ellipse(double a, double b, double weight, double rotation, Vector2 position) {
this.a = a;
this.b = b;
this.weight = weight;
@ -16,12 +16,12 @@ public class Ellipse extends Shape {
this.length = 2 * Math.PI * Math.sqrt((a * a + b * b) / 2);
}
public Ellipse(double a, double b, Vector position) {
public Ellipse(double a, double b, Vector2 position) {
this(a, b, 100, 0, position);
}
public Ellipse(double a, double b) {
this(a, b, 100, 0, new Vector());
this(a, b, 100, 0, new Vector2());
}
@Override
@ -53,7 +53,7 @@ public class Ellipse extends Shape {
}
@Override
public Shape translate(Vector vector) {
public Shape translate(Vector2 vector) {
return new Ellipse(a, b, weight, rotation, position.add(vector));
}
}

Wyświetl plik

@ -1,28 +1,28 @@
package shapes;
public class Line extends Shape {
private final Vector a;
private final Vector b;
private final Vector2 a;
private final Vector2 b;
public static final double DEFAULT_WEIGHT = 100;
public Line(Vector a, Vector b, double weight) {
public Line(Vector2 a, Vector2 b, double weight) {
this.a = a;
this.b = b;
this.weight = weight;
this.length = calculateLength();
}
public Line(Vector a, Vector b) {
public Line(Vector2 a, Vector2 b) {
this(a, b, DEFAULT_WEIGHT);
}
public Line(double x1, double y1, double x2, double y2, double weight) {
this(new Vector(x1, y1), new Vector(x2, y2), weight);
this(new Vector2(x1, y1), new Vector2(x2, y2), weight);
}
public Line(double x1, double y1, double x2, double y2) {
this(new Vector(x1, y1), new Vector(x2, y2));
this(new Vector2(x1, y1), new Vector2(x2, y2));
}
private double calculateLength() {
@ -35,7 +35,7 @@ public class Line extends Shape {
}
@Override
public Line translate(Vector vector) {
public Line translate(Vector2 vector) {
return new Line(getA().add(vector), getB().add(vector));
}
@ -58,11 +58,11 @@ public class Line extends Shape {
return (float) (getY1() + (getY2() - getY1()) * drawingProgress);
}
public Vector getA() {
public Vector2 getA() {
return a;
}
public Vector getB() {
public Vector2 getB() {
return b;
}

Wyświetl plik

@ -8,7 +8,7 @@ public abstract class Shape {
public abstract float nextY(double drawingProgress);
public abstract Shape rotate(double theta);
public abstract Shape scale(double factor);
public abstract Shape translate(Vector vector);
public abstract Shape translate(Vector2 vector);
public double getWeight() {
return weight;

Wyświetl plik

@ -4,11 +4,11 @@ import java.util.ArrayList;
import java.util.List;
public class Shapes {
public static List<Shape> generatePolygram(int sides, int angleJump, Vector start, double weight) {
public static List<Shape> generatePolygram(int sides, int angleJump, Vector2 start, double weight) {
List<Shape> polygon = new ArrayList<>();
double theta = angleJump * 2 * Math.PI / sides;
Vector rotated = start.rotate(theta);
Vector2 rotated = start.rotate(theta);
polygon.add(new Line(start, rotated, weight));
while (!rotated.equals(start)) {
@ -20,32 +20,32 @@ public class Shapes {
return polygon;
}
public static List<Shape> generatePolygram(int sides, int angleJump, Vector start) {
public static List<Shape> generatePolygram(int sides, int angleJump, Vector2 start) {
return generatePolygram(sides, angleJump, start, Line.DEFAULT_WEIGHT);
}
public static List<Shape> generatePolygram(int sides, int angleJump, double scale, double weight) {
return generatePolygram(sides, angleJump, new Vector(scale, scale), weight);
return generatePolygram(sides, angleJump, new Vector2(scale, scale), weight);
}
public static List<Shape> generatePolygram(int sides, int angleJump, double scale) {
return generatePolygram(sides, angleJump, new Vector(scale, scale));
return generatePolygram(sides, angleJump, new Vector2(scale, scale));
}
public static List<Shape> generatePolygon(int sides, Vector start, double weight) {
public static List<Shape> generatePolygon(int sides, Vector2 start, double weight) {
return generatePolygram(sides, 1, start, weight);
}
public static List<Shape> generatePolygon(int sides, Vector start) {
public static List<Shape> generatePolygon(int sides, Vector2 start) {
return generatePolygram(sides, 1, start);
}
public static List<Shape> generatePolygon(int sides, double scale, double weight) {
return generatePolygon(sides, new Vector(scale, scale), weight);
return generatePolygon(sides, new Vector2(scale, scale), weight);
}
public static List<Shape> generatePolygon(int sides, double scale) {
return generatePolygon(sides, new Vector(scale, scale));
return generatePolygon(sides, new Vector2(scale, scale));
}
public static List<Line> cleanupLines(List<Line> lines) {

Wyświetl plik

@ -2,18 +2,18 @@ package shapes;
import java.util.Objects;
public class Vector {
public class Vector2 {
private final double x;
private final double y;
private static final double EPSILON = 0.001;
public Vector(double x, double y) {
public Vector2(double x, double y) {
this.x = x;
this.y = y;
}
public Vector() {
public Vector2() {
this(0, 0);
}
@ -25,28 +25,28 @@ public class Vector {
return y;
}
public Vector setX(double x) {
return new Vector(x, this.y);
public Vector2 setX(double x) {
return new Vector2(x, this.y);
}
public Vector setY(double y) {
return new Vector(this.x, y);
public Vector2 setY(double y) {
return new Vector2(this.x, y);
}
public Vector add(Vector vector) {
return new Vector(getX() + vector.getX(), getY() + vector.getY());
public Vector2 add(Vector2 vector) {
return new Vector2(getX() + vector.getX(), getY() + vector.getY());
}
public Vector scale(double factor) {
return new Vector(getX() * factor, getY() * factor);
public Vector2 scale(double factor) {
return new Vector2(getX() * factor, getY() * factor);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Vector) {
Vector vector = (Vector) obj;
} else if (obj instanceof Vector2) {
Vector2 vector = (Vector2) obj;
return approxEquals(vector.getX(), getX()) && approxEquals(vector.getY(), getY());
} else {
@ -63,12 +63,12 @@ public class Vector {
return Math.round(d * 1000) / 1000d;
}
public Vector copy() {
return new Vector(x, y);
public Vector2 copy() {
return new Vector2(x, y);
}
public Vector rotate(double theta) {
Vector vector = setX(getX() * Math.cos(theta) - getY() * Math.sin(theta));
public Vector2 rotate(double theta) {
Vector2 vector = setX(getX() * Math.cos(theta) - getY() * Math.sin(theta));
vector = vector.setY(getX() * Math.sin(theta) + getY() * Math.cos(theta));
return vector;