// POVScene.pde version 0.001 // David Bollinger, Feb 2007 // http://www.davebollinger.com // as of Processing 0123 // // this is a "middle tier" approach, it sits "between" your code and the p5 api. // this covers maybe 0.001% of POV-Ray's functionality, so if you'd like to borrow // from it, then expect that it'll need further customization for each unique use // an interface that knows how to: // 1) draw itself in processing // 2) write itself to POV-Ray's Scene Description Language // interface POVRayable { void draw(PGraphics g); void write(PrintWriter pw); } class POVCamera implements POVRayable { float eyex, eyey, eyez; float atx, aty, atz; float upx, upy, upz; POVCamera() { defaults(); } void defaults() { eyex = eyey = 0f; eyez = 100f; // note: this is an arbitrary value, not sure what the "right" default should be atx = aty = atz = 0f; upx = upz = 0f; upy = 1f; } void draw(PGraphics g) { g.camera(eyex,eyey,eyez, atx,aty,atz, upx,upy,upz); } void write(PrintWriter pw) { pw.println("// CAMERA"); pw.println("camera {"); pw.println(" location <" + -eyex + "," + -eyey + "," + -eyez + ">"); pw.println(" look_at <" + -atx + "," + -aty + "," + -atz + ">"); pw.println(" right -x"); // note: hardcoded, assumes up vector of 0,1,0 AND square output aspect pw.println(" up y"); // note: hardcoded, assumes up vector of 0,1,0 pw.println(" angle 60"); pw.println("}"); pw.println(""); } } // the rotator object exists solely to insert the rotations at the proper point // during the draw cycle, that is: after background() and camera() but before triangles class POVRotator implements POVRayable { float rotx, roty, rotz; // note: rotz not currently used POVRotator() { defaults(); } void defaults() { rotx = roty = rotz = 0f; } void draw(PGraphics g) { g.rotateX(rotx); g.rotateY(roty); } void write(PrintWriter pw) { pw.println("// GLOBAL ROTATION VALUES"); pw.println("#declare ROTX = " + (rotx*180f/PI) + ";"); pw.println("#declare ROTY = " + (roty*180f/PI) + ";"); pw.println(""); } } // the scaler object exists solely to insert the scaling at the proper point // during the draw cycle, that is: after background() and camera() but before triangles class POVScaler implements POVRayable { float scale; POVScaler() { defaults(); } void defaults() { scale = 1f; } void draw(PGraphics g) { g.scale(this.scale); } void write(PrintWriter pw) { pw.println("// GLOBAL SCALE VALUE"); pw.println("#declare SCALE = " + this.scale + ";"); pw.println(""); } } class POVLights implements POVRayable { POVLights() { // todo: right now all lighting is hardcoded, so this is a set of lights (plural) // todo: will eventually want a POVLight (singular) that better maps a p5 light to pov light } void draw(PGraphics g) { g.ambientLight(32,32,32); g.directionalLight(255, 255, 255, 0, 0, -1); g.directionalLight(255, 255, 255, 1,1,-.5); g.directionalLight(255, 255, 255, 1,1,-.5); g.directionalLight(64, 64, 64, -1,-1,-.5); } void write(PrintWriter pw) { pw.println("// LIGHTS"); pw.println("light_source { <500,500,-1000> rgb <1,1,1> } // forelight"); pw.println("light_source { <-500,-500,-1000> rgb <1,1,1> } // forelight"); pw.println("light_source { <-500,500,1000> rgb <1,1,1> shadowless } // backlight"); pw.println(""); } } class POVBackplane implements POVRayable { float offset; color c; POVBackplane() { offset = 100f; // note: hardcoded c = color(255); } POVBackplane(color c) { offset = 100f; // note: hardcoded this.c = c; } void draw(PGraphics g) { g.background(c); } void write(PrintWriter pw) { pw.println("// BACKGROUND PLANE"); pw.println("plane {"); pw.println(" z, " + offset); // note: hardcoded in z plane pw.println(" texture {"); float R = red(c)/255f; float G = green(c)/255f; float B = blue(c)/255f; pw.println(" pigment { color rgb <" + R + "," + G + "," + B + "> }"); pw.println(" finish { ambient 1 }"); pw.println(" }"); pw.println(" hollow"); pw.println("}"); pw.println(""); } } class POVTriangle implements POVRayable { float x1, y1, z1; float x2, y2, z2; float x3, y3, z3; color c; POVTriangle(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, color c) { this.x1 = x1; this.y1 = y1; this.z1 = z1; this.x2 = x2; this.y2 = y2; this.z2 = z2; this.x3 = x3; this.y3 = y3; this.z3 = z3; this.c = c; } void draw(PGraphics g) { noStroke(); // because it has no logical correlation in POV-Ray, so don't draw it in p5 either fill(c); beginShape(TRIANGLES); vertex(x1, y1, z1); vertex(x2, y2, z2); vertex(x3, y3, z3); endShape(); } void write(PrintWriter pw) { pw.println("object {"); pw.println(" triangle {"); pw.println(" <" + -x1 + ", " + -y1 + ", " + -z1 + ">"); pw.println(" <" + -x2 + ", " + -y2 + ", " + -z2 + ">"); pw.println(" <" + -x3 + ", " + -y3 + ", " + -z3 + ">"); float R = red(c)/255f; float G = green(c)/255f; float B = blue(c)/255f; pw.println(" }"); pw.println(" texture { pigment { color rgb <" + R + "," + G + "," + B + "> } finish { DEFFIN } normal { DEFNOR } }"); // *global* scale and rotation. does *not* currently support *local* scale and rotation. pw.println(" scale SCALE rotate y*ROTY rotate x*ROTX"); pw.println("}"); pw.println(""); } } // this is just a hack to write out a bunch of boilerplate header stuff // may want to eventually break this up into more discrete and configurable sub-pieces class POVHeaders implements POVRayable { POVHeaders() { // nop } void draw(PGraphics g) { // nop } void write(PrintWriter pw) { // note: write out command line opts that make it easy to duplicate current p5 width/height pw.println("// COMMAND-LINE OPTIONS"); pw.println("// right-click the following line into the command line:"); pw.println("// +w" + width + " +h" + height + " +a0.01 +am2 +r3 +sp1 +ep1"); pw.println(""); // note: this should probably be a POVStandardIncludes class or something like that, then just add to items[] pw.println("// STANDARD INCLUDES"); pw.println("#include \"colors.inc\""); pw.println("#include \"textures.inc\""); pw.println(""); // note: this should probably be a POVGlobalSettings class or something like that, then just add to items[] // (there's a ton of things you might want to add into here, like radiosity settings) pw.println("// GLOBAL SETTINGS"); pw.println("global_settings {"); pw.println(" max_trace_level 5"); pw.println("}"); pw.println(""); // note: this should probably be a POVDefaultTextures class or something like that, then just add to items[] // (these just make it easier to adjust the global triangle material) pw.println("// DEFAULT FINISH AND NORMAL"); pw.println("#declare DEFFIN = finish { ambient 0.1 diffuse 0.8 specular 0.1 };"); pw.println("#declare DEFNOR = normal { dents 0.1 scale 0.001 };"); pw.println(""); } } class POVSceneManager implements POVRayable { ArrayList items; POVSceneManager() { items = new ArrayList(); defaults(); } void defaults() { // nop } void add(POVRayable s) { items.add(s); } void clear() { items.clear(); } void draw(PGraphics g) { int n = items.size(); for (int i=0; i