public class SplinePatch { final int X = 0; final int Y = 1; final int Z = 2; final int NX = 3; final int NY = 4; final int NZ = 5; Material material; double[][][] vertices; int M, N; Cubic xSpline, ySpline, zSpline; public SplinePatch (int m, int n, double[][] gx, double[][] gy, double[][] gz) { M = m; N = n; setGX(gx); setGY(gy); setGZ(gz); reset(); } public void setGX(double[][] gx) { xSpline = new Cubic(Cubic.BEZIER, gx);; } public void setGY(double[][] gy) { ySpline = new Cubic(Cubic.BEZIER, gy);; } public void setGZ(double[][] gz) { zSpline = new Cubic(Cubic.BEZIER, gz);; } public void setVertices() { vertices = new double[M][N][6]; for (int j = 0 ; j < N; j++) for (int i = 0 ; i < M; i++) { double u = (double)i / M; double v = (double)j / N; double x = xSpline.eval(u,v); double y = ySpline.eval(u,v); double z = zSpline.eval(u,v); vertices[i][j][X] = x; vertices[i][j][Y] = y; vertices[i][j][Z] = z; } double[][][] normals = getNormals(vertices); for (int i = 0; i < M; i++) for (int j = 0; j < N; j++) { vertices[i][j][NX] = normals[i][j][X]; vertices[i][j][NY] = normals[i][j][Y]; vertices[i][j][NZ] = normals[i][j][Z]; } } public void reset() { setVertices(); } public void setMaterial(Material m) { material = m.copy(); } public void bufferTo(double[][] zBuffer, double[][][] frameBuffer, Light[] lights, double focalLength) { for (int i = 0; i < M-1; i++) { for (int j = 0; j < N-1; j++) { Triangle triangle1 = makeTriangle( vertices[i][j], vertices[i+1][j], vertices[i+1][j+1]); triangle1.perspectiveTransform(focalLength); triangle1.viewportTransform(zBuffer.length, zBuffer[0].length); triangle1.calculateColors(lights); triangle1.bufferTo(zBuffer, frameBuffer); Triangle triangle2 = makeTriangle( vertices[i][j], vertices[i][j+1], vertices[i+1][j+1]); triangle2.perspectiveTransform(focalLength); triangle2.viewportTransform(zBuffer.length, zBuffer[0].length); triangle2.calculateColors(lights); triangle2.bufferTo(zBuffer, frameBuffer); } } } private Triangle makeTriangle(double[] v0, double[] v1, double[] v2) { Triangle triangle = new Triangle(); double[][] vertices = { {v0[X], v0[Y], v0[Z]}, {v1[X], v1[Y], v1[Z]}, {v2[X], v2[Y], v2[Z]} }; double[][] normals = { {v0[NX], v0[NY], v0[NZ]}, {v1[NX], v1[NY], v1[NZ]}, {v2[NX], v2[NY], v2[NZ]} }; //if (normals[0][Z] < 0) { //for (int i = 0; i < normals.length; i++) //for (int j = 0; j < normals[i].length; j++) //normals[i][j] = -1 * normals[i][j]; //} triangle.setVertices(vertices); triangle.setNormals(normals); triangle.setAmbientColor(material.getAmbientColor()); triangle.setDiffuseColor(material.getDiffuseColor()); triangle.setSpecularColor(material.getSpecularColor()); triangle.setSpecularPower(material.specularPower); return triangle; } public void printVertices() { System.out.println("Vertices"); for (int i = 0; i < vertices.length; i++) { System.out.println(i + ": {" + vertices[i][X] + ", " + vertices[i][Y] + ", " + vertices[i][Z] + "}"); } } public double[][][] getTransformedVertices(Matrix3D t) { double[][][] newVertices = new double[M][N][3]; for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { double[] point = { vertices[i][j][X], vertices[i][j][Y], vertices[i][j][Z] }; double[] transPoint = t.transform(point); newVertices[i][j][X] = transPoint[0]; newVertices[i][j][Y] = transPoint[1]; newVertices[i][j][Z] = transPoint[2]; } } return newVertices; } public double[][][] getNormals(double[][][] v) { double[][][] gradients = new double[M][N][3]; for (int i = 0; i < M-1; i++) { for (int j = 0; j < N-1; j++) { double[] v1minusv0 = { v[i][j+1][X] - v[i][j][X], v[i][j+1][Y] - v[i][j][Y], v[i][j+1][Z] - v[i][j][Z] }; double[] v2minusv1 = { v[i+1][j+1][X] - v[i][j+1][X], v[i+1][j+1][Y] - v[i][j+1][Y], v[i+1][j+1][Z] - v[i][j+1][Z] }; // gradient for a square is defined by gradient of it's topleft corner gradients[i][j][X] = v1minusv0[Y] * v2minusv1[Z] - v1minusv0[Z] * v2minusv1[Y]; gradients[i][j][Y] = v1minusv0[Z] * v2minusv1[X] - v1minusv0[X] * v2minusv1[Z]; gradients[i][j][Z] = v1minusv0[X] * v2minusv1[Y] - v1minusv0[Y] * v2minusv1[X]; } } double[][][] normals = new double[M][N][3]; for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { normals[i][j][X] = 0; normals[i][j][Y] = 0; normals[i][j][Z] = 0; int gradientI = i; int gradientJ = j; if (gradientI == M-1) gradientI--; if (gradientJ == N-1) gradientJ--; normals[i][j][X] = gradients[gradientI][gradientJ][X]; normals[i][j][Y] = gradients[gradientI][gradientJ][Y]; normals[i][j][Z] = gradients[gradientI][gradientJ][Z]; double magnitude = Math.sqrt( normals[i][j][X] * normals[i][j][X] + normals[i][j][Y] * normals[i][j][Y] + normals[i][j][Z] * normals[i][j][Z] ); normals[i][j][X] /= magnitude; normals[i][j][Y] /= magnitude; normals[i][j][Z] /= magnitude; } } return normals; } public void transformedBy(Matrix3D t) { double[][][] transVertices = getTransformedVertices(t); double[][][] transNormals = getNormals(transVertices); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { vertices[i][j][X] = transVertices[i][j][X]; vertices[i][j][Y] = transVertices[i][j][Y]; vertices[i][j][Z] = transVertices[i][j][Z]; vertices[i][j][NX] = transNormals[i][j][X]; vertices[i][j][NY] = transNormals[i][j][Y]; vertices[i][j][NZ] = transNormals[i][j][Z]; } } } }