package uk.org.floop.epq3d; import java.util.ArrayList; import java.util.Random; public class Face { public PointComp[] points; public double[][] UVPoints; public Vector3D normal; public double boundingSphereR; public Point3D boundingSphereC; public Triangle[] tris; public int[][] trisFaceList; public boolean hasEdges; public Texture texture; public double randomValue; public Matrix[][] perspectiveMappingMatrices; public boolean isInitialised; public boolean isValid; // fixed face public Face fixedFace; public void initialise(Random random) { double distance = 0; double newDis; Point3D pointA = points[0].point; Point3D pointB = points[0].point; Vector3D distanceVec = new Vector3D(); for (int i = 1; i < points.length; i += 1) { distanceVec.createFrom2Points(points[0].point, points[i].point); newDis = distanceVec.getLength(); if (newDis >= distance) { pointA = points[i].point; distance = newDis; } } for (PointComp point : points) { distanceVec.createFrom2Points(points[0].point, points[0].point); newDis = distanceVec.getLength(); if (newDis >= distance) { pointB = point.point; distance = newDis; } } boundingSphereC = new Point3D( (pointA.x + pointB.x) / 2, (pointA.y + pointB.y) / 2, (pointA.z + pointB.z) / 2); boundingSphereR = Math.sqrt(distance) / 2; for (PointComp point : points) { distanceVec.createFrom2Points(boundingSphereC, point.point); distance = distanceVec.getLength(); boundingSphereR = Math.max(boundingSphereR, distance); } calculateNormal(); perspectiveMappingMatrices = new Matrix[points.length - 2][2]; separateTris(); //generateUVMatrices(); // fixedFace is a constant object which is used temporarily when the face intersects with the camera, // and thus needs to be sliced. fixedFace = new Face(); fixedFace.hasEdges = hasEdges; fixedFace.texture = texture; fixedFace.normal = normal; fixedFace.isInitialised = true; // initialises a random value for the face. Used for random colour selection. randomValue = random.nextDouble()*2 - 1; // the fixed face inherits the perspective mapping matrices from the true face. This is because the transforms // stay the same, just the edge bounds of the face have changed. fixedFace.perspectiveMappingMatrices = perspectiveMappingMatrices; isInitialised = true; } public void invalidate() { for (Triangle tri : tris) { tri.invalidate(); } } public void draw(drawData drawData, ArrayList<Integer> frustumInfo) { double ang = normal.angleTo(new Vector3D(0.2, 0.5, 1)); if (!isInitialised) { throw new RuntimeException("Face not initialised"); } // the check for backface culling has been done previously. // initialise points // apply point transforms for all points within the face boolean valid = applyPointTransforms(drawData); // this function is completed every frame, without checking whether pixels will be drawn first 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, randomValue); } 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) int numOfInvalidPoints = 0; for (int i = 0; i < 3; i += 1) { if (points[trisFaceList[tri_i][i]].getRotatedPoint().z < 0.001) { numOfInvalidPoints += 1; } } if (numOfInvalidPoints == 0) { // if there are no invalid points, treat the triangle normally // project all points in triangle tris[tri_i].draw(drawData, ang, randomValue); } else if (numOfInvalidPoints == 1) {// if one point is invalid, interpolate 2 new points and draw 2 new triangles: int invalidIndex = -1; for (int i = 0; i < 3; i += 1) { if (points[trisFaceList[tri_i][i]].getRotatedPoint().z < 0.001) { invalidIndex = i; break; } } if (invalidIndex == -1) { throw new RuntimeException("How did this happen?!"); } 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; 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); newPoint1.setProjectedPoint(drawData); // interpolate between oldPoint2 and invalid point newPoint2 = interpolate(drawData, frustumInfo, oldPoint2, invalidPoint); newPoint2.setProjectedPoint(drawData); Triangle newTri; newTri = new Triangle(oldPoint1, newPoint2, newPoint1, new boolean[]{false, false, false}, tris[tri_i].texture); newTri.draw(drawData, ang, randomValue); newTri = new Triangle(oldPoint1, oldPoint2, newPoint2, new boolean[]{false, false, false}, tris[tri_i].texture); newTri.draw(drawData, ang, randomValue); } else if (numOfInvalidPoints == 2) { // if two points are invalid, interpolate and draw triangle w/ new points: int validIndex = -1; for (int i = 0; i < 3; i += 1) { if (points[trisFaceList[tri_i][i]].getRotatedPoint().z > 0.001) { validIndex = i; break; } } if (validIndex == -1) { throw new RuntimeException("How did this happen?!"); } PointComp invalidPoint1 = points[trisFaceList[tri_i][Math.floorMod(validIndex + 1, 3)]]; PointComp invalidPoint2 = points[trisFaceList[tri_i][Math.floorMod(validIndex + 2, 3)]]; PointComp oldPoint = points[trisFaceList[tri_i][validIndex]]; PointComp newPoint1; PointComp newPoint2; // interpolate for z = 0.001 between invalid1 and oldPoint newPoint1 = interpolate(drawData, frustumInfo, oldPoint, invalidPoint1); newPoint1.setProjectedPoint(drawData); // interpolate for z = 0.001 between invalid2 and oldPoint newPoint2 = interpolate(drawData, frustumInfo, oldPoint, invalidPoint2); newPoint2.setProjectedPoint(drawData); // project points, set their z values, and then draw triangles { // create and draw new triangle Triangle newTri; newTri = new Triangle(newPoint1, newPoint2, oldPoint, new boolean[]{false, false, false}, tris[tri_i].texture); newTri.draw(drawData, ang, randomValue); } } // if all points are invalid, do nothing } drawData.timeSpentChoppingFaces += System.currentTimeMillis() - lastTime; } } private PointComp interpolate(drawData drawData, ArrayList<Integer> 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; } } } double interpolateZVal = 0.1; if(minDis < -1){ interpolateZVal = 0.1; // Vector3D oldNew = new Vector3D(oldPoint.getRotatedPoint(), invalidPoint.getRotatedPoint()); // double pointDis = oldNew.getLength(); // x 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); if (!Double.isFinite(gradX)) { newPointRotated.x = oldPoint.getRotatedPoint().x; } if (!Double.isFinite(gradY)) { newPointRotated.y = oldPoint.getRotatedPoint().y; } PointComp newPoint = new PointComp(); newPoint.invalidate(); newPoint.setRotatedPoint(newPointRotated); return newPoint; } /* if (valid) { //drawTris(img, zBuf, FPDis, scrX, scrY);} else { ArrayList<PointComp> newPoints = new ArrayList<>(); // if there are points behind the camera, loop through all the points and interpolate a point that is. // The perspective mapping matrix is calculated beforehand, so we don't need to move UVS PointComp lastPoint = points[points.length - 1]; boolean lastValid = lastPoint.getRotatedPoint().z > 0.1; boolean thisValid; for (PointComp point: points) { thisValid = point.getRotatedPoint().z > 0.1; // We need to do different things depending on whether the previous point was also a valid point, or not. // first - if only 1 of the last point or this point were valid, // interpolate between them to get the point at the screen. (XOR) if(lastValid ^ thisValid){ // solving for z = 0.1 for the line between thisPoint and lastPoint, // separately in the xz and yz planes. double gradX = (point.getRotatedPoint().z - lastPoint.getRotatedPoint().z) / (point.getRotatedPoint().x - lastPoint.getRotatedPoint().x); double gradY = (point.getRotatedPoint().z - lastPoint.getRotatedPoint().z) / (point.getRotatedPoint().y - lastPoint.getRotatedPoint().y); newPoints.add(new PointComp( (0.1+gradX*point.getRotatedPoint().x-point.getRotatedPoint().z)/gradX, (0.1+gradY*point.getRotatedPoint().y-point.getRotatedPoint().z)/gradY, 0.1)); if(!Double.isFinite(gradX)){ newPoints.get(newPoints.size() - 1).point.x = point.getRotatedPoint().x;} if(!Double.isFinite(gradY)){ newPoints.get(newPoints.size() - 1).point.y = point.getRotatedPoint().y;} } // finally - if the current point is valid, then add it to the list if(thisValid){ newPoints.add(new PointComp( point.getRotatedPoint().x, point.getRotatedPoint().y, point.getRotatedPoint().z)); } lastPoint = point; lastValid = thisValid; } // there must be at least 3 points in the face for it to be drawn successfully if(newPoints.size() >= 3) { // finished fixing points, now we need to create a new face consisting of those points. fixedFace.points = newPoints.toArray(new PointComp[0]); fixedFace.separateTris(); // invalidate all the points so they are actually calculated for (PointComp point : newPoints) { point.invalidate(); } Matrix identMat = new Matrix(3,3); // we use an identity matrix because the points of the fixed face are in camera coordinates already. // we just need the projected 2d point. identMat.setItems(new double[][]{ {1,0,0}, {0,1,0}, {0,0,1} }); fixedFace.applyPointTransforms(identMat, FPDis, scrX, scrY); fixedFace.drawTris(img, zBuf, FPDis, scrX, scrY); } } return numberOfPixels; } */ public boolean applyPointTransforms(drawData drawData) { boolean valid = true; for (PointComp point : points) { point.setRotatedPoint(drawData.camMatrix); // if any points are behind the camera, we will need to handle it differently. if (point.getRotatedPoint().z < 0.001) { valid = false; } else { // only worth calculating the projected point if that point is valid point.setProjectedPoint(drawData); } } return valid; } public void separateTris() { Triangle[] newTris = new Triangle[points.length - 2]; int[][] newTrisFaceList = new int[points.length - 2][3]; for (int i = 0; i < newTris.length; i += 1) { newTrisFaceList[i][0] = 0; newTrisFaceList[i][1] = i + 1; newTrisFaceList[i][2] = i + 2; newTris[i] = new Triangle( points[0], points[i + 1], points[i + 2], UVPoints[0], UVPoints[i+1], UVPoints[i+2], new boolean[]{hasEdges, hasEdges, hasEdges}, texture); } tris = newTris; trisFaceList = newTrisFaceList; } public void calculateNormal() { // too many new variables Point3D point0 = points[0].point; Point3D point1 = points[1].point; Vector3D vec1 = new Vector3D(point1.x - point0.x, point1.y - point0.y, point1.z - point0.z); Vector3D vec2 = new Vector3D(); // initialisation otherwise intellij gets mad // find a vector which is not inline with other vectors boolean valid = false; int i = 2; while (!valid && i <= points.length) { point0 = point1; point1 = points[Math.floorMod(i, points.length)].point; vec2.x = point1.x - point0.x; vec2.y = point1.y - point0.y; vec2.z = point1.z - point0.z; double angle = Math.abs(vec1.angleTo(vec2)); if (angle > 0.1 && angle < 2 * Math.PI - 0.1) { // if the angle between the vectors is between a threshold, the two vectors are valid. // else, calculate the second vector using a different set of points. valid = true; } i += 1; } isValid = valid; normal = vec1.cross(vec2); } private void generateUVMatrices() { // temporary object for multiplying Matrix MultMat = new Matrix(4, 4); // 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); // repeat for every triangle (this method must be called BEFORE separateTris is called) int i = 0; for (int[] tri : trisFaceList) { // generate two matrices - // uvTo00 takes the uv's point 1 to 0,0 with its point 2 at 0,1 (rotated, translated and scaled) 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.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[][]{ {Math.cos(rotAng), Math.sin(rotAng), 0, 0}, {-Math.sin(rotAng), Math.cos(rotAng), 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); uvTo00.multiply(MultMat); double scaleFac = 1 / vOrig.getLength(); // set to scaling MultMat.setItems(new double[][]{ {scaleFac, 0, 0, 0}, {0, scaleFac, 0, 0}, {0, 0, scaleFac, 0}, {0, 0, 0, 1}, }); uvTo00.multiply(MultMat); // set to translation MultMat.setItems(new double[][]{ {1, 0, 0, -UVPoints[tri[0]][0]}, {0, 1, 0, -UVPoints[tri[0]][1]}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); uvTo00.multiply(MultMat); } // faceTo00 takes the face's point 1 to 0,0 with its point 2 at 1,0 (rotated, translated and scale Matrix faceTo00 = new Matrix(4, 4); faceTo00.setItems(new double[][]{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}); { Vector3D rotVector301 = new Vector3D(); Vector3D rotVector302 = new Vector3D(); // rotation (pain) { double rotAng; rotVector301.createFrom2Points(points[tri[0]].point, points[tri[1]].point); rotVector302.createFrom2Points(points[tri[0]].point, points[tri[2]].point); vOrig.x = rotVector301.x; vOrig.y = rotVector301.y; rotAng = vFin.angleTo(vOrig); MultMat.setItems(new double[][]{ {Math.cos(rotAng), Math.sin(rotAng), 0, 0}, {-Math.sin(rotAng), Math.cos(rotAng), 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); faceTo00 = MultMat.multiplyGetResult(faceTo00); faceTo00.multiplyVec3to(rotVector301, rotVector301); vOrig.x = rotVector301.z; vOrig.y = rotVector301.y; rotAng = -vFin.angleTo(vOrig); MultMat.setItems(new double[][]{ {1, 0, 0, 0}, {0, Math.cos(rotAng), Math.sin(rotAng), 0}, {0, -Math.sin(rotAng), Math.cos(rotAng), 0}, {0, 0, 0, 1}, }); faceTo00 = MultMat.multiplyGetResult(faceTo00); faceTo00.multiplyVec3to(rotVector302, rotVector302); Vector2D vFin2 = new Vector2D(1, 0); vOrig.x = rotVector302.x; vOrig.y = rotVector302.z; rotAng = -vFin2.angleTo(vOrig); MultMat.setItems(new double[][]{ {Math.cos(rotAng), 0, -Math.sin(rotAng), 0}, {0, 1, 0, 0}, {Math.sin(rotAng), 0, Math.cos(rotAng), 0}, {0, 0, 0, 1}, }); faceTo00 = MultMat.multiplyGetResult(faceTo00); } // scale and translation (less pain) rotVector301.createFrom2Points(points[tri[0]].point, points[tri[1]].point); double scaleFac = 1 / rotVector301.getLength(); MultMat.setItems(new double[][]{ {scaleFac, 0, 0, 0}, {0, scaleFac, 0, 0}, {0, 0, scaleFac, 0}, {0, 0, 0, 1}, }); faceTo00.multiply(MultMat); MultMat.setItems(new double[][]{ {1, 0, 0, -points[tri[0]].point.x}, {0, 1, 0, -points[tri[0]].point.y}, {0, 0, 1, -points[tri[0]].point.z}, {0, 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 Point3D pointFace = new Point3D(); 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]][0], UVPoints[tri[2]][1], 0)); double xScale = pointUV.x / pointFace.x; //System.out.println("Scale: " + xScale); MultMat.setItems(new double[][]{ {xScale, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); faceTo00 = MultMat.multiplyGetResult(faceTo00); double yShearFac = (pointUV.y - pointFace.y) / pointUV.x; if (!Double.isFinite(yShearFac)) { yShearFac = 0; } MultMat.setItems(new double[][]{ {1, 0, 0, 0}, {yShearFac, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }); faceTo00 = MultMat.multiplyGetResult(faceTo00); // multiply final matrices and set their values in the class perspectiveMappingMatrices[i][0] = uvTo00.getInverse().multiplyGetResult(faceTo00); i += 1; } } // OPTIMIZATION - remove the z row from the matrix, since z output should always be zero. // should decrease processing time of each pixel } private void bakePerspectiveMatrices(drawData drawData) { // calculate matrix which converts 2d points into 3d points { // first, we get the rotated plane points and normal points Point3D planePoint = points[0].getRotatedPoint(); Vector3D rotatedNormalVector = new Vector3D(0, 0, 0); drawData.camMatrix.multiplyVec3to(normal, rotatedNormalVector); /* next we define matrices according to the simultaneous equations: 1, derived from projection: point.x = scrX - (scrX*0.5*((fpdis*y)/(z) + 1)); becomes: 0 = 0x + y(fpdis)+z(2*point.x/scrX - 1); where point.x is the 2d x position of the point on the screen. 2, derived from projection point.y = (scrX*0.5*((fpdis*x)/(z) + (scrY/scrX))); becomes: 0 = x(scrX*fpDis) + 0y + z(scrY-2*point.y) where point.y is the 2d y position of the point on the screen. 3, derived from the distance to a plane. a plane's normal vector dotted with a vector that goes from a point that lies on a plane to the point to be tested, equals the distance the tested point is from the plane. This becomes: x(normal.x)+y(normal.y)+z(normal.z) = normal.x*planePoint.x + normal.y*planePoint.y + normal.z*planePoint.z */ int x = 0; int y = 0; Matrix simulMat = new Matrix(3, 3); simulMat.setItems(new double[][]{ {0, drawData.FPDis, (2 * x / (double) drawData.scrX) - 1}, {drawData.scrX * drawData.FPDis, 0, drawData.scrY - 2 * y}, {normal.x, normal.y, normal.z}, }); Matrix simulMat2 = new Matrix(1, 3); simulMat2.setItems(new double[][]{ {0}, {0}, {normal.x * planePoint.x + normal.y * planePoint.y + normal.z * planePoint.z} }); } } // private void bakePerspectiveMatrices() { // // one mapping matrix for each triangle // // to achieve perspective mapping, we need to convert from the 2d screen position, to the 3d world position by // // reverse projecting and interpolating in the triangle - this gives camera coordinates. // // next, we need to use the inverse camera matrix to convert from camera coordinates to world coordinates. // // then, we can use the perspective mapping matrix unique and baked to each triangle on each face to convert from those world coordinates, into uv coordinates. // // // // real01Vec.createFrom2Points(points[0].getRotatedPoint(), points[1].getRotatedPoint()); // real02Vec.createFrom2Points(points[0].getRotatedPoint(), points[2].getRotatedPoint()); // // scaVec.createFrom2Points(points[0].getProjectedPoint(), points[1].getProjectedPoint()); // UV01Vec.createFrom2Points(UVPoints[0], UVPoints[1]); // UV02Vec.createFrom2Points(UVPoints[0], UVPoints[2]); // // it must remain as the same object so pointers elsewhere still work. // // invert x and y coordinates because in rotated coordinates, they are the wrong way round. // perspectiveMappingMatrix.setItems(new double[][]{ // {0,1,0,0}, // {1,0,0,0}, // {0,0,1,0}, // {0,0,0,1}, // }); // // traVec.createFrom2Points(new Point3D(UVPoints[0].y, UVPoints[0].x, 0), points[0].getRotatedPoint()); // Matrix tMat = new Matrix(4, 4); //// tMat.setItems(new double[][]{ //// {1, 0, 0, traVec.x}, //// {0, 1, 0, traVec.y}, //// {0, 0, 1, traVec.z}, //// {0, 0, 0, 1}, //// }); // tMat.setItems(new double[][]{ // {1, 0, 0, 0}, // {0, 1, 0, 0}, // {0, 0, 1, points[0].getRotatedPoint().z}, // {0, 0, 0, 1}, // }); // double scale = 0.1;//(real01Vec.getLength() / UV01Vec.getLength()); // Matrix scaMat = new Matrix(4, 4); // scaMat.setItems(new double[][]{ // {scale, 0, 0, 0}, // {0, scale, 0, 0}, // {0, 0, scale, 0}, // {0, 0, 0, 1} // }); // // find z rotation and define matrix // double zAng = new Vector2D(real01Vec.x, real01Vec.y).angleTo(UV01Vec); // Matrix zMat = new Matrix(4, 4); // zMat.setItems(new double[][]{ // {Math.cos(zAng), Math.sin(zAng), 0, 0}, // {-Math.sin(zAng), Math.cos(zAng), 0, 0}, // {0, 0, 1, 0}, // {0, 0, 0, 1}} // ); // // rotate "real" vectors using the Z matrix // result = zMat.multiplyPoint3raw(real01Vec.x, real01Vec.y, real01Vec.z); // real01Vec.x = result[0];real01Vec.y = result[1];real01Vec.z = result[2]; // result = zMat.multiplyPoint3raw(real02Vec.x, real02Vec.y, real02Vec.z); // real02Vec.x = result[0];real02Vec.y = result[1];real02Vec.z = result[2]; // zMat.setItems(new double[][]{ // {Math.cos(-zAng), Math.sin(-zAng), 0, 0}, // {-Math.sin(-zAng), Math.cos(-zAng), 0, 0}, // {0, 0, 1, 0}, // {0, 0, 0, 1}} // ); // // find Y rotation and define matrix // double yAng = new Vector2D(real01Vec.x, real01Vec.z).angleTo(new Vector2D(UV01Vec.x, 0)); // Matrix yMat = new Matrix(4, 4); // yMat.setItems(new double[][]{ // {Math.cos(yAng), 0, -Math.sin(yAng), 0}, // {0, 1, 0, 0}, // {Math.sin(yAng), 0, Math.cos(yAng), 0}, // {0, 0, 0, 1}} // ); // result = yMat.multiplyPoint3raw(real02Vec.x, real02Vec.y, real02Vec.z); // real02Vec.x = result[0];real02Vec.y = result[1];real02Vec.z = result[2]; // yMat.setItems(new double[][]{ // {Math.cos(-yAng), 0, -Math.sin(-yAng), 0}, // {0, 1, 0, 0}, // {Math.sin(-yAng), 0, Math.cos(-yAng), 0}, // {0, 0, 0, 1}} // ); // double xAng = new Vector2D(real02Vec.y, real02Vec.z).angleTo(new Vector2D(UV01Vec.x, 0)); // this is fine // Matrix xMat = new Matrix(4, 4); // xMat.setItems(new double[][]{ // {1, 0, 0, 0}, // {0, Math.cos(-xAng), Math.sin(-xAng), 0}, // {0, -Math.sin(-xAng), Math.cos(-xAng), 0}, // {0, 0, 0, 1}} // ); // // Matrix that returns the position on a texture from 3d camera space on the face of an object // // we already know the Z depth because of calculations for Z buffers. // //perspectiveMappingMatrix.multiply(scaMat); // perspectiveMappingMatrix.multiply(scaMat.multiplyGetResult(tMat)); // //perspectiveMappingMatrix.multiply((scaMat.multiplyGetResult(xMat.multiplyGetResult(yMat.multiplyGetResult(zMat.multiplyGetResult(tMat)))))); // // perspectiveMappingMatrix.multiply(scaMat.multiplyGetResult(zMat.multiplyGetResult(yMat.multiplyGetResult(xMat.multiplyGetResult(tMat))))); // } }