public class Triangle { double[][] vertex = new double[3][3]; double[][] normal = new double[3][3]; double[][] color = new double[3][3]; double[] specularColor = new double[3]; double[] ambientColor = new double[3]; double[] diffuseColor = new double[3]; double specularPower; final int X = 0; final int Y = 1; final int Z = 2; final int R = 0; final int G = 1; final int B = 2; final int BL = 0; final int BR = 1; final int TR = 2; final int TL = 3; public Triangle() { } public void print() { System.out.println("Triangle"); System.out.println("vertex0: (" + vertex[0][X] + ", " + vertex[0][Y] + ", " + vertex[0][Z] + ")"); System.out.println("vertex1: (" + vertex[1][X] + ", " + vertex[1][Y] + ", " + vertex[1][Z] + ")"); System.out.println("vertex2: (" + vertex[2][X] + ", " + vertex[2][Y] + ", " + vertex[2][Z] + ")"); } public void printColors() { System.out.println("Triangle Colors"); System.out.println("color0: (" + color[0][X] + ", " + color[0][Y] + ", " + color[0][Z] + ")"); System.out.println("color1: (" + color[1][X] + ", " + color[1][Y] + ", " + color[1][Z] + ")"); System.out.println("color2: (" + color[2][X] + ", " + color[2][Y] + ", " + color[2][Z] + ")"); } public void setPointColors (double[][] c) { for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { color[i][j] = c[i][j]; //System.out.println("color["+i+"]["+j+"] = " + color[i][j]); } } public void setVertices (double[][] v) { for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) vertex[i][j] = v[i][j]; } public void setNormals (double[][] n) { //System.out.println("Normals:"); //System.out.println("{" + n[0][0] + ", " + n[0][1] + ", " + n[0][2] + "}"); //System.out.println("{" + n[1][0] + ", " + n[1][1] + ", " + n[1][2] + "}"); //System.out.println("{" + n[2][0] + ", " + n[2][1] + ", " + n[2][2] + "}"); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { normal[i][j] = n[i][j]; } //System.out.println("Normals:"); //System.out.println("{" + normal[0][0] + ", " + normal[0][1] + ", " + normal[0][2] + "}"); //System.out.println("{" + normal[1][0] + ", " + normal[1][1] + ", " + normal[1][2] + "}"); //System.out.println("{" + normal[2][0] + ", " + normal[2][1] + ", " + normal[2][2] + "}"); } public double[][] getNormals() { double[][] n = new double[3][3]; for (int i = 0; i < normal.length; i++) for (int j = 0; j < normal[i].length; j++) n[i][j] = normal[i][j]; return n; } public void setAmbientColor (double[] ac) { for (int i = 0; i < 3; i++) ambientColor[i] = ac[i]; } public void setDiffuseColor (double[] dc) { for (int i = 0; i < 3; i++) diffuseColor[i] = dc[i]; } public void setSpecularColor (double[] sc) { for (int i = 0; i < 3; i++) specularColor[i] = sc[i]; } public void setSpecularPower( double sp) { specularPower = sp; } public void viewportTransform (int h, int w) { for (int i = 0; i < 3; i++) { vertex[i][X] = (int)(w/2 + (int)(vertex[i][X]*w/4)); vertex[i][Y] = (int)(h/2 - (int)(vertex[i][Y]*w/4)); // vertex[i][Z]: z coordinate doesn't change: it's inconsequential } } public void perspectiveTransform (double focalLength) { for (int i = 0; i < 3; i++) { vertex[i][X] = focalLength * vertex[i][X] / vertex[i][Z]; // x = f * x / z vertex[i][Y] = focalLength * vertex[i][Y] / vertex[i][Z]; // y = f * y / z vertex[i][Z] = focalLength / vertex[i][Z]; // z = f / z } } public void bufferTo(double[][] zBuffer, double[][][] frameBuffer) { //print(); // Make trapezoids double[][] trap1 = new double[4][6]; double[][] trap2 = new double[4][6]; int top, bottom, middle; int bottomY = (int)Math.max(Math.max(vertex[0][Y], vertex[1][Y]), vertex[2][Y]); if (vertex[0][Y] == bottomY) bottom = 0; else if (vertex[1][Y] == bottomY) bottom = 1; else bottom = 2; int topY = (int)Math.min(Math.min(vertex[0][Y], vertex[1][Y]), vertex[2][Y]); if (vertex[2][Y] == topY) top = 2; else if (vertex[0][Y] == topY) top = 0; else top = 1; middle = 3 - top - bottom; //System.out.println("vertex[top] (" + vertex[top][X] + ", " + vertex[top][Y] + ", " + vertex[top][Z] + ")"); //System.out.println("vertex[middle] (" + vertex[middle][X] + ", " + vertex[middle][Y] + ", " + vertex[middle][Z] + ")"); //System.out.println("vertex[bottom] (" + vertex[bottom][X] + ", " + vertex[bottom][Y] + ", " + vertex[bottom][Z] + ")"); //System.out.println("color["+top+"] (" + color[top][0] + ", " + color[top][1] + ", " + color[top][2] + ")"); //System.out.println("color["+middle+"] (" + color[middle][0] + ", " + color[middle][1] + ", " + color[middle][2] + ")"); //System.out.println("color["+bottom+"] (" + color[bottom][0] + ", " + color[bottom][1] + ", " + color[bottom][2] + ")"); double midLeft[] = new double[6], midRight[] = new double[6], newMid[] = new double[6]; double t; if (vertex[bottom][Y] != vertex[top][Y]) t = ((double)(vertex[middle][Y] - vertex[top][Y]))/ (vertex[bottom][Y] - vertex[top][Y]); else t = 1; newMid[X] = lerp(t, vertex[top][X], vertex[bottom][X]); newMid[Y] = vertex[middle][Y]; newMid[Z] = lerp(t, vertex[top][Z], vertex[bottom][Z]); newMid[3] = lerp(t, color[top][R], color[bottom][R]); newMid[4] = lerp(t, color[top][G], color[bottom][G]); newMid[5] = lerp(t, color[top][B], color[bottom][B]); if (newMid[X] < vertex[middle][X]) { midLeft = newMid; midRight[X] = vertex[middle][X]; midRight[Y] = vertex[middle][Y]; midRight[Z] = vertex[middle][Z]; midRight[3] = color[middle][R]; midRight[4] = color[middle][G]; midRight[5] = color[middle][B]; } else { midLeft[X] = vertex[middle][X]; midLeft[Y] = vertex[middle][Y]; midLeft[Z] = vertex[middle][Z]; midLeft[3] = color[middle][R]; midLeft[4] = color[middle][G]; midLeft[5] = color[middle][B]; midRight = newMid; } trap1[TL][0] = vertex[top][X]; trap1[TL][1] = vertex[top][Y]; trap1[TL][2] = vertex[top][Z]; trap1[TL][3] = color[top][R]; trap1[TL][4] = color[top][G]; trap1[TL][5] = color[top][B]; trap1[TR][0] = vertex[top][X]; trap1[TR][1] = vertex[top][Y]; trap1[TR][2] = vertex[top][Z]; trap1[TR][3] = color[top][R]; trap1[TR][4] = color[top][G]; trap1[TR][5] = color[top][B]; trap1[BL][0] = midLeft[0]; trap1[BL][1] = midLeft[1]; trap1[BL][2] = midLeft[2]; trap1[BL][3] = midLeft[3]; trap1[BL][4] = midLeft[4]; trap1[BL][5] = midLeft[5]; trap1[BR][0] = midRight[0]; trap1[BR][1] = midRight[1]; trap1[BR][2] = midRight[2]; trap1[BR][3] = midRight[3]; trap1[BR][4] = midRight[4]; trap1[BR][5] = midRight[5]; //System.out.println("Trap 1: {" + trap1[TL][0] + ", " + trap1[TL][1] + "} {" + trap1[TR][0] + ", " + trap1[TR][1] + "}"); //System.out.println(" : {" + trap1[BL][0] + ", " + trap1[BL][1] + "} {" + trap1[BR][0] + ", " + trap1[BR][1] + "}"); trap2[TL][0] = midLeft[0]; trap2[TL][1] = midLeft[1]; trap2[TL][2] = midLeft[2]; trap2[TL][3] = midLeft[3]; trap2[TL][4] = midLeft[4]; trap2[TL][5] = midLeft[5]; trap2[TR][0] = midRight[0]; trap2[TR][1] = midRight[1]; trap2[TR][2] = midRight[2]; trap2[TR][3] = midRight[3]; trap2[TR][4] = midRight[4]; trap2[TR][5] = midRight[5]; trap2[BL][0] = vertex[bottom][X]; trap2[BL][1] = vertex[bottom][Y]; trap2[BL][2] = vertex[bottom][Z]; trap2[BL][3] = color[bottom][R]; trap2[BL][4] = color[bottom][G]; trap2[BL][5] = color[bottom][B]; trap2[BR][0] = vertex[bottom][X]; trap2[BR][1] = vertex[bottom][Y]; trap2[BR][2] = vertex[bottom][Z]; trap2[BR][3] = color[bottom][R]; trap2[BR][4] = color[bottom][G]; trap2[BR][5] = color[bottom][B]; //System.out.println("Trap 2: {" + trap2[TL][0] + ", " + trap2[TL][1] + "} {" + trap2[TR][0] + ", " + trap2[TR][1] + "}"); //System.out.println(" : {" + trap2[BL][0] + ", " + trap2[BL][1] + "} {" + trap2[BR][0] + ", " + trap2[BR][1] + "}"); scanTrapezoid(trap1, zBuffer, frameBuffer); scanTrapezoid(trap2, zBuffer, frameBuffer); } private void scanTrapezoid(double[][] trap, double[][] zBuffer, double[][][] frameBuffer) { double t; int xLeft, xRight; double[] xl= new double[4]; double[] xr= new double[4]; double[] xy = new double[4];; double slopeLeft, slopeRight; slopeLeft = (trap[TL][Y] - trap[BL][Y]) / (trap[TL][X] - trap[BL][X]); slopeRight = (trap[TR][Y] - trap[BR][Y]) / (trap[TR][X] - trap[BR][X]); //System.out.println("doing a trap..."); //System.out.println("TL: {" + trap[TL][X] + ", " + trap[TL][Y] + ", " + trap[TL][Z] + ", " + trap[TL][3] + ", " + trap[TL][4] + ", " + trap[TL][5] + "}"); //System.out.println("TR: {" + trap[TR][X] + ", " + trap[TR][Y] + ", " + trap[TR][Z] + ", " + trap[TR][3] + ", " + trap[TR][4] + ", " + trap[TR][5] + "}"); //System.out.println("BL: {" + trap[BL][X] + ", " + trap[BL][Y] + ", " + trap[BL][Z] + ", " + trap[BL][3] + ", " + trap[BL][4] + ", " + trap[BL][5] + "}"); //System.out.println("BR: {" + trap[BR][X] + ", " + trap[BR][Y] + ", " + trap[BR][Z] + ", " + trap[BR][3] + ", " + trap[BR][4] + ", " + trap[BR][5] + "}"); int yBottom = (int)trap[BL][Y]; if (yBottom >= zBuffer[0].length) yBottom = zBuffer[0].length - 1; int yTop = (int)trap[TL][Y]; if (yTop < 0) yTop = 0; //System.out.println("YRange: (" + yTop+ ", " + yBottom+ ")"); for (int y = yTop; y <= yBottom; y++) { // lerp the x boundaries for the line if (trap[BL][Y] != trap[TL][Y]) t = 1 - (double)(y - trap[TL][Y]) / (trap[BL][Y] - trap[TL][Y]); else t = 0; //System.out.println("t for x is: (" + t + ")"); xLeft = (int) (trap[BL][X] + (y - trap[BL][Y]) / slopeLeft); xRight= (int) (trap[BR][X] + (y - trap[BR][Y]) / slopeRight); // lerp the colors and pz for the boundaries xl[0] = lerp(t, trap[BL][3], trap[TL][3]); xl[1] = lerp(t, trap[BL][4], trap[TL][4]); xl[2] = lerp(t, trap[BL][5], trap[TL][5]); xl[3] = lerp(t, trap[BL][2], trap[TL][2]); xr[0] = lerp(t, trap[BR][3], trap[TR][3]); xr[1] = lerp(t, trap[BR][4], trap[TR][4]); xr[2] = lerp(t, trap[BR][5], trap[TR][5]); xr[3] = lerp(t, trap[BR][2], trap[TR][2]); if (xLeft < 0) xLeft = 0; if (xRight >= zBuffer.length) xRight = zBuffer.length - 1; // do each column of said scanline //System.out.println("-- for y = " + y + ": xrange = (" + xLeft + "," + xRight + ")"); for (int x = xLeft; x <= xRight; x++) { if (xRight != xLeft) t = (double)(x - xLeft) / (xRight - xLeft); else t = 1; //System.out.println("t for pixel on x = (" + t + ")"); //System.out.println("prelerp: xl = {" + xl[0] + ", " + xl[1] + ", " + xl[2] + ", " + xl[3] + "}"); //System.out.println("prelerp: xr = {" + xr[0] + ", " + xr[1] + ", " + xr[2] + ", " + xr[3] + "}"); // lerp the color and pz values xy[0] = lerp(t, xl[0], xr[0]); xy[1] = lerp(t, xl[1], xr[1]); xy[2] = lerp(t, xl[2], xr[2]); xy[3] = lerp(t, xl[3], xr[3]); if (xy[3] > zBuffer[x][y]) { //System.out.println("insert: xy[" + x + "][" + y + "] = (" + xy[0] + ", " + xy[1] + ", " + xy[2] + ", " + xy[3] + ")"); frameBuffer[x][y][0] = xy[0]; frameBuffer[x][y][1] = xy[1]; frameBuffer[x][y][2] = xy[2]; zBuffer[x][y] = xy[3]; } } } //System.out.println("done scanning trap..."); } private double lerp(double t, double minVal, double maxVal){ return (minVal + t * (maxVal - minVal)); } // lights in form lights[which light][col] where col contians xyzrgb public void calculateColors (Light[] lights) { double reflection[] = new double[3]; double newColor[]; for (int v = 0; v < 3; v++) { newColor = new double[3]; newColor[R] = 0; newColor[G] = 0; newColor[B] = 0; newColor[R] += ambientColor[R]; newColor[G] += ambientColor[G]; newColor[B] += ambientColor[B]; for (int l = 0; l < lights.length; l++) { double[] directionL = lights[l].getDirection(); double lDOTn = directionL[X] * normal[v][X] + directionL[Y] * normal[v][Y] +directionL[Z] * normal[v][Z]; reflection[X] = 2 * lDOTn * normal[v][X] - directionL[X]; reflection[Y] = 2 * lDOTn * normal[v][Y] - directionL[Y]; reflection[Z] = 2 * lDOTn * normal[v][Z] - directionL[Z]; double reflectionMagnitude = Math.sqrt(reflection[X] * reflection[X] + reflection[Y] * reflection[Y] + reflection[Z] * reflection[Z]); reflection[X] /= reflectionMagnitude; reflection[Y] /= reflectionMagnitude; reflection[Z] /= reflectionMagnitude; double lDOTr = directionL[X] * reflection[X] + directionL[Y] * reflection[Y] +directionL[Z] * reflection[Z]; double[] lightColor = lights[l].getColor(); //System.out.println("reds: light(" + lightColor[R] + "), diffuse(" + diffuseColor[R] + "), lDOTn(" + lDOTn); newColor[R] += lightColor[R] * diffuseColor[R] * Math.max(0, lDOTn) + lightColor[R] * specularColor[R] * Math.pow(Math.max(0, lDOTr), specularPower); newColor[G] += lightColor[G] * diffuseColor[G] * Math.max(0, lDOTn) + lightColor[G] * specularColor[G] * Math.pow(Math.max(0, lDOTr), specularPower); newColor[B] += lightColor[B] * diffuseColor[B] * Math.max(0, lDOTn) + lightColor[B] * specularColor[B] * Math.pow(Math.max(0, lDOTr), specularPower); } color[v] = newColor; } } }