package uk.org.floop.epq3d;
import java.util.ArrayList;
public class Face {
public PointComp[] points;
public Point2D[] UVPoints;
public Vector3D normal;
public double boundingSphereR;
public Point3D boundingSphereC;
public Triangle[] tris;
public int[][] trisFaceList;
public boolean hasEdges;
public Texture texture;
public Matrix[][] perspectiveMappingMatrices;
public boolean isInitialised;
public boolean isValid;
// fixed face
public Face fixedFace;
public void initialise() {
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;
// 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.
if (valid) {
for (Triangle tri :
tris) {
tri.draw(drawData, ang);
}
} 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);
} else if (numOfInvalidPoints == 1) {// if one point is invalid, interpolate 2 new points and draw 2 new triangles:
// find which point is the invalid one TODO could optimise and find this beforehand
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 = new PointComp();
PointComp newPoint2 = new PointComp();
// 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);
if (newPoint1.getProjectedPoint().x == 0){
int p = 0;
}
// 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,
tris[tri_i].perspectiveMappingMatrix);
newTri.draw(drawData, ang);
newTri = new Triangle(oldPoint1, oldPoint2, newPoint2,
new boolean[]{false, false, false},
tris[tri_i].texture,
tris[tri_i].perspectiveMappingMatrix);
newTri.draw(drawData, ang);
} 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,
tris[tri_i].perspectiveMappingMatrix);
newTri.draw(drawData, ang);
}
} // if all points are invalid, do nothing
}
}
}
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.001;
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],
new boolean[]{hasEdges, hasEdges, hasEdges},
texture, perspectiveMappingMatrices[i]);
}
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.createFrom2Points(UVPoints[tri[0]], UVPoints[tri[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]].x},
{0, 1, 0, -UVPoints[tri[0]].y},
{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]].x, UVPoints[tri[2]].y, 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;
}
/*
System.out.println("UVPoints:###########################");
//DEBUG - printout the positions of old uv coords and new uv coords
Point3D newPoint = new Point3D();
for(int i = 0; i < 3; i+=1){
newPoint.set(uvTo00.multiplyPoint3raw(UVPoints[tri[i]].x, UVPoints[tri[i]].y, 0));
System.out.println(i + ": " + "xyzOld: " +
UVPoints[tri[i]].x + ", " + UVPoints[tri[i]].y + ", " + 0 + ", new:" +
newPoint.x + ", " + newPoint.y + ", " + newPoint.z);
}
System.out.println("FacePoints:###########################");
//DEBUG - printout the positions of old face coords and new face coords
Point3D newPoint = new Point3D();
for (int i = 0; i < 3; i += 1) {
newPoint.set(faceTo00.multiplyPoint3raw(points[tri[i]].point.x, points[tri[i]].point.y, points[tri[i]].point.z));
System.out.println(i + ": " + "xyzOld: " +
points[tri[i]].point.x + ", " + points[tri[i]].point.y + ", " + points[tri[i]].point.z + ", new:" +
newPoint.x + ", " + newPoint.y + ", " + newPoint.z);
}
*/
}
// OPTIMIZATION - remove the z row from the matrix, since z output should always be zero.
// should decrease processing time of each pixel by a lot
}
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)))));
// }
}