package cgp.render; import cgp.basics.Shape3D; import cgp.basics.Face3D; import cgp.basics.Vertex3D; import cgp.basics.LightParams; import cgp.math.Point4f; import java.util.Enumeration; /** * Ein Renderer, der * - BFC durchfuehrt, * - die uebrigen Flaechen am Frustum clippt * - mit FlatShading darstellt. * * Diese Version beruecksichtigt, dass es keinen Unterschied zwischen * Flat und CurvedFace bzw. -Vertex mehr gibt * * Diese Version benutzt einen BFCuller. * * @author Olaf Mueller * @author Axel Block * @version 1.2 22..07.2002 */ public class GreyFlatRenderer implements Renderer { public static final float EPS = -0.001f; public WCClipper clipper; public BFCuller bfculler; public View view; public Lighting lights = null; public CGCanvas cgc = null; int [] colors; public GreyFlatRenderer() { clipper = new WCClipper(); bfculler = new BFCuller(); colors = new int[256]; for (int i=0; i<256; i++) { colors[i] = 255<<24; colors[i] |= i<<16; colors[i] |= i<<8; colors[i] |= i; } } /** * Zentrale Methode; loest das Rendern der Szene aus. Die uebergebene View * liefert alle Informationen, die der Renderer braucht, um die Szene * darzustellen. * Die Uebergabe der View ermoeglicht den Einsatz derselben * Renderer-Instanz in mehreren Views. */ public void renderScene(View view) { Scene scene = view.scene; lights = scene.lights; Camera cam = view.cam; Shape3D shape; // aktueller Koerper Face3D face; // aktuelle Flaeche view.cgc.clearBuffer(); // neues Frame vorbereiten view.cgc.clearZBuffer(); // neues Frame vorbereiten Enumeration e = scene.getVisibleShapes(cam); // Liste sichtbarer Koerper while(e.hasMoreElements()) { // Liste durchlaufen shape = (Shape3D)e.nextElement(); // naechsten Koerper holen if (shape == cam) continue; for(int j=0; j<shape.count; j++) { // Alle Flaechen face = shape.faces[j]; renderFace(face, view); // Flat or Curved } // Fuer alle Flaechen } // Fuer alle Koerper view.cgc.refresh(); // Frame auf den Schirm } public void renderFace(Face3D f, View view) { Camera cam = view.cam; cgc = view.cgc; LightParams lp = new LightParams(); Vertex3D[] knoten; // sichtbare Punkte int kc=0; // Anzahl sichtb. Punkte f = bfculler.bfc(f, cam); // Flaeche holen u. bfc if(f != null) { knoten = clipper.clip(f, cam); // Flaeche clippen if((knoten != null) && (knoten.length >2)){// Flaeche z.T. sichtbar? kc = knoten.length; Point4f p0 = new Point4f(); // Dreieckspunkte Point4f p1 = new Point4f(); Point4f p2 = new Point4f(); Point4f tmp; float l0,l1,l2; // Licht-intensitaeten view.WC2DC.multiply(knoten[0].wc, p0); p0.homogenize(); // teile durch homogene Koord. l0 = lights.getLight(knoten[0].wc, knoten[0].wc_normal ,lp); view.WC2DC.multiply(knoten[1].wc, p2); p2.homogenize(); // teile durch homogene Koord. l2 = lights.getLight(knoten[1].wc, knoten[1].wc_normal ,lp); for(int k=2; k<kc; k++) { // Fuer alle Punkte //for(int k=2; k<3; k++) { // Fuer ersten Punkt tmp = p1; p1 = p2; p2 = tmp; l1 = l2; view.WC2DC.multiply(knoten[k].wc, p2); p2.homogenize(); // teile durch homogene Koord. l2 = lights.getLight(knoten[k].wc, knoten[k].wc_normal ,lp); shade(p0,p1,p2, (l0+l1+l2)/3.0f); } // fuer alle Punkte dieser Flaeche } // Flaeche nicht entartet und mind. z.T. sichtbar } // Flaeche nicht abgewandt } // Faerbt das Dreieck PA PB PC mit Intensitaet I private void shade(Point4f pa, Point4f pb, Point4f pc, float I) { Point4f pA, pB, pC; // pA.y <= pB.y <= pC.y float szAB, szAC, szBC; // Steigungen in Dimension z int errorAB=0, errorAC=0, errorBC=0; int miAB=0, miAC=0, miBC=0; int mfAB=0, mfAC=0, mfBC=0; int schrittAB=0, schrittAC=0, schrittBC=0; int pAx, pBx, pCx; // X-Werte in Ganzahlarithmetik int pAy, pBy, pCy; // Y-Werte in Ganzahlarithmetik int dxAB, dxAC, dxBC; int dyAB, dyAC, dyBC; Point4f p1, p2; // Laufvariablen if (pa.y <= pb.y) { pA = pa; pB = pb; } else { pA = pb; pB = pa; } if (pc.y >= pB.y) { pC = pc; } else { pC = pB; if (pc.y >= pA.y) { pB = pc; } else { pB = pA; pA = pc; } } pAx = (int)(pA.x+0.5f); pAy = (int)(pA.y+0.5f); pBx = (int)(pB.x+0.5f); pBy = (int)(pB.y+0.5f); pCx = (int)(pC.x+0.5f); pCy = (int)(pC.y+0.5f); dxAB = pBx - pAx; int xIncAB = dxAB<0? -1: +1; dyAB = pBy - pAy; dxAC = pCx - pAx; int xIncAC = dxAC<0? -1: +1; dyAC = pCy - pAy; dxBC = pCx - pBx; int xIncBC = dxBC<0? -1: +1; dyBC = pCy - pBy; if (pAy != pCy) { // Kante AC nicht horizontal -> Steigungen berechnen szAC = (pC.z - pA.z) / (pC.y - pA.y); //sxAC = (pC.x - pA.x) / (pC.y - pA.y); errorAC=-dyAC; miAC = dxAC/dyAC; mfAC = 2*(dxAC%dyAC); if(mfAC<0) mfAC*= -1; schrittAC = -2*dyAC; } else { // Steigungen werden nicht benoetigt - ausser fuer den Compiler ;-) szAC = 0f; } //p2 = new Point4f(pA); // p2 laeuft von A nach C int xAC = pAx; float zAC = pA.z; if (pAy == pBy) { // Kante AB horizontal } else { szAB = (pB.z - pA.z) / (pB.y - pA.y); //sxAB = (pB.x - pA.x) / (pB.y - pA.y); // Steigungen berechnen errorAB=-dyAB; miAB = dxAB/dyAB; mfAB = 2*(dxAB%dyAB); if(mfAB<0) mfAB*= -1; schrittAB = -2*dyAB; //p1 = new Point4f(pA); // p1 laeuft von A nach B int xAB = pAx; float zAB = pA.z; for (int y = pAy; y < pBy; y++) { putScanline(y, xAC, xAB, zAC, zAB, I); //p2.x += sxAC; xAC += miAC; errorAC += mfAC; if(errorAC > 0) { xAC+=xIncAC; errorAC += schrittAC; } //p2.z += szAC; zAC += szAC; //p1.x += sxAB; xAB += miAB; errorAB += mfAB; if(errorAB > 0) { xAB+=xIncAB; errorAB += schrittAB; } //p1.z += szAB; zAB += szAB; } } if (pBy == pCy) { // Kante BC horizontal } else { szBC = (pC.z - pB.z) / (pC.y - pB.y); //sxBC = (pC.x - pB.x) / (pC.y - pB.y); // Steigungen berechnen errorBC = -dyBC; miBC = dxBC/dyBC; mfBC = 2*(dxBC%dyBC); if(mfBC<0) mfBC*= -1; schrittBC = -2*dyBC; //p1 = new Point4f(pB); // p1 laeuft von B nach C (p2 laeuft weiter von A nach C) int xBC = pBx; float zBC = pB.z; for (int y = pBy; y < pCy; y++) { // Reihenfolge der X-Werte tauschen? putScanline(y, xBC, xAC, zBC, zAC, I); //p1.x += sxBC; xBC += miBC; errorBC += mfBC; if(errorBC > 0) { xBC+=xIncBC; errorBC += schrittBC; } //p1.z += szBC; zBC += szBC; //p2.x += sxAC; xAC += miAC; errorAC += mfAC; if(errorAC > 0) { xAC+=xIncAC; errorAC += schrittAC; } //p2.z += szAC; zAC += szAC; } } } private void putScanline(int y, // Berechnet waagerechte Linie in Hoehe y int x1, int x2, // von x1 nach x2 float z1, float z2, float I) { // mit Z-Komponenten z1, z2 int col = colors[(int)(I*256)]; if (x1 == x2) { // Linie ist Punkt if(z1 < 0.1f) { cgc.setPixelWithZ(x1, y, z1, colors[Math.min(255, (int)((I+1f-10f*z1)*256f))]); } else { cgc.setPixelWithZ(x1, y, z1, col); } } else { int xl, xr; float zl, zr; if (x1 < x2) { xl = x1; xr = x2; zl = z1; zr = z2; } else { xl = x2; xr = x1; zl = z2; zr = z1; } float sz = (zr - zl) / (xr - xl); // Steigung berechnen float z = zl; // x laeuft von Links nach Rechts for (int x = xl; x <= xr; x++) { //cgc.setScanlineWithP(xl, xr, y, col); if(z < 0.1f) { cgc.setPixelWithZ(x, y, z, colors[Math.min(255, (int)((I+1f-10f*z)*256f))]); } else { cgc.setPixelWithZ(x, y, z, col); } z += sz; } } } }