/* Torus.java Title: Scene3D Author: voiculescu Description: */ package Scene3D; import java.applet.*; import java.awt.*; import java.awt.event.*; import java.util.*; public class Scene3D extends Applet { //********************* // constants & variables private double theta = Math.PI / 6; // left - right view angle private double phi=Math.PI/3; // up - down view angle private float rho, d, rhoMin, rhoMax, // perspective and view transformation xMin, xMax, yMin, yMax, zMin, zMax, v11, v12, v13, v21, // parameters v22, v23, v32, v33, v43, xe, ye, ze, objSize; // private float xScrMin, xScrMax, yScrMin, yScrMax; private Point3D eyeLight; // in Eye private Point2D imgCenter; // center on screen private double sunZ = 1/2d, sunY = 0.559017d, sunX = -sunY, // light vector for ambient light inprodMin = 1e30, inprodMax = -1e30, inprodRange; // private Vector norm = new Vector(); // normals for each face (World coord) private Vector col = new Vector(); // colors (for each face) private Vector rfl = new Vector(); // reflections, specular private Vector faceList = new Vector(); // list of faces (triangles) private Vector w = new Vector(); // World coordinates (vertices) private Point3D[] e; // Eye coordinates (vertices) private Point3D[] ne; // Eye coordinates (normals) private Point2D[] vScr; // Screen coordinates (vertices) private float[][] objReflect; // Object's reflectivity and specular params. private Triangle[] objColor; // for each face private Triangle[] indexZ; // array list of faces some times sorted private double coeff[][]; // plane coefficients for all triang. private int viewType = 0; // current view private float buf[][]; // buffer array to store 1/ze coord private int maxX, maxY, centerX, centerY, maxX0 = -1, maxY0 = -1; // used in z-buffer algoritm private int depth,maxDepth=2; // recursion depth for ray trace private float maxTime; // ********************** // member declarations java.awt.Panel panel1 = new java.awt.Panel(); java.awt.Button wireBttn = new java.awt.Button(); java.awt.Button hdlineBttn = new java.awt.Button(); java.awt.Label label1 = new java.awt.Label(); java.awt.Label label2 = new java.awt.Label(); java.awt.Button upBttn = new java.awt.Button(); java.awt.Button downBttn = new java.awt.Button(); java.awt.Button lftBttn = new java.awt.Button(); java.awt.Button rightBttn = new java.awt.Button(); java.awt.Label label3 = new java.awt.Label(); java.awt.Button dftBttn = new java.awt.Button(); java.awt.Label label4 = new java.awt.Label(); java.awt.Button insTor = new java.awt.Button(); java.awt.Button paintBttn = new java.awt.Button(); java.awt.Label label5 = new java.awt.Label(); java.awt.Button zbufBttn = new java.awt.Button(); java.awt.Button insCyl = new java.awt.Button(); java.awt.Button insSph = new java.awt.Button(); java.awt.Button shadeBttn = new java.awt.Button(); java.awt.Button lightBttn = new java.awt.Button(); // ************************ boolean isStandalone = false; public Scene3D() { } // Retrieve the value of an applet parameter public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } // Get info on the applet parameters public String[][] getParameterInfo() { return null; } // Get applet information public String getAppletInfo() { return "Applet Information"; } // Initialize the applet public void init() { try { initComponents(); } catch (Exception e) { e.printStackTrace(); } insertAxes(); repaint(); }// end init() public void initComponents() throws Exception { // ************************ // the following code sets the frame's initial state panel1.setLocation(new java.awt.Point(0, 0)); panel1.setVisible(true); panel1.setBackground(java.awt.SystemColor.control); panel1.setLayout(null); panel1.setSize(new java.awt.Dimension(800, 90)); panel1.add(wireBttn); panel1.add(hdlineBttn); panel1.add(label1); panel1.add(label2); panel1.add(upBttn); panel1.add(downBttn); panel1.add(lftBttn); panel1.add(rightBttn); panel1.add(label3); panel1.add(dftBttn); panel1.add(label4); panel1.add(insTor); panel1.add(paintBttn); panel1.add(label5); panel1.add(zbufBttn); panel1.add(insCyl); panel1.add(insSph); panel1.add(shadeBttn); panel1.add(lightBttn); wireBttn.setLocation(new java.awt.Point(10, 30)); wireBttn.setLabel("Wireframe"); wireBttn.setVisible(true); wireBttn.setSize(new java.awt.Dimension(71, 20)); hdlineBttn.setLocation(new java.awt.Point(90, 30)); hdlineBttn.setLabel("Hidden Lines"); hdlineBttn.setVisible(true); hdlineBttn.setSize(new java.awt.Dimension(90, 20)); label1.setText("View Type"); label1.setLocation(new java.awt.Point(90, 10)); label1.setAlignment(Label.CENTER); label1.setVisible(true); label1.setFont(new java.awt.Font("Dialog", 1, 12)); label1.setSize(new java.awt.Dimension(90, 20)); label2.setText("_______________"); label2.setLocation(new java.awt.Point(10, 10)); label2.setVisible(true); label2.setSize(new java.awt.Dimension(90, 20)); upBttn.setLocation(new java.awt.Point(690, 10)); upBttn.setLabel("Up"); upBttn.setVisible(true); upBttn.setFont(new java.awt.Font("Dialog", 0, 12)); upBttn.setSize(new java.awt.Dimension(40, 20)); downBttn.setLocation(new java.awt.Point(690, 60)); downBttn.setLabel("Down"); downBttn.setVisible(true); downBttn.setFont(new java.awt.Font("Dialog", 0, 12)); downBttn.setSize(new java.awt.Dimension(40, 20)); lftBttn.setLocation(new java.awt.Point(640, 34)); lftBttn.setLabel("Left"); lftBttn.setVisible(true); lftBttn.setFont(new java.awt.Font("Dialog", 0, 12)); lftBttn.setSize(new java.awt.Dimension(40, 20)); rightBttn.setLocation(new java.awt.Point(740, 34)); rightBttn.setLabel("Right"); rightBttn.setVisible(true); rightBttn.setFont(new java.awt.Font("Dialog", 0, 12)); rightBttn.setSize(new java.awt.Dimension(40, 20)); label3.setText("View Point"); label3.setLocation(new java.awt.Point(620, 10)); label3.setVisible(true); label3.setFont(new java.awt.Font("Dialog", 1, 12)); label3.setSize(new java.awt.Dimension(70, 10)); dftBttn.setLocation(new java.awt.Point(685, 35)); dftBttn.setLabel("Default"); dftBttn.setVisible(true); dftBttn.setSize(new java.awt.Dimension(50, 20)); label4.setText("Insert Object ..."); label4.setLocation(new java.awt.Point(410, 30)); label4.setVisible(true); label4.setFont(new java.awt.Font("Dialog", 1, 12)); label4.setSize(new java.awt.Dimension(98, 17)); insTor.setLocation(new java.awt.Point(320, 60)); insTor.setLabel("Torus"); insTor.setVisible(true); insTor.setSize(new java.awt.Dimension(90, 20)); paintBttn.setLocation(new java.awt.Point(190, 30)); paintBttn.setLabel("Painter's"); paintBttn.setVisible(true); paintBttn.setSize(new java.awt.Dimension(90, 20)); label5.setText("_______________"); label5.setLocation(new java.awt.Point(180, 10)); label5.setVisible(true); label5.setSize(new java.awt.Dimension(90, 20)); zbufBttn.setLocation(new java.awt.Point(10, 60)); zbufBttn.setLabel("Z-buffer"); zbufBttn.setVisible(true); zbufBttn.setSize(new java.awt.Dimension(70, 20)); insCyl.setLocation(new java.awt.Point(520, 60)); insCyl.setLabel("Cylinder"); insCyl.setVisible(true); insCyl.setSize(new java.awt.Dimension(90, 20)); insSph.setLocation(new java.awt.Point(420, 60)); insSph.setLabel("Sphere"); insSph.setVisible(true); insSph.setSize(new java.awt.Dimension(90, 20)); shadeBttn.setLocation(new java.awt.Point(90, 60)); shadeBttn.setLabel("Smooth Shade"); shadeBttn.setVisible(true); shadeBttn.setSize(new java.awt.Dimension(90, 20)); lightBttn.setLocation(new java.awt.Point(190, 60)); lightBttn.setLabel("Ray Trace"); lightBttn.setVisible(true); lightBttn.setSize(new java.awt.Dimension(90, 20)); setLocation(new java.awt.Point(0, 0)); setBackground(new java.awt.Color(192, 192, 192)); setLayout(null); setSize(new java.awt.Dimension(800, 600)); add(panel1); wireBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { wireBttnActionPerformed(e); } }); hdlineBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { hdlineBttnActionPerformed(e); } }); upBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { upBttnActionPerformed(e); } }); downBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { downBttnActionPerformed(e); } }); lftBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { lftBttnActionPerformed(e); } }); rightBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { rightBttnActionPerformed(e); } }); dftBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { dftBttnActionPerformed(e); } }); insTor.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { insTorActionPerformed(e); } }); zbufBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { zbufBttnActionPerformed(e); } }); insCyl.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { insCylActionPerformed(e); } }); insSph.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { insSphActionPerformed(e); } }); shadeBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { shadeBttnActionPerformed(e); } }); lightBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { lightBttnActionPerformed(e); } }); paintBttn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { paintBttnActionPerformed(e); } }); } //--------------------------------------------- End initComponents()---------------------------- // Standard method to start the applet public void start() { } // Standard method to stop the applet public void stop() { } // Standard method to destroy the applet public void destroy() { } //************************** DRAW **************************** public void paint(Graphics g) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); spaceSize(); //shiftToOrigin(); int nrFaces=faceList.size(); switch (viewType) {case 0://------------------------------------------front faces { eyeAndScreen(); for (int i=0; i=0) { g.setColor(new Color(120*clr.a,120*clr.b,120*clr.c)); line(g, t1.a, t1.b);line(g, t1.b, t1.c);line(g, t1.c, t1.a); }// end if }//end for i break; }//end case 0 case 1://------------------------------------------hidden lines { eyeAndScreen(); sortZ(nrFaces); for (int i=0; i0) { g.setColor(new Color(191,191,191)); int[] x = {iX(p.x), iX(q.x), iX(r.x)}; int[] y = {iY(p.y), iY(q.y), iY(r.y)}; g.fillPolygon(x, y, 3); g.setColor(new Color(120*clr.a,120*clr.b,120*clr.c)); line(g, t1.a, t1.b);line(g, t1.b, t1.c);line(g, t1.c, t1.a); }// end if }//end for i break; }//end case 1 case 2://-------------------------------------------Painter's algoritm { eyeAndScreen(); sortZ(nrFaces); planeCoeff(nrFaces); for (int i=0; i255) cCode=255; Point2D p=vScr[t1.a], q=vScr[t1.b], r=vScr[t1.c]; if (area2(p,q,r)>0) { g.setColor(new Color(cCode*clr.a,cCode*clr.b,cCode*clr.c)); int[] x = {iX(p.x), iX(q.x), iX(r.x)}; int[] y = {iY(p.y), iY(q.y), iY(r.y)}; g.fillPolygon(x, y, 3); }// end if }//end for i break; }//end case 2 case 3://---------------------------------------------Z-Buffer (Ameraal's) { eyeAndScreen(); planeCoeff(nrFaces); //float xe, ye, ze; Dimension dim = getSize(); maxX = dim.width - 1; maxY = dim.height - 1; if (maxX != maxX0 || maxY != maxY0) { buf = new float[dim.width][dim.height]; maxX0 = maxX; maxY0 = maxY; }// end if for (int iy=0; iymaxY || iy<0) continue; //---- optimized for line draw boolean emptyStore = true; int xLeftmost = 0; for (int ix=iXL; ix<=iXR; ix++) { if(ix>maxX || ix<0) continue; if (zi < buf[ix][iy]) // < means nearer { if (emptyStore) { xLeftmost = ix; emptyStore = false; } buf[ix][iy] = (float)zi; } else if (!emptyStore) { g.drawLine(xLeftmost, iy, ix-1, iy); emptyStore = true; } zi += dzdx; }// end for ix if (!emptyStore) g.drawLine(xLeftmost, iy, iXR, iy); // --- }//end for y }// end for i break; }//end case 3 case 4://------------------------ Smoth Shade ----- uses Z-Buffer algoritm //--------------------- Gouraud Shading ---------------------------- { eyeAndScreen(); eyeNormals(); planeCoeff(nrFaces); smoothShades(g); break; }//end case 4 case 5://--------------------------Ray Trace ------------------------------------ { eyeAndScreen(); eyeNormals(); planeCoeff(nrFaces); rayTrace(g); break; }//end case 5 }//end switch setCursor(Cursor.getDefaultCursor()); }// ---------------------------------------------------------------end paint() //******************************************** END DRAW ******************************************* void rayTrace(Graphics g) { long elapsed; int nrFaces=faceList.size(); int xStart = Math.round(xScrMin), xEnd = Math.round(xScrMax), // x,y, Min, Max, computed in imageSize() yStart = Math.round(yScrMin), yEnd = Math.round(yScrMax); Date initTime = new Date(); long startTime = initTime.getTime(); for (int x = xStart; x maxTime){y = yEnd+2; x = xEnd + 2;} }//end for y }//end for x return; }//end rayTrace Triangle ray(Point3D P0, Point3D P1, int n, int depth, int current) { float deltaX = P1.x-P0.x, deltaY = P1.y-P0.y, deltaZ = P1.z-P0.z; Triangle color = new Triangle(255,255,255); // returned value - white is the background color Triangle clr = new Triangle(255,255,255); // for objects that are white, light gray is used if (depth >= maxDepth) return color; // double tMin=1e30; double t; int index=-1, shadow=0; Point3D hit = new Point3D(0,0,0), toLight; Point3D Light = new Point3D(100f*objSize,-100f*objSize,100*objSize);//light in world coord. Point3D origin = new Point3D(0,0,0); Point2D A,B,C,X,hit2D = new Point2D(0,0); // //--------------Phong illumination elements --------------------------------- float Ka = 0.2f, // ambient Kd = 0.75f, // difuse Ks = 0.6f, // specular Kr = 0.8f, // reflective nspec = 8; // specular n // the actual values will be taken from // objReflect array //----------------------------------------------------------- Point3D hitNormal = new Point3D(0,0,0); // normal vector at the intersection point Point3D L = new Point3D(0,0,0); // Light vector Point3D R = new Point3D(0,0,0); // Reflection vector Point3D V = new Point3D(0,0,0); // Viewing vector Point3D RVw = new Point3D(0,0,0); // Symetric to view for (int i=3; i0 && t 0f){ // if the current triangle is reflective Kr = objReflect[index][0]; float NV = inproduct(hitNormal,V); // inproduct of view and normal RVw.x = 2f*hitNormal.x*NV - V.x; // Compute the direction for the following RVw.y = 2f*hitNormal.y*NV - V.y; // ray RVw.z = 2f*hitNormal.z*NV - V.z; // mirroring view by the normal Point3D nextTarget = new Point3D((double)(hit.x+1000f*RVw.x),(double)(hit.y+1000f*RVw.y),(double)(hit.z+1000f*RVw.z)); Triangle nextRay = ray(hit,nextTarget,n,depth,index); // **** recursive call here ***** if ((nextRay.a+nextRay.b+nextRay.c)<255+255+255){ // if the next ray hitted something color.a = Math.round((1.2f-Kr)*(float)color.a + Kr*(float)nextRay.a); color.b = Math.round((1.2f-Kr)*(float)color.b + Kr*(float)nextRay.b); color.c = Math.round((1.2f-Kr)*(float)color.c + Kr*(float)nextRay.c);}} if (color.a<0) color.a=0; // Trim to min max values if (color.b<0) color.b=0; // if (color.c<0) color.c=0; // if (color.a>255) color.a=254; // if (color.b>255) color.b=254; // if (color.c>255) color.c=254; // } return color; }//end ray int shadowRay(Point3D P0, Point3D P1, int current, int nrFaces) { int shaded = -200; // int adjust = 0; // returned value float deltaX = P1.x-P0.x, deltaY = P1.y-P0.y, deltaZ = P1.z-P0.z; // double tMin=1e30; // double t; // int index=-1; // for (int i=3; i0) // if a valid intersection was found { adjust = shaded; } return adjust; }//end shadow Ray boolean pointInTriangle(Point3D P, Point2D A, Point2D B, Point2D C) { float x = -d*P.x/P.z, y = -d*P.y/P.z; // Point's projection on screen Point2D X = new Point2D (x,y); boolean pozitive = area2(A,B,X)>=0 && area2(B,C,X)>=0 && area2(C,A,X)>=0; // vizible triangle boolean negative = area2(A,B,X)<=0 && area2(B,C,X)<=0 && area2(C,A,X)<=0; // back face return pozitive || negative; } float inproduct(Point3D P1, Point3D P2) {return P1.x*P2.x+P1.y*P2.y+P1.z*P2.z;} double distance (Point3D X, Point3D Y) // used to normalize some vectors {double dx = X.x - Y.x, dy = X.y - Y.y, dz = X.z - Y.z; double dist = Math.sqrt(dx*dx+dy*dy+dz*dz); return dist; }//end distance Point3D interpNormal(int ii,float yy, float xx) { Point3D computedNormal = new Point3D(0,0,0), // value to be returned NL = new Point3D(0,0,0), // intermediate values at the ends of an NR = new Point3D(0,0,0); // horizontal segment Triangle tri = (Triangle)indexZ[ii]; // current triangle int iA = tri.a, iB = tri.b, iC = tri.c; // vertices index Point2D A = vScr[iA], B = vScr[iB], C = vScr[iC]; // tr. on screen Point3D Na = (Point3D)(ne[iA]); // normals at the three Point3D Nb = (Point3D)(ne[iB]); // vertices of the triangle Point3D Nc = (Point3D)(ne[iC]); // angles are tested here Point3D PlNorm = new Point3D((float)coeff[ii][0],(float)coeff[ii][1],(float)coeff[ii][2]); float iprodA = inproduct(PlNorm,Na); float iprodB = inproduct(PlNorm,Na); float iprodC = inproduct(PlNorm,Na); // inprod. of plane normal and the three normals at vertices // should be grater than 0.75 // hexagonal prisma (cylinder for n=6) should appear as prisma if (iprodA<=0.75F) Na = PlNorm; if (iprodB<=0.75F) Nb = PlNorm; if (iprodC<=0.75F) Nc = PlNorm; double xA = A.x, yA = A.y, xB = B.x, yB = B.y, xC = C.x, yC = C.y; // compute orizontal segment xL,xR double xI, xJ, xK, xI1, xJ1, xK1, xL, xR; xI = xJ = xK = 1e30; xI1 = xJ1 = xK1 = -1e30; if ((yy - yB) * (yy - yC) <= 0 && yB != yC) xI = xI1 = xC + (yy - yC)/(yB - yC) * (xB - xC); if ((yy - yC) * (yy - yA) <= 0 && yC != yA) xJ = xJ1 = xA + (yy - yA)/(yC - yA) * (xC - xA); if ((yy - yA) * (yy - yB) <= 0 && yA != yB) xK = xK1 = xB + (yy - yB)/(yA - yB) * (xA - xB); // xL = xR = xI; xL = Math.min(xI, Math.min(xJ, xK)); xR = Math.max(xI1, Math.max(xJ1, xK1)); Point2D L = new Point2D((float)xL,yy); Point2D R = new Point2D((float)xR,yy); if(area2(A,B,L)<0.1F && area2(A,B,L)>-0.1F) { NL.x = normalElement(A.y,B.y,L.y,Na.x,Nb.x); NL.y = normalElement(A.y,B.y,L.y,Na.y,Nb.y); NL.z = normalElement(A.y,B.y,L.y,Na.z,Nb.z);} else if(area2(B,C,L)<0.1F && area2(B,C,L)>-0.1F) { NL.x = normalElement(B.y,C.y,L.y,Nb.x,Nc.x); NL.y = normalElement(B.y,C.y,L.y,Nb.y,Nc.y); NL.z = normalElement(B.y,C.y,L.y,Nb.z,Nc.z);} else if(area2(C,A,L)<0.1F && area2(C,A,L)>-0.1F) { NL.x = normalElement(C.y,A.y,L.y,Nc.x,Na.x); NL.y = normalElement(C.y,A.y,L.y,Nc.y,Na.y); NL.z = normalElement(C.y,A.y,L.y,Nc.z,Na.z);} else NL = PlNorm; if(area2(A,B,R)<0.1F && area2(A,B,R)>-0.1F) { NR.x = normalElement(A.y,B.y,R.y,Na.x,Nb.x); NR.y = normalElement(A.y,B.y,R.y,Na.y,Nb.y); NR.z = normalElement(A.y,B.y,R.y,Na.z,Nb.z);} else if(area2(B,C,R)<0.1F && area2(B,C,R)>-0.1F) { NR.x = normalElement(B.y,C.y,R.y,Nb.x,Nc.x); NR.y = normalElement(B.y,C.y,R.y,Nb.y,Nc.y); NR.z = normalElement(B.y,C.y,R.y,Nb.z,Nc.z);} else if(area2(C,A,R)<0.1F && area2(C,A,R)>-0.1F) { NR.x = normalElement(C.y,A.y,R.y,Nc.x,Na.x); NR.y = normalElement(C.y,A.y,R.y,Nc.y,Na.y); NR.z = normalElement(C.y,A.y,R.y,Nc.z,Na.z);} else NL = PlNorm; // normalElement (xStart, xEnd, x, f(xStart), f(xEnd) -- linear interpolation to find f(x) computedNormal.x = normalElement((float)xL,(float)xR,xx,NL.x,NR.x); computedNormal.y = normalElement((float)xL,(float)xR,xx,NL.y,NR.y); computedNormal.z = normalElement((float)xL,(float)xR,xx,NL.z,NR.z); return computedNormal; } float normalElement(float x1,float x2,float x,float Nx1,float Nx2) //called from interpNormal (ray trace (viewType = 5)) // linear interpolation to find the normal elements at point x // uses the same method like in smoothShade, but with float insted of integers { float y; float NxMax = Math.max(Nx1,Nx2); float NxMin = Math.min(Nx1,Nx2); float y1 = Nx1; float y2 = Nx2; if (x2!=x1) y = y1+(x-x1)*(y2-y1)/(x2-x1); else y=Nx1; if (y>NxMax) y=NxMax; if (y255) colorA=255; if (colorB>255) colorB=255; if (colorC>255) colorC=255; if (colorA<0) colorA=0; if (colorB<0) colorB=0; if (colorC<0) colorC=0; double zAi = 1/e[tri.a].z, zBi = 1/e[tri.b].z, //continues in a z-buffer zCi = 1/e[tri.c].z; // way of things double u1 = B.x - A.x, v1 = C.x - A.x, u2 = B.y - A.y, v2 = C.y - A.y, c = u1 * v2 - u2 * v1; if (c <= 0) continue; double xA = A.x, yA = A.y, xB = B.x, yB = B.y, xC = C.x, yC = C.y, xD = (xA + xB + xC)/3, yD = (yA + yB + yC)/3, zDi = (zAi + zBi + zCi)/3, u3 = zBi - zAi, v3 = zCi - zAi, a = u2 * v3 - u3 * v2, b = u3 * v1 - u1 * v3, dzdx = -a/c, dzdy = -b/c, yBottomR = Math.min(yA, Math.min(yB, yC)), yTopR = Math.max(yA, Math.max(yB, yC)); int yBottom = (int)Math.ceil(yBottomR), yTop = (int)Math.floor(yTopR); for (int y=yBottom; y<=yTop; y++) { // Compute horizontal line segment (xL, xR) // for coordinate y: double xI, xJ, xK, xI1, xJ1, xK1, xL, xR; xI = xJ = xK = 1e30; xI1 = xJ1 = xK1 = -1e30; if ((y - yB) * (y - yC) <= 0 && yB != yC) xI = xI1 = xC + (y - yC)/(yB - yC) * (xB - xC); if ((y - yC) * (y - yA) <= 0 && yC != yA) xJ = xJ1 = xA + (y - yA)/(yC - yA) * (xC - xA); if ((y - yA) * (y - yB) <= 0 && yA != yB) xK = xK1 = xB + (y - yB)/(yA - yB) * (xA - xB); // xL = xR = xI; xL = Math.min(xI, Math.min(xJ, xK)); xR = Math.max(xI1, Math.max(xJ1, xK1)); int iy = iY((float)y), iXL = iX((float)(xL+0.5)), iXR = iX((float)(xR-0.5)); double zi = 1.01 * zDi + (y - yD) * dzdy + (xL - xD) * dzdx; if(iy>maxY || iy<0) continue; //compute colors at the ends of the line segment LR Point2D L = new Point2D((float)xL,(float)y); Point2D R = new Point2D((float)xR,(float)y); if(area2(A,B,L)<0.1F && area2(A,B,L)>-0.1F) colorStart = pointColor(A.y,B.y,L.y,colorA,colorB); else if(area2(B,C,L)<0.1F && area2(B,C,L)>-0.1F) colorStart = pointColor(B.y,C.y,L.y,colorB,colorC); else if(area2(C,A,L)<0.1F && area2(C,A,L)>-0.1F) colorStart = pointColor(C.y,A.y,L.y,colorC,colorA); else colorStart = cCode; if(area2(A,B,R)<0.1F && area2(A,B,R)>-0.1F) colorEnd = pointColor(A.y,B.y,R.y,colorA,colorB); else if(area2(B,C,R)<0.1F && area2(B,C,R)>-0.1F) colorEnd = pointColor(B.y,C.y,R.y,colorB,colorC); else if(area2(C,A,R)<0.1F && area2(C,A,R)>-0.1F) colorEnd = pointColor(C.y,A.y,R.y,colorC,colorA); else colorEnd = cCode; // pointColor (xStart, xEnd, x, f(xStart), f(xEnd) -- linear interpolation to find f(x) for (int x=iXL; x<=iXR; x++) { if (zi < buf[x][iy]) // < is nearer {color = pointColor((float)iXL,(float)iXR,(float)x,colorStart,colorEnd); g.setColor(new Color(color*clr.a,color*clr.b,color*clr.c)); g.drawLine(x, iy, x, iy); buf[x][iy] = (float)zi; }//endif zi += dzdx; }//end for x }//end for y }// end for i }//--------------------------------------------------end shades --------------------------------- int pointColor(float x1,float x2,float x,int colA,int colB) //called from smooth shade (viewType = 4) // linear interpolation to find the color at point x { int y; int colMax = Math.max(colA,colB); int colMin = Math.min(colA,colB); float y1 = (float)colA; float y2 = (float)colB; if (x2!=x1) y = Math.round(y1+(x-x1)*(y2-y1)/(x2-x1)); else y=colA; if (y>colMax) y=colMax; if (y inprodMax) inprodMax = inprod; } inprodRange = inprodMax - inprodMin; }// end plane coef int colorCode(double a, double b, double c) // Copied from Appendix C (discussed in Section 6.3) of // Ammeraal, L. (1998) Computer Graphics for Java Programmers, // Modified by Jon Voiculescu (increase of contrast) { double inprod = a * sunX + b * sunY + c * sunZ; // return (int)Math.round(((inprod - inprodMin)/inprodRange) * 255); int code = (int)Math.round(((inprod - inprodMin)/inprodRange) * 295 - 20); if (code<0) code = 0; if (code>255) code = 255; return code; }// end colorCode //********************************* ADD AN OBJECT TO THE WORKING SPACE ********************* void addObj(int obD,int obFaces, float[][] pnts, float[][] nrmls, int [][] fcs, int color, float reflection, float specular, int specN) //----------------------------------------------------------------------------------------------------------------------------------------- // adds an object to the current space. // obD - object dimension (nr. of vertices) // obFaces - nr of faces // pnts - matrix with all the coordinates of the points // first index = point's number // second index = point's coordinates [0]-x, [1]-y, [2]-z // nrmls - matrix with the normals for each point // first index = point's number // second index = normal's coordinates [0]-x, [1]-y, [2]-z // fcs - matrix with all faces(triangles) // first index = triangle's number // second index = point's numbers for the three vertices of triangle // clr - object's color (used Triangle class to store three integers) // reflection - more or less reflective (0-0.8) // specular - specular coefficient // specN - specular exponent //------------------------------------------------------------------------------------------------------------------------------------------ { Triangle clr; if (color == 0) {clr = new Triangle(0, 0, 1);} // the Triangle class was used else if (color == 1) {clr = new Triangle(0, 1, 0);} // to store a set of three integers else if (color == 2) {clr = new Triangle(0, 1, 1);} // else if (color == 3) {clr = new Triangle(1, 0, 0);} //clr = new Triangle(Red, Green, Blue) else if (color == 4) {clr = new Triangle(1, 0, 1);} // these integers will be multiplied else if (color == 5) {clr = new Triangle(1, 1, 0);} // with the ColorCode to get the else {clr = new Triangle(1, 1, 1);} // final color in a given point. RflSpec reflect = new RflSpec(reflection, specular, specN); int ipStart = w.size(); int ipStop = ipStart + obD; for (int ip=ipStart; ip xMax) xMax = p.x; if (p.y < yMin) yMin = p.y; if (p.y > yMax) yMax = p.y; if (p.z < zMin) zMin = p.z; if (p.z > zMax) zMax = p.z; }// end for i float dx = xMax - xMin, dy = yMax - yMin, dz = zMax - zMin; objSize = (float) Math.sqrt(dx * dx + dy * dy + dz * dz); rhoMin = 0.6F * objSize; rhoMax = 1000 * rhoMin; rho = 5 * rhoMin; Dimension dim = getSize(); int maxX = dim.width - 1, maxY = dim.height - 1, minMaxXY = Math.min(maxX, maxY); int centerX = maxX/2, centerY = 40+maxY/2; d = 1.2f*rho * minMaxXY / objSize; imgCenter = new Point2D(centerX,centerY); return; }// end of spaceSize() void imageSize() { int n = w.size(); xScrMin=1e30F; xScrMax=-1e30F; yScrMin=1e30F; yScrMax=-1e30F; for (int i=4; i xScrMax) xScrMax = p.x; if (p.y < yScrMin) yScrMin = p.y; if (p.y > yScrMax) yScrMax = p.y; }//end for i } void initPersp() // Copied from Ammeraal, L. (1998) Computer Graphics for Java Programmers, // { float costh = (float)Math.cos(theta), sinth = (float)Math.sin(theta), cosph = (float)Math.cos(phi), sinph = (float)Math.sin(phi); v11 = -sinth; v12 = -cosph * costh; v13 = sinph * costh; v21 = costh; v22 = -cosph * sinth; v23 = sinph * sinth; v32 = sinph; v33 = cosph; v43 = -rho; return; } //end initPersp void eyeNormals() //--------------------------------------------------------------------------- // called only if the view type is smooth shaded or ray traced // the view transformation is aplied to the normals vector "norm" // the result is stored in ne[] //--------------------------------------------------------------------------- {// initPersp(); int n = norm.size(); ne = new Point3D[n]; for (int i=0; ip1.z+q1.z+r1.z) {swap = indexZ[i]; indexZ[i] = indexZ[i+1]; indexZ[i+1] = swap; swapz=0F; swc = objColor[i]; objColor[i] = objColor[i+1]; objColor[i+1] = swc; swapr = objReflect[i][0]; objReflect[i][0] = objReflect[i+1][0]; objReflect[i+1][0] = swapr; swapr = objReflect[i][1]; objReflect[i][1] = objReflect[i+1][1]; objReflect[i+1][1] = swapr; swapr = objReflect[i][2]; objReflect[i][2] = objReflect[i+1][2]; objReflect[i+1][2] = swapr; }// end if }//end for i if (swapz == 1000F) sorted = true; }//end while not sorted return; }// end of sortZ void shiftToOrigin() // Copied from Ammeraal, L. (1998) Computer Graphics for Java Programmers, // modified by Jon Voiculescu // not used in the current version { int n = w.size(); float xwC = 0.5F * (xMin + xMax), // pozition of the logical ywC = 0.5F * (yMin + yMax), // coordinates origin zwC = 0.5F * (zMin + zMax); // Min - Max calculated for (int i=1; i0) reflectives = reflectives + 1; } InfoRay rayDepthTime = new InfoRay(maxDepth,10,rayCancel); try { RayDia frame = new RayDia(); RayDialog d = new RayDialog(frame); rayCancel = d.showDialog(rayDepthTime,width,height,nrFaces,reflectives); if (rayCancel) {viewType = 0; repaint(); return;} maxDepth = rayDepthTime.nRay; maxTime = rayDepthTime.timeRay; maxTime = maxTime*60000f; d.setVisible(false); d.dispose(); viewType = 5; repaint(); } catch (Exception e1) { e1.printStackTrace(); } return; } // ------------------------------------------------ Group 2 - View Point public void upBttnActionPerformed(java.awt.event.ActionEvent e) { double dPhi=Math.PI/20; phi -=dPhi; if (phi <= 0) phi = 0; if (phi >= Math.PI) phi = Math.PI; repaint(); return; } public void downBttnActionPerformed(java.awt.event.ActionEvent e) {double dPhi=Math.PI/20; phi +=dPhi; if (phi <= 0) phi = 0; if (phi >= Math.PI) phi = Math.PI; repaint(); return; } public void dftBttnActionPerformed(java.awt.event.ActionEvent e) { phi = Math.PI/3; theta = Math.PI/6; repaint(); return; } public void lftBttnActionPerformed(java.awt.event.ActionEvent e) {double dTheta=Math.PI/20; theta -=dTheta; if (theta <= 0) theta = 0; if (theta >= Math.PI) theta = Math.PI; repaint(); return; } public void rightBttnActionPerformed(java.awt.event.ActionEvent e) {double dTheta=Math.PI/20; theta +=dTheta; if (theta <= 0) theta = 0; if (theta >= Math.PI) theta = Math.PI; repaint(); return; } // ---------------------------------------------------- Group 3 - Insert Object // ------------------------------------Torus ----------------------------------------- public void insTorActionPerformed(java.awt.event.ActionEvent e) { //insertTorus(int sqr(vertices), double Radius ... and more); int torPoints=32; double torRadius=2.5; float torx = 0, tory = 0, torz = 0; boolean torCancel = true; boolean vTor = false; int torc=7; float torRfl = 0; float torSpec = 0; int torSpN = 0; InfoTor tData = new InfoTor(torPoints,torRadius,torx,tory,torz,torCancel,vTor,torc,torRfl,torSpec,torSpN); try { torData frame = new torData(); torDia d = new torDia(frame); torCancel = d.showDia(tData); d.dispose(); } catch (Exception e1) { e1.printStackTrace(); } if (torCancel) return; else { torPoints = tData.nTor; torRadius = tData.RTor; torx=tData.xTor; tory=tData.yTor; torz=tData.zTor; vTor=tData.vertTor; torc=tData.colorTor; torRfl = tData.reflectTor; torSpec = tData.specularTor; torSpN = tData.specularNTor; }//end else torusObj tor = new torusObj(torPoints, torRadius, torx, tory, torz, vTor, torc); int obDim = torPoints*torPoints; float[][] points = new float[obDim][3]; points = tor.getVertex(obDim); float[][] normals = new float[obDim][3]; normals = tor.getNormal(obDim); int[][] faces = new int[2*obDim][3]; faces = tor.getSides(obDim); int faceCount = 2*obDim; addObj(obDim,faceCount,points,normals,faces,torc,torRfl,torSpec,torSpN); repaint(); return; }// end insert Torus (trigered by button) // ------------------------------------Cylinder ----------------------------------------- public void insCylActionPerformed(java.awt.event.ActionEvent e) { int cylPoints=32; double cylRadius=2.5; float cylh = 0, cylx = 0, cyly = 0, cylz = 0; boolean cylCancel = true; boolean vcyl = false; int cylc=1; float cylRfl = 0; float cylSpec = 0; int cylSpN = 0; InfoCyl cData = new InfoCyl(cylPoints,cylRadius,cylh,cylx,cyly,cylz,cylCancel,vcyl,cylc,cylRfl,cylSpec,cylSpN); try { cylDta frame = new cylDta(); cylDia d = new cylDia(frame); cylCancel = d.showDia(cData); d.dispose(); } catch (Exception e1) { e1.printStackTrace(); } if (cylCancel) return; else { cylPoints = cData.nCyl; cylRadius = cData.RCyl; cylh=cData.hCyl; cylx=cData.xCyl; cyly=cData.yCyl; cylz=cData.zCyl; vcyl=cData.vertCyl; cylc=cData.colorCyl; cylRfl = cData.reflectCyl; cylSpec=cData.specularCyl; cylSpN = cData.specularNCyl; }//end else int obDim = cylPoints; cylObj cyl = new cylObj(obDim,cylRadius,cylh,cylx,cyly,cylz,vcyl,cylc,cylRfl); float[][] points = new float[2+obDim*2][3]; points = cyl.getVertex(obDim); float[][] normals = new float[2+obDim*2][3]; normals = cyl.getNormal(obDim); int[][] faces = new int[4*obDim][3]; faces = cyl.getSides(obDim); int faceCount = 4*obDim; int vertCount = 2+obDim*2; addObj(vertCount,faceCount,points,normals,faces,cylc,cylRfl,cylSpec,cylSpN); repaint(); return; }// end insert Cylinder // ------------------------------------Sphere ----------------------------------------- public void insSphActionPerformed(java.awt.event.ActionEvent e) { int sphPoints=32; double sphRadius=2.5; float sphx = 0, sphy = 0, sphz = 0; boolean sphCancel = true; int sphc=1;float sphRfl = 0; float sphSpec = 0; int sphSpN = 0; InfoSph sData = new InfoSph(sphPoints,sphRadius,sphx,sphy,sphz,sphCancel,sphc,sphRfl,sphSpec,sphSpN); try { sphData frame = new sphData(); sphDia d = new sphDia(frame); sphCancel = d.showDia(sData); d.dispose(); } catch (Exception e1) { e1.printStackTrace(); } if (sphCancel) return; else { sphPoints = sData.nSph; sphRadius = sData.RSph; sphx=sData.xSph; sphy=sData.ySph; sphz=sData.zSph; sphc=sData.colorSph;sphRfl = sData.reflectSph; sphSpec = sData.specularSph; sphSpN = sData.specularNSph; }//end else int n = sphPoints; sphObj sph = new sphObj(sphPoints,sphRadius,sphx,sphy,sphz,sphc); int vertCount = n*n/2-2*n+2; int faceCount = n*n-4*n; float[][] points = new float[vertCount][3]; points = sph.getVertex(n); float[][] normals = new float[vertCount][3]; normals = sph.getNormal(n); int[][] faces = new int[faceCount][3]; faces = sph.getSides(n); addObj(vertCount,faceCount,points,normals,faces,sphc,sphRfl,sphSpec,sphSpN); repaint(); return; }// end insert Sphere }//end of Scene3D Applet (main) //******************************* class RflSpec {float r; float s; int N; RflSpec(float r, float s, int N){this.r = r; this.s=s; this.N=N;} }