// realtime mesh deforms with glow and dynamic texturing // demonstrates a way to efficiently clear z-buffer only (without touching pixel buffer) // makes use of (new since rev67) imaging/blit routines and blend modes // author: info@toxi.co.uk (06/02/2004) // // source code released under creative commons license Sphere main; BImage overlay; float[] clearZ; void setup() { hint(NEW_GRAPHICS); size(400,400); background(255); noStroke(); lights(); textureMode(NORMAL_SPACE); // set light source g.lightKind[2] = DIFFUSE; g.lightX[2] = 300.0; g.lightY[2] = 2000.0; g.lightZ[2] = -500.0; g.lightR[2] = 0.6; g.lightG[2] = 0.3; g.lightB[2] = 0.5; // create a new sphere mesh main=new Sphere(32,150); // create image object used as scene overlay, see below overlay=new BImage(80,50); // make a copy of the virgin z-buffer state clearZ=new float[width*height]; System.arraycopy(g.zbuffer,0,clearZ,0,clearZ.length); // nasty: this really is a cheap hack for now, to testdrive sami's new renderer // please don't ask! ;) g.z_order=false; } void loop() { // turn off antialiasing noSmooth(); // clear the z-buffer System.arraycopy(clearZ,0,g.zbuffer,0,clearZ.length); // draw semi-transparent background fill(255,100); rect(0,0,width,height); //lights(); // setup 3d perspective translate(200,200,-100); rotateX(-PI/3.5-mouseY*0.01); rotateY(1+mouseX*0.01); // update animation & draw mesh main.update(); // show glow overlay if mouse is pressed // the overlay consists of a extremely scaled down version of the current pixelbuffer // which is then scaled and copied back up again in the main pixelbuffer using additive blending // to emphasize darker areas/shadows, we apply the scaled down image as alpha channel for itself // darker pixels in the alpha channel mean less intensity (like in photoshop) // brighter pixels will be stronger in the blending process and eventually become 100% white // UPDATE: this image object is now also used as animated texture for the mesh // also note, that i'm only using a small area of the actual image for the overlay, // however the entire image is used as texture. the remaining pixels remain simply transparent // and create the "holes" in the texture overlay.replicate(g,0,0,width,height,0,0,10,10); overlay.alpha(overlay); // temporarily enable smoothing/bi-linear filtering // also compare the result with the line commented out! smooth(); // blend pixels from overlay image with main pixel buffer // additive blending will clip at white blend(overlay,0,0,9,9,0,0,width,height,ADD); } // this class constructs a spherical mesh of independently animating vertices // the vertice animation is based on simple, slightly randomized sine wave // noise level increases over time class Sphere { float baseRadius; Vertice[] vertices; int vertCount; int sphere_detail; Sphere(int res,float radius) { baseRadius=radius; float delta = TWO_PI/res; float[] cx = new float[res]; float[] cz = new float[res]; // pre-calc unit circle in XZ plane for (int i = 0; i < res; i++) { cx[i] = cos(i*delta); cz[i] = sin(i*delta); } // computing vertexlist // vertexlist starts at north pole vertCount = res * (res-1); vertices = new Vertice[vertCount]; int currVert = 0; float angle_step = PI/res; float angle = angle_step; // step along Y axis for (int i = 1; i < res; i++) { float curradius = sin(angle)*baseRadius; float currY = -cos(angle)*baseRadius; for (int j = 0; j < res; j++) { // create and store new vertices vertices[currVert++]=new Vertice(cx[j]*curradius, currY, cz[j]*curradius,currVert); } angle += angle_step; } sphere_detail=res; } // main mesh animation loop void update() { int v1,v2; // update all vertice positions for(int i=0; i0.0) { x/=mag; y/=mag; z/=mag; } } float magnitude() { return sqrt(x*x+y*y+z*z); } } // actual vertice definition based on Vec3d // class Vertice extends Vec3d { Vec3d dir; float angle,speed,scale,factor; Vertice(float x, float y, float z, int index) { // 1st call the constructor in parent class (Vec3d) super(x,y,z); // the vertice's position also represents // its direction from the sphere's center dir=new Vec3d(x,y,z); // we need to normalize it so the vector's length = 1 dir.normalize(); // setup sinewave animation params // to start out smoothly, the sine wave's start angle // is based on the vertices position in space // this is to ensure that neighbouring vertices move // on similar waveforms/phases angle=y*0.01+x*0.02-z*0.015; // alternatively use index in vertex list as basis // for start angle (creates a rose look) //angle=index*index*0.001; speed=random(0.05,0.0503)*3; scale=this.magnitude()/4; } // compute the current displacement factor by // progressing through the sine wave void update() { factor=scale*sin(angle); angle+=speed; } // called from Sphere's update function // add vertex to the sphere mesh // vertex colour and texture coordinates are based on position (yet again ;) void getCurrent() { fill(50-dir.x*factor,150-dir.y*factor,196-dir.z*factor); vertex(x+dir.x*factor,y+dir.y*factor,z+dir.z*factor,abs(dir.x*factor)*0.005+abs(dir.z*factor*dir.y)*0.005,abs(dir.y*factor)*0.01); } } // the end