diff --git a/EPQ 3D renderer.iml b/EPQ 3D renderer.iml index e9c3f97..50eaffd 100644 --- a/EPQ 3D renderer.iml +++ b/EPQ 3D renderer.iml @@ -13,5 +13,6 @@ + \ No newline at end of file diff --git a/Grass block.png b/Grass block.png new file mode 100644 index 0000000..2e08778 --- /dev/null +++ b/Grass block.png Binary files differ diff --git a/config.json b/config.json index 3a39d53..813c394 100644 --- a/config.json +++ b/config.json @@ -10,8 +10,8 @@ "__comment":"values are: enabled/disabled", "masterDebugToggle":"enabled", "drawDebugHud":"disabled", - "drawLines":"disabled", - "overrideBackFaceCulling":"disabled", + "drawLines":"false", + "overrideBackFaceCulling":"enabled", "frustumCullingOverridePercent":0, "drawZBuffer":"disabled" } diff --git a/jsonCollections.json b/jsonCollections.json new file mode 100644 index 0000000..9fa75bc --- /dev/null +++ b/jsonCollections.json @@ -0,0 +1 @@ +{"collections": [{"name": "MainCollection", "subCollections": [], "objects": [{"name": "Cube", "position": [0.0, 0.0, 0.0], "rotation": [0.0, 0.0, 0.0], "scale": [1.0, 1.0, 1.0], "points": [[-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0], [-1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, -1.0, -1.0], [1.0, -1.0, 1.0], [1.0, 1.0, -1.0], [1.0, 1.0, 1.0], [-1.0, -1.0, 3.2648987770080566], [-1.0, 1.0, 3.2648987770080566], [1.0, -1.0, 3.2648987770080566], [1.0, 1.0, 3.2648987770080566], [0.0, 0.0, 5.255918979644775]], "faceList": [[0, 1, 3, 2], [2, 3, 7, 6], [6, 7, 5, 4], [4, 5, 1, 0], [2, 6, 4, 0], [7, 3, 1, 5], [11, 10, 8, 9], [11, 9, 12], [10, 11, 12], [9, 8, 12], [8, 10, 12]], "uvPointsList": [[1.0000001192092896, 0.3333333134651184], [1.0000001192092896, 0.6666666865348816], [0.75, 0.6666666865348816], [0.75, 0.3333333134651184], [0.75, 0.3333333134651184], [0.75, 0.6666666865348816], [0.5, 0.6666666865348816], [0.5, 0.3333333134651184], [0.5, 0.3333333134651184], [0.5, 0.6666666865348816], [0.2499999850988388, 0.6666666865348816], [0.2499999850988388, 0.3333333134651184], [0.2499999850988388, 0.3333333134651184], [0.2499999850988388, 0.6666666865348816], [0.0, 0.6666666865348816], [0.0, 0.3333333134651184], [0.5, 0.0], [0.5, 0.3333333134651184], [0.2499999850988388, 0.3333333134651184], [0.2499999850988388, 0.0], [0.5, 0.6666666865348816], [0.5, 1.0], [0.24999994039535522, 1.0], [0.2499999850988388, 0.6666666865348816], [0.5, 0.6666666865348816], [0.2499999850988388, 0.6666666865348816], [0.24999994039535522, 1.0], [0.5, 1.0], [0.5, 0.6666666865348816], [0.5, 1.0], [0.5, 0.6666666865348816], [0.2499999850988388, 0.6666666865348816], [0.5, 0.6666666865348816], [0.2499999850988388, 0.6666666865348816], [0.5, 1.0], [0.24999994039535522, 1.0], [0.5, 1.0], [0.24999994039535522, 1.0], [0.2499999850988388, 0.6666666865348816], [0.24999994039535522, 1.0]], "textureList": ["Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002", "Material.002"]}]}]} \ No newline at end of file diff --git a/jsonTextures.json b/jsonTextures.json new file mode 100644 index 0000000..ca60de7 --- /dev/null +++ b/jsonTextures.json @@ -0,0 +1,3 @@ +{"textures": [{"name": "Dots Stroke", "type": "solid", "color": "cccccc", "imgPath": "/"}, {"name": "Material", "type": "solid", "color": "cccccc", "imgPath": "/"}, +{"name": "Material.002", "type": "image", "color": "cccccc", "imgPath": "Grass block.png"}, +{"name": "Material.001", "type": "image", "color": "cccccc", "imgPath": "Grass block.png"}]} diff --git a/src/main/java/uk/org/floop/epq3d/Face.java b/src/main/java/uk/org/floop/epq3d/Face.java index ea4214c..d04e317 100644 --- a/src/main/java/uk/org/floop/epq3d/Face.java +++ b/src/main/java/uk/org/floop/epq3d/Face.java @@ -4,7 +4,7 @@ public class Face { public PointComp[] points; - public Point2D[] UVPoints; + public double[][] UVPoints; public Vector3D normal; public double boundingSphereR; @@ -92,11 +92,13 @@ bakePerspectiveMatrices(drawData); // if all the points are valid (in front of the camera) draw all tris normally. + double lastTime = System.currentTimeMillis(); if (valid) { for (Triangle tri : tris) { tri.draw(drawData, ang); } + drawData.timeSpentDrawingNormalFaces += System.currentTimeMillis() - lastTime; } else { for (int tri_i = 0; tri_i < trisFaceList.length; tri_i += 1) { // first, count up the number of invalid points in the triangle (points which are behind the camera) @@ -124,8 +126,8 @@ PointComp oldPoint1 = points[trisFaceList[tri_i][Math.floorMod(invalidIndex + 1, 3)]]; PointComp oldPoint2 = points[trisFaceList[tri_i][Math.floorMod(invalidIndex + 2, 3)]]; PointComp invalidPoint = points[trisFaceList[tri_i][invalidIndex]]; - PointComp newPoint1 = new PointComp(); - PointComp newPoint2 = new PointComp(); + PointComp newPoint1; + PointComp newPoint2; // assign old points 1 and 2 based on the index of the invalid point // interpolate between oldPoint1 and invalidPoint newPoint1 = interpolate(drawData, frustumInfo, oldPoint1, invalidPoint); @@ -137,13 +139,11 @@ Triangle newTri; newTri = new Triangle(oldPoint1, newPoint2, newPoint1, new boolean[]{false, false, false}, - tris[tri_i].texture, - tris[tri_i].perspectiveMappingMatrix); + tris[tri_i].texture); newTri.draw(drawData, ang); newTri = new Triangle(oldPoint1, oldPoint2, newPoint2, new boolean[]{false, false, false}, - tris[tri_i].texture, - tris[tri_i].perspectiveMappingMatrix); + tris[tri_i].texture); newTri.draw(drawData, ang); } else if (numOfInvalidPoints == 2) { // if two points are invalid, interpolate and draw triangle w/ new points: int validIndex = -1; @@ -174,51 +174,46 @@ Triangle newTri; newTri = new Triangle(newPoint1, newPoint2, oldPoint, new boolean[]{false, false, false}, - tris[tri_i].texture, - tris[tri_i].perspectiveMappingMatrix); + tris[tri_i].texture); newTri.draw(drawData, ang); } } // if all points are invalid, do nothing } + drawData.timeSpentChoppingFaces += System.currentTimeMillis() - lastTime; } } private PointComp interpolate(drawData drawData, ArrayList frustumInfo, PointComp oldPoint, PointComp invalidPoint){ - // calculate distance to each of the frustum planes. Then store the minimum distance from each of - double minDis = 0; - int planeMin = 0; - for (int planeId: - frustumInfo) { - // don't check the near plane - if(planeId != 0) { - double dist = drawData.frustumPlanes[planeId].getDistance(invalidPoint.getRotatedPoint()); - if (minDis > dist) { - minDis = dist; - planeMin = planeId; - } - } - } - /* if the minimum distance is less than zero: - Find the z difference between oldPoint and invalidPoint - Find the distance from the oldPoint to the plane with that value - Add this distance to the minDis we found earlier - divide minDis by this number - multiply by the Z difference between oldPoint and invalidPoint - */ - double interpolateZval = 0.01; - if(minDis < 0 && false){ - interpolateZval = Math.max(interpolateZval, - (oldPoint.getRotatedPoint().z - invalidPoint.getRotatedPoint().z)*minDis/ - (drawData.frustumPlanes[planeMin].getDistance(oldPoint.getRotatedPoint()) + minDis)); - } +// // calculate distance to each of the frustum planes. Then store the minimum distance from each of +// double minDis = 0; +// int planeMin = 0; +// for (int planeId: +// frustumInfo) { +// // don't check the near plane +// if(planeId != 0) { +// double dist = drawData.frustumPlanes[planeId].getDistance(invalidPoint.getRotatedPoint()); +// if (minDis > dist) { +// minDis = dist; +// planeMin = planeId; +// } +// } +// } + double interpolateZVal = 0.1; +// if(minDis < 0){ +// Vector3D oldNew = new Vector3D(oldPoint.getRotatedPoint(), invalidPoint.getRotatedPoint()); +// double pointDis = oldNew.getLength(); +// double fraction = -minDis / pointDis; +// double newZ = (oldPoint.getRotatedPoint().z - invalidPoint.getRotatedPoint().z)*fraction - invalidPoint.getRotatedPoint().z; +// interpolateZVal = Math.max(interpolateZVal, newZ); +// } double gradX = (oldPoint.getRotatedPoint().z - invalidPoint.getRotatedPoint().z) / (oldPoint.getRotatedPoint().x - invalidPoint.getRotatedPoint().x); double gradY = (oldPoint.getRotatedPoint().z - invalidPoint.getRotatedPoint().z) / (oldPoint.getRotatedPoint().y - invalidPoint.getRotatedPoint().y); Point3D newPointRotated = new Point3D( - (interpolateZval + gradX * oldPoint.getRotatedPoint().x - oldPoint.getRotatedPoint().z) / gradX, - (interpolateZval + gradY * oldPoint.getRotatedPoint().y - oldPoint.getRotatedPoint().z) / gradY, - interpolateZval); + (interpolateZVal + gradX * oldPoint.getRotatedPoint().x - oldPoint.getRotatedPoint().z) / gradX, + (interpolateZVal + gradY * oldPoint.getRotatedPoint().y - oldPoint.getRotatedPoint().z) / gradY, + interpolateZVal); if (!Double.isFinite(gradX)) { newPointRotated.x = oldPoint.getRotatedPoint().x; } @@ -327,8 +322,11 @@ points[0], points[i + 1], points[i + 2], + UVPoints[0], + UVPoints[i+1], + UVPoints[i+2], new boolean[]{hasEdges, hasEdges, hasEdges}, - texture, perspectiveMappingMatrices[i]); + texture); } tris = newTris; trisFaceList = newTrisFaceList; @@ -379,7 +377,8 @@ Matrix uvTo00 = new Matrix(4, 4); uvTo00.setItems(new double[][]{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}); { - vOrig.createFrom2Points(UVPoints[tri[0]], UVPoints[tri[1]]); + vOrig.x = UVPoints[tri[1]][0] - UVPoints[tri[0]][0]; + vOrig.y = UVPoints[tri[1]][1] - UVPoints[tri[0]][1]; double rotAng = -vOrig.angleTo(vFin); // set to rotation MultMat.setItems(new double[][]{ @@ -401,8 +400,8 @@ uvTo00.multiply(MultMat); // set to translation MultMat.setItems(new double[][]{ - {1, 0, 0, -UVPoints[tri[0]].x}, - {0, 1, 0, -UVPoints[tri[0]].y}, + {1, 0, 0, -UVPoints[tri[0]][0]}, + {0, 1, 0, -UVPoints[tri[0]][1]}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); @@ -485,7 +484,7 @@ pointFace.set(faceTo00.multiplyPoint3raw(points[tri[2]].point.x, points[tri[2]].point.y, points[tri[2]].point.z)); Point3D pointUV = new Point3D(); - pointUV.set(uvTo00.multiplyPoint3raw(UVPoints[tri[2]].x, UVPoints[tri[2]].y, 0)); + pointUV.set(uvTo00.multiplyPoint3raw(UVPoints[tri[2]][0], UVPoints[tri[2]][1], 0)); double xScale = pointUV.x / pointFace.x; //System.out.println("Scale: " + xScale); diff --git a/src/main/java/uk/org/floop/epq3d/JsonReader.java b/src/main/java/uk/org/floop/epq3d/JsonReader.java index 18082ec..8ef4d7c 100644 --- a/src/main/java/uk/org/floop/epq3d/JsonReader.java +++ b/src/main/java/uk/org/floop/epq3d/JsonReader.java @@ -72,15 +72,15 @@ JSONArray texturesNamesJson = (JSONArray) object.get("textureList"); int[][] faceList = new int[faceListJson.size()][]; - Point2D[][] uvPointsList = new Point2D[faceListJson.size()][]; + double[][][] uvPointsList = new double[faceListJson.size()][][]; Texture[] texturesList = new Texture[faceListJson.size()]; - + int uvIndex = 0; for (int i = 0; i < faceListJson.size(); i+=1) { JSONArray jsonFace = (JSONArray) faceListJson.get(i); String jsonTextureName = (String) texturesNamesJson.get(i); faceList[i] = new int[jsonFace.size()]; - uvPointsList[i] = new Point2D[jsonFace.size()]; + uvPointsList[i] = new double[jsonFace.size()][]; // probably inefficient linear search but idc because this code only runs once for (Texture texture : textures) { if (Objects.equals(texture.name, jsonTextureName)) { @@ -91,10 +91,11 @@ for (int j = 0; j < jsonFace.size(); j += 1){ faceList[i][j] = (int)(long)jsonFace.get(j); if(!texturesList[i].isSolid()){ - uvPointsList[i][j] = new Point2D( - (int)(double)((JSONArray)uvPointsListJson.get(faceList[i][j])).get(0), - (int)(double)((JSONArray)uvPointsListJson.get(faceList[i][j])).get(1)); + uvPointsList[i][j] = new double[2]; + uvPointsList[i][j][0] = (double)((JSONArray)uvPointsListJson.get(uvIndex)).get(0); + uvPointsList[i][j][1] = (double)((JSONArray)uvPointsListJson.get(uvIndex)).get(1); } + uvIndex += 1; } } @@ -108,7 +109,8 @@ JSONObject JsonTexture = (JSONObject) textures.get(i); if(Objects.equals(JsonTexture.get("type"), "solid")){ result[i] = new Texture(JsonTexture.get("name").toString(), Color.decode('#' + (String) JsonTexture.get("color"))); - //result[i] = new Texture(JsonTexture.get("name").toString(), Color.decode('#' + "0000ff")); + } else if(Objects.equals(JsonTexture.get("type"), "image")){ + result[i] = new Texture(JsonTexture.get("name").toString(), Color.decode('#' + (String) JsonTexture.get("color")), (String) JsonTexture.get("imgPath")); } } return result; diff --git a/src/main/java/uk/org/floop/epq3d/Line2d.java b/src/main/java/uk/org/floop/epq3d/Line2d.java index 1e027ae..6e7cb47 100644 --- a/src/main/java/uk/org/floop/epq3d/Line2d.java +++ b/src/main/java/uk/org/floop/epq3d/Line2d.java @@ -7,6 +7,8 @@ public class Line2d { public PointComp point1; public PointComp point2; + public double[] UVPoint1; + public double[] UVPoint2; public boolean isDrawn; @@ -23,9 +25,11 @@ // drawing progress variables private int iteratorVal; private int D; - public Line2d(PointComp _point1, PointComp _point2, boolean _isDrawn){ + public Line2d(PointComp _point1, PointComp _point2, double[] _UVPoint1, double[] _UVPoint2, boolean _isDrawn){ point1 = _point1; point2 = _point2; + UVPoint1 = _UVPoint1; + UVPoint2 = _UVPoint2; isDrawn = _isDrawn; } /** diff --git a/src/main/java/uk/org/floop/epq3d/Matrix.java b/src/main/java/uk/org/floop/epq3d/Matrix.java index 5a3c9ff..621f006 100644 --- a/src/main/java/uk/org/floop/epq3d/Matrix.java +++ b/src/main/java/uk/org/floop/epq3d/Matrix.java @@ -123,11 +123,11 @@ public double[] multiplyPoint2raw(double px, double py) { double[] result = new double[2]; if(x==2){ - result[0] = (int)(px * getItem(0,0) + py* getItem(1,0)); - result[1] = (int)(px * getItem(0,1) + py* getItem(1,1)); + result[0] = (px * getItem(0,0) + py* getItem(1,0)); + result[1] = (px * getItem(0,1) + py* getItem(1,1)); } else if(x==3){ - result[0] = (int)(px * getItem(0,0) + py* getItem(1,0) + getItem(2,0)); - result[1] = (int)(px * getItem(0,1) + py* getItem(1,1) + getItem(2,1)); + result[0] = (px * getItem(0,0) + py* getItem(1,0) + getItem(2,0)); + result[1] = (px * getItem(0,1) + py* getItem(1,1) + getItem(2,1)); } else {throw new RuntimeException("wrong-dimensions");} return result; } diff --git a/src/main/java/uk/org/floop/epq3d/Object3d.java b/src/main/java/uk/org/floop/epq3d/Object3d.java index bc3fc5d..0d8b1c2 100644 --- a/src/main/java/uk/org/floop/epq3d/Object3d.java +++ b/src/main/java/uk/org/floop/epq3d/Object3d.java @@ -5,7 +5,7 @@ public class Object3d { public PointComp[] points; public int[][] faceList; - public Point2D[][] uvPoints; + public double[][][] uvPoints; public Face[] faces; public Point3D boundingSphereC; @@ -13,7 +13,7 @@ public boolean hasEdges; public Texture[] textures; - public Object3d(PointComp[] _points, int[][] _faceList, Point2D[][] _uvPoints, boolean _hasEdges, Texture[] _textures, boolean initialise) { + public Object3d(PointComp[] _points, int[][] _faceList, double[][][] _uvPoints, boolean _hasEdges, Texture[] _textures, boolean initialise) { points = _points; faceList = _faceList; uvPoints = _uvPoints; diff --git a/src/main/java/uk/org/floop/epq3d/Screen.java b/src/main/java/uk/org/floop/epq3d/Screen.java index 6d3d851..7f88312 100644 --- a/src/main/java/uk/org/floop/epq3d/Screen.java +++ b/src/main/java/uk/org/floop/epq3d/Screen.java @@ -147,7 +147,7 @@ // DEBUG DRAWING { //debugImg.getGraphics().drawString(Math.round(1000 / (float) (System.currentTimeMillis() - lastTime)) + " fps", 10, 10); - drawData.debugImg.getGraphics().drawString("FrameTime: " + (System.currentTimeMillis() - lastTime) + " millis", 10, 10); + drawData.debugImg.getGraphics().drawString(f"FrameTime: " + (System.currentTimeMillis() - lastTime) + " millis", 10, 10); if(drawData.debugHud) { drawData.debugImg.getGraphics().drawString("fpPos: " + String.format("%.2f", player.FPWorldPos.x) + " " + @@ -200,6 +200,10 @@ } } } + //System.out.println(drawData.timeSpentChoppingFaces + ", " + drawData.timeSpentDrawingNormalFaces); + drawData.timeSpentChoppingFaces = 0; + drawData.timeSpentDrawingNormalFaces = 0; + // HTTPPost post = new HTTPPost(); // // json WRITING // json = new JsonWriter(); diff --git a/src/main/java/uk/org/floop/epq3d/Texture.java b/src/main/java/uk/org/floop/epq3d/Texture.java index 40b3ded..5d256f9 100644 --- a/src/main/java/uk/org/floop/epq3d/Texture.java +++ b/src/main/java/uk/org/floop/epq3d/Texture.java @@ -19,14 +19,16 @@ color = _color; } - public Texture(String _name, String _imgPath) { + public Texture(String _name, Color _color, String _imgPath) { name = _name; type = "image"; - + color = _color; // grab file and pack it into a list[][] int (gives better performance than a BufferedImage by a _lot_ - File imgFile = new File(_imgPath); + String path = System.getProperty("user.dir") + "/" + _imgPath; + File imgFile = new File(path); try { BufferedImage _img = ImageIO.read(imgFile); + img = new int[_img.getWidth()][_img.getHeight()]; for (int x = 0; x < _img.getWidth(); x += 1) { for (int y = 0; y < _img.getHeight(); y += 1) { img[x][y] = _img.getRGB(x, y); @@ -56,4 +58,15 @@ (int) (Math.min(255, (g + 255*(multiplier-1)) * multiplier - 255*(multiplier-1))), (int) (Math.min(255, (b + 255*(multiplier-1)) * multiplier - 255*(multiplier-1)))); } + public Color getColor(double ang, int x, int y) { + double multiplier = 1.5 - ang/(Math.PI); + int rgb = img[x][y]; + int r = (rgb >> 16) & 0xff; + int g = (rgb >> 8) & 0xff; + int b = rgb & 0xff; + return new Color( + (int) (Math.min(255, (r + 255*(multiplier-1)) * multiplier - 255*(multiplier-1))), + (int) (Math.min(255, (g + 255*(multiplier-1)) * multiplier - 255*(multiplier-1))), + (int) (Math.min(255, (b + 255*(multiplier-1)) * multiplier - 255*(multiplier-1)))); + } } diff --git a/src/main/java/uk/org/floop/epq3d/Triangle.java b/src/main/java/uk/org/floop/epq3d/Triangle.java index 1cd3ef2..f05ae28 100644 --- a/src/main/java/uk/org/floop/epq3d/Triangle.java +++ b/src/main/java/uk/org/floop/epq3d/Triangle.java @@ -6,8 +6,14 @@ public PointComp point1; public PointComp point2; public PointComp point3; + public double[] UVPoint1; + public double[] UVPoint2; + public double[] UVPoint3; - public Matrix[] perspectiveMappingMatrix; + public Matrix textureMappingMatrix; + public Matrix uvTo00; + public Matrix uvTo00_inv; + public boolean[] edgeList; //edge 1-2 , 2-3, 3-1 @@ -16,26 +22,78 @@ private Line2d LineB; public Texture texture; + public boolean isTextured; // initialisation variables private boolean is_initialised = false; private Point2D min; private Point2D max; private Point2D startPoint; - private double xGradient; - private double yGradient; + private double xzGradient; + private double yzGradient; + private final Point2D result2 = new Point2D(0,0); public void invalidate() { is_initialised = false; } - public Triangle(PointComp _pA, PointComp _pB, PointComp _pC, boolean[] _edgeList, Texture _texture, Matrix[] mapMatrix){ + public Triangle(PointComp _pA, PointComp _pB, PointComp _pC, boolean[] _edgeList, Texture _texture){ + isTextured = false; point1 = _pA; point2 = _pB; point3 = _pC; edgeList = _edgeList; texture = _texture; - perspectiveMappingMatrix = mapMatrix; + } + public Triangle(PointComp _pA, PointComp _pB, PointComp _pC, double[] _uvA, double[] _uvB, double[] _uvC, boolean[] _edgeList, Texture _texture){ + isTextured = !_texture.isSolid(); + point1 = _pA; + point2 = _pB; + point3 = _pC; + UVPoint1 = _uvA; + UVPoint2 = _uvB; + UVPoint3 = _uvC; + edgeList = _edgeList; + texture = _texture; + // temporary object for multiplying + Matrix MultMat = new Matrix(3, 3); + // temporary unit up vector for reference + Vector2D vFin = new Vector2D(0, 1); + // temporary vector representing a vector between two points on the uv / triangle + Vector2D vOrig = new Vector2D(0, 0); + // calculate uvTo00 matrix + // uvTo00 takes the uv's point 1 to 0,0 with its point 2 at 0,1 (rotated, translated and scaled) + uvTo00 = new Matrix(3, 3); + uvTo00.setItems(new double[][]{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}); + { + vOrig.x = (UVPoint2[0] - UVPoint1[0]) ; + vOrig.y = (UVPoint2[1] - UVPoint1[1]); + double rotAng = -vOrig.angleTo(vFin); + // set to rotation + MultMat.setItems(new double[][]{ + {Math.cos(rotAng), Math.sin(rotAng), 0}, + {-Math.sin(rotAng), Math.cos(rotAng), 0}, + {0, 0, 1}, + }); + uvTo00.multiply(MultMat); + + double scaleFac = 1 / vOrig.getLength(); + // set to scaling + MultMat.setItems(new double[][]{ + {scaleFac, 0, 0}, + {0, scaleFac, 0}, + {0, 0, 1}, + }); + uvTo00.multiply(MultMat); + // set to translation + MultMat.setItems(new double[][]{ + {1, 0, -UVPoint1[0]}, + {0, 1, -UVPoint1[1]}, + {0, 0, 1}, + }); + uvTo00.multiply(MultMat); + uvTo00_inv = uvTo00.getInverse(); + } } // returns int for debug public int draw(drawData drawData, double ang){ @@ -121,7 +179,6 @@ return 0; } public boolean initialise(drawData drawData){ - if (point1 == null || point2 == null || point3 == null){ throw new NullPointerException(); } @@ -143,35 +200,35 @@ // and then assign line A and line B in order if (point1.getProjectedPoint().x == min.x) { if (point2.getProjectedPoint().x == max.x){ - LineLong = new Line2d(point1, point2, edgeList[0]); - LineA = new Line2d(point1, point3, edgeList[2]); - LineB = new Line2d(point3, point2, edgeList[1]); + LineLong = new Line2d(point1, point2, UVPoint1, UVPoint2, edgeList[0]); + LineA = new Line2d(point1, point3, UVPoint1, UVPoint3, edgeList[2]); + LineB = new Line2d(point3, point2, UVPoint3, UVPoint2, edgeList[1]); } else { - LineLong = new Line2d(point1, point3, edgeList[2]); - LineA = new Line2d(point1, point2, edgeList[0]); - LineB = new Line2d(point2, point3, edgeList[1]); + LineLong = new Line2d(point1, point3, UVPoint1, UVPoint3, edgeList[2]); + LineA = new Line2d(point1, point2, UVPoint1, UVPoint2, edgeList[0]); + LineB = new Line2d(point2, point3, UVPoint2, UVPoint3, edgeList[1]); } } else if (point2.getProjectedPoint().x == min.x) { if (point1.getProjectedPoint().x == max.x) { - LineLong = new Line2d(point2, point1, edgeList[0]); - LineA = new Line2d(point2, point3, edgeList[1]); - LineB = new Line2d(point3, point1, edgeList[2]); + LineLong = new Line2d(point2, point1, UVPoint2, UVPoint1, edgeList[0]); + LineA = new Line2d(point2, point3, UVPoint2, UVPoint3, edgeList[1]); + LineB = new Line2d(point3, point1, UVPoint3, UVPoint1, edgeList[2]); } else { - LineLong = new Line2d(point2, point3, edgeList[1]); - LineA = new Line2d(point2, point1, edgeList[0]); - LineB = new Line2d(point1, point3, edgeList[2]); + LineLong = new Line2d(point2, point3, UVPoint2, UVPoint3, edgeList[1]); + LineA = new Line2d(point2, point1, UVPoint2, UVPoint1, edgeList[0]); + LineB = new Line2d(point1, point3, UVPoint1, UVPoint3, edgeList[2]); } } else if (point3.getProjectedPoint().x == min.x){ if (point1.getProjectedPoint().x == max.x) { - LineLong = new Line2d(point3, point1, edgeList[2]); - LineA = new Line2d(point3, point2, edgeList[1]); - LineB = new Line2d(point2, point1, edgeList[0]); + LineLong = new Line2d(point3, point1, UVPoint3, UVPoint1, edgeList[2]); + LineA = new Line2d(point3, point2, UVPoint3, UVPoint2, edgeList[1]); + LineB = new Line2d(point2, point1, UVPoint2, UVPoint1, edgeList[0]); } else { - LineLong = new Line2d(point3, point2, edgeList[2]); - LineA = new Line2d(point3, point1, edgeList[1]); - LineB = new Line2d(point1, point2, edgeList[0]); + LineLong = new Line2d(point3, point2, UVPoint3, UVPoint2, edgeList[2]); + LineA = new Line2d(point3, point1, UVPoint3, UVPoint1,edgeList[1]); + LineB = new Line2d(point1, point2, UVPoint1, UVPoint2, edgeList[0]); } } // find z calculation constants @@ -192,28 +249,85 @@ ); // calculate the cross product of these two vectors in order to obtain a normal vector Vector3D cross = vec1.cross(vec2); - // find xGradient and yGradient for the triangle, in terms of z. We take the negative reciprocal of these gradients, because of the normal vector. - xGradient = -cross.x / cross.z; - yGradient = -cross.y / cross.z; - if(!Double.isFinite(xGradient)){ - xGradient = 0; + // find xzGradient and yzGradient for the triangle, in terms of z. We take the negative reciprocal of these gradients, because of the normal vector. + xzGradient = -cross.x / cross.z; + yzGradient = -cross.y / cross.z; + if(!Double.isFinite(xzGradient)){ + xzGradient = 0; } - if(!Double.isFinite(yGradient)){ - yGradient = 0; + if(!Double.isFinite(yzGradient)) { + yzGradient = 0; } + // if the triangle is textured, calculate a matrix to apply the texture + if(isTextured) { + // temporary object for multiplying + Matrix MultMat = new Matrix(3, 3); + // temporary unit up vector for reference + Vector2D vFin = new Vector2D(0, 1); + // temporary vector representing a vector between two points on the uv / triangle + Vector2D vOrig = new Vector2D(0, 0); + // calculate triTo00 matrix + // triTo00 takes the triangle's point 1 to 0,0 with its point 2 at 0,1 (rotated, translated and scaled) + Matrix faceTo00 = new Matrix(3, 3); + faceTo00.setItems(new double[][]{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}); + { + vOrig.createFrom2Points(point1.getProjectedPoint(), point2.getProjectedPoint()); + double rotAng = -vOrig.angleTo(vFin); + // set to rotation + MultMat.setItems(new double[][]{ + {Math.cos(rotAng), Math.sin(rotAng), 0}, + {-Math.sin(rotAng), Math.cos(rotAng), 0}, + {0, 0, 1}, + }); + faceTo00.multiply(MultMat); -// double testZ2 = LineLong.point2.getProjectedPoint().z; -// double testZ = refPoint.getProjectedPoint().z + -// xGradient * (LineLong.point2.getProjectedPoint().x-refPoint.getProjectedPoint().x) + -// yGradient * (LineLong.point2.getProjectedPoint().y-refPoint.getProjectedPoint().y); + double scaleFac = 1 / vOrig.getLength(); + // set to scaling + MultMat.setItems(new double[][]{ + {scaleFac, 0, 0}, + {0, scaleFac, 0}, + {0, 0, 1}, + }); + faceTo00.multiply(MultMat); + // set to translation + MultMat.setItems(new double[][]{ + {1, 0, -point1.getProjectedPoint().x}, + {0, 1, -point1.getProjectedPoint().y}, + {0, 0, 1}, + }); + faceTo00.multiply(MultMat); + // next, modify the faceTo00 matrix to scale and shear such that point 3 matches up with UV point 3. + { + // first, apply the calculated matrices to their respective point 3s + double[] pointFace = faceTo00.multiplyPoint2raw( + point3.getProjectedPoint().x, + point3.getProjectedPoint().y + ); + double[] pointUV = (uvTo00.multiplyPoint2raw(UVPoint3[0], UVPoint3[1])); - double testZ2 = LineA.point2.getProjectedPoint().z; + double xScale = pointUV[0] / pointFace[0]; + MultMat.setItems(new double[][]{ + {xScale, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }); + faceTo00 = MultMat.multiplyGetResult(faceTo00); - double testZ = 1/(1/startPoint.z + - xGradient * (LineA.point2.getProjectedPoint().x-startPoint.x) + - yGradient * (LineA.point2.getProjectedPoint().y-startPoint.y)); - //System.out.println(testZ - testZ2); - // assign points to lines + double yShearFac = (pointUV[1] - pointFace[1]) / pointUV[0]; + if (!Double.isFinite(yShearFac)) { + yShearFac = 0; + } + MultMat.setItems(new double[][]{ + {1, 0, 0}, + {yShearFac, 1, 0}, + {0, 0, 1}, + }); + faceTo00 = MultMat.multiplyGetResult(faceTo00); + // multiply final matrices and set their values in the class + textureMappingMatrix = uvTo00_inv.multiplyGetResult(faceTo00); + } + } + } is_initialised = true; return true; } @@ -221,13 +335,13 @@ // a value of 0 represents a value which is on the camera, at z=0. // not the best mapping but it's probably good enough double zVal = 1/((1/startPoint.z + - (x - startPoint.x)*xGradient + - (y - startPoint.y)*yGradient)); + (x - startPoint.x)* xzGradient + + (y - startPoint.y)* yzGradient)); int newZ = (int)(2147483647d/(zVal + 1)); // if (newZ == 2147483647){ // System.out.println((1/startPoint.z + -// (x - startPoint.x)*xGradient + -// (y - startPoint.y)*yGradient)); +// (x - startPoint.x)*xzGradient + +// (y - startPoint.y)*yzGradient)); // } // if the new Z value is greater than the existing Z value on the buffer, the new pixel is calculated and drawn if(drawData.zBuf[x][y] == 0 || @@ -235,10 +349,14 @@ drawData.zBuf[x][y] = newZ; // project result Color pixColor; - if(texture.isSolid()){ - pixColor = texture.getColor(ang); + if(isTextured){ + double[] pos = textureMappingMatrix.multiplyPoint2raw(x, y); + pixColor = texture.getColor(ang, + Math.floorMod((int)(pos[0]*texture.img.length), texture.img.length), + Math.floorMod(-1-(int)(pos[1]*texture.img[0].length), texture.img[0].length) + ); } else { - throw new RuntimeException("Textures are not supported"); + pixColor = texture.getColor(ang); } if(drawData.drawZBuffer){ drawData.drawImg[x][y] = Color.getHSBColor((float)newZ/2147483648f + 0.5f, 1, 1).getRGB(); diff --git a/src/main/java/uk/org/floop/epq3d/drawData.java b/src/main/java/uk/org/floop/epq3d/drawData.java index ceedde1..f3b618c 100644 --- a/src/main/java/uk/org/floop/epq3d/drawData.java +++ b/src/main/java/uk/org/floop/epq3d/drawData.java @@ -45,6 +45,9 @@ public Plane[] frustumPlanes = new Plane[6]; public Point2D mouseRel; + //temps + public double timeSpentChoppingFaces; + public double timeSpentDrawingNormalFaces; public drawData(String filePath){ Object obj; try { diff --git a/src/main/java/uk/org/floop/epq3d/testing.java b/src/main/java/uk/org/floop/epq3d/testing.java index a439d60..b467d1f 100644 --- a/src/main/java/uk/org/floop/epq3d/testing.java +++ b/src/main/java/uk/org/floop/epq3d/testing.java @@ -1,10 +1,18 @@ package uk.org.floop.epq3d; +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.videoio.VideoCapture; + +import javax.swing.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.WritableRaster; +import java.nio.file.Paths; class testing { public static void main(String[] args) { - JsonReader Jason = new JsonReader(); - Jason.getObjects(); - ObjectCollection main = Jason.mainCollection; - Texture[] textures = Jason.textures; + System.out.println(System.getProperty("user.dir")); + VideoCapture camera = new VideoCapture(filePath); } }