Jellyfish Head Animation #2

Whole head in 3d.

To properly view this example you need WebGL capable browser. If you don't see anything please follow instructions how to get one on Khronos wiki. I checked with Firefox4b7 and WebKit nigtly build on OSX.

This example is part of blog post Cindermedusae - making generative creatures

       
// Code by Marcin Ignac  
// Made in processing.js  

float prevTime = millis();
float animTime = 0;     
float totalTime = 0;
float w = 950;
float h = 360;       

float headR = 130;
float headScaleXZ = 1;
float headScaleY = 1;    

void setup() {     
	try {
		size(w, h, P3D);	
	}
	catch(Exception e) {
	   alert(e);
	}             
}   

int nsides = 20;
int nsegments = 10;

void mousePressed() {
	if (nsides == 20) {
		nsides = 40;
		nsegments = 20;
	}                  
	else {
		nsides = 20;
		nsegments = 10;
	}
}       

PVertex evalHeadVertex(float theta, float phi) {
	PVector rvec = new PVector(headR*headScaleXZ, headR*headScaleY, headR*headScaleXZ);
	
	PVector v = new PVector();		
	float smoothAngleRange = radians(20); 
	float headClampAngle = radians(120);
	
	if (theta < headClampAngle) {
		v.x = rvec.x * sin(theta) * sin(phi);
		v.y = rvec.y * cos(theta);
		v.z = rvec.z * sin(theta) * cos(phi);
	}
	else {
		if (theta >= headClampAngle && theta <= headClampAngle + smoothAngleRange) {
			float curveAngle = map(theta, headClampAngle, headClampAngle + smoothAngleRange, 0, PI);				
			v.x = rvec.x * sin(theta) * sin(phi);
			v.y = rvec.y * cos(headClampAngle) - sin(curveAngle) * headR * 0.1;
			v.z = rvec.z * sin(theta) * cos(phi);
		}
		else {
			theta = map(theta, headClampAngle + smoothAngleRange, PI, PI/2, 0);//headClampAngle
			rvec.mult(0.75f);
			v.x = rvec.x * sin(theta) * sin(phi);
			v.y = rvec.y * cos(theta) - rvec.y * 0.5;
			v.z = rvec.z * sin(theta) * cos(phi);
		}
	}   
	                     
	int numSpikeWaves = 6;
	v.x *= 1 + 0.175 * cos(phi * numSpikeWaves) * theta/PI;
	v.z *= 1 + 0.175 * cos(phi * numSpikeWaves) * theta/PI;	
	
	return v;
}   

void drawHead() {     	
	
	float theta,phi;
	float dtheta = PI/nsegments;
	float dphi   = 2*PI/nsides;
	int segment;
	int side;     
	                       
	headScaleXZ = 1 + (mouseX-width/2)/width;
                   
	ArrayList vertices = new ArrayList();
	ArrayList triangles = new ArrayList();
	for (theta=0, segment=0; theta<=PI, segment<=nsegments; theta+=dtheta, ++segment) {
		for (phi=0, side=0; phi<=2*PI, side<=nsides; phi+=dphi, ++side) {
			PVector v1 = evalHeadVertex(theta, phi);
			PVector v2 = evalHeadVertex(theta+dtheta, phi);
			PVector v3 = evalHeadVertex(theta, phi+dphi);
			
			PVector a = PVector.sub(v2, v1);
			PVector b = PVector.sub(v3, v1);
			PVector normal = a.cross(b);
			normal.normalize();
			if (normal.mag() == 0) {
				normal = new PVector(0, 1, 0);
			}
			normal.mult(10 * sin(v1.y/headR*PI + animTime*4));  
			
			v1.add(normal);			
		    vertices.add(v1); 
		
			if (segment == nsegments) continue;
			if (side == nsides) continue;  
		    
			triangles.add((segment  )*(nsides+1) + side);
			triangles.add((segment+1)*(nsides+1) + side);
			triangles.add((segment+1)*(nsides+1) + side + 1);
			triangles.add((segment  )*(nsides+1) + side);
			triangles.add((segment+1)*(nsides+1) + side + 1);
			triangles.add((segment  )*(nsides+1) + side + 1);
		}
	}   
	   
	beginShape(TRIANGLES);         
	for(int i=0; i<triangles.size(); i++) {
		PVector v = vertices.get(triangles.get(i));
		vertex(v.x, v.y, v.z);  		
	}	   
	endShape();    
}  

void draw() {           	
	float time = millis(); 
	float delta = time - prevTime;	
	totalTime += delta/1000;
	prevTime = time;                

	animTime += delta/1000;   

	background(252, 236, 194);		

	stroke(0);
	fill(252, 246, 224);
	//noFill();
	stroke(100);
	float fov = PI/3.0;
	float cameraZ = (height/2.0) / tan(fov/2.0);
	perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*10.0);	
	translate(w/2, h/2, -100);
	float rotY = PI*0.3;
	if (mouseY) {
		rotY = mouseY/height * PI;
	}
	rotateX(PI/2 + rotY);
	rotateY(PI/3 + totalTime/5);   
	drawHead();	 	
}